blob: 9b210d9f0a636001c09b736036ef45653c1696aa [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fdio/spawn.h>
#include <pthread.h>
#include <stdlib.h>
#include <zircon/syscalls.h>
#include <fbl/algorithm.h>
#include <zxtest/zxtest.h>
// This file is for regression tests for race conditions where the test was
// only observed to reproduce the race condition when some scheduling
// tweaks were applied to the software under test -- e.g. adding sleeps or
// sched_yield()/thread_yield() calls, or changing the scheduler to
// randomize its scheduling decisions.
static const char* g_executable_filename;
static void* ThreadFunc(void* thread_arg) { zx_process_exit(200); }
static void Subprocess() {
pthread_t thread;
pthread_create(&thread, NULL, ThreadFunc, NULL);
zx_process_exit(100);
}
// This is a regression test for an issue where the exit status for a
// process -- as reported by zx_object_get_info()'s return_code field --
// could change. That could happen if multiple threads called
// zx_process_exit() concurrently.
TEST(RaceTests, TestProcessExitStatusRace) {
// Launch a subprocess.
const char* argv[] = {g_executable_filename, "--subprocess", nullptr};
zx_handle_t proc;
ASSERT_EQ(fdio_spawn(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, g_executable_filename, argv, &proc),
ZX_OK);
for (;;) {
// Query the process state.
zx_info_process_t info1;
size_t records_read;
ASSERT_EQ(zx_object_get_info(proc, ZX_INFO_PROCESS, &info1, sizeof(info1), &records_read, NULL),
ZX_OK);
ASSERT_EQ(records_read, 1u);
// If the process was reported as exited, query its state again.
if (info1.flags & ZX_INFO_PROCESS_FLAG_EXITED) {
EXPECT_TRUE(info1.return_code == 100 || info1.return_code == 200);
zx_info_process_t info2;
ASSERT_EQ(
zx_object_get_info(proc, ZX_INFO_PROCESS, &info2, sizeof(info2), &records_read, NULL),
ZX_OK);
ASSERT_EQ(records_read, 1u);
// Do the results match what we got before?
EXPECT_TRUE(info1.flags & ZX_INFO_PROCESS_FLAG_EXITED);
EXPECT_EQ(info1.return_code, info2.return_code);
break;
}
sched_yield();
}
// Clean up.
ASSERT_EQ(zx_handle_close(proc), ZX_OK);
}
int main(int argc, char** argv) {
g_executable_filename = argv[0];
if (argc == 2 && !strcmp(argv[1], "--subprocess")) {
Subprocess();
return 0;
}
return zxtest::RunAllTests(argc, argv);
}