close_ioengine(td);
cleanup_io_u(td);
td_set_runstate(td, TD_EXITED);
- return NULL;
+ return (void *) td->error;
}
/*
* We cannot pass the td data into a forked process, so attach the td and
* pass it to the thread worker.
*/
-static void *fork_main(int shmid, int offset)
+static int fork_main(int shmid, int offset)
{
struct thread_data *td;
- void *data;
+ void *data, *ret;
data = shmat(shmid, NULL, 0);
if (data == (void *) -1) {
+ int __err = errno;
+
perror("shmat");
- return NULL;
+ return __err;
}
td = data + offset * sizeof(struct thread_data);
- thread_main(td);
+ ret = thread_main(td);
shmdt(data);
- return NULL;
+ return (int) ret;
}
/*
static void reap_threads(int *nr_running, int *t_rate, int *m_rate)
{
struct thread_data *td;
- int i, cputhreads, pending;
+ int i, cputhreads, pending, status, ret;
/*
* reap exited threads (TD_EXITED -> TD_REAPED)
if (td->io_ops && td->io_ops->flags & FIO_CPUIO)
cputhreads++;
+ if (td->runstate < TD_EXITED) {
+ /*
+ * check if someone quit or got killed in an unusual way
+ */
+ ret = waitpid(td->pid, &status, WNOHANG);
+ if (ret < 0)
+ perror("waitpid");
+ else if ((ret == td->pid) && WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+
+ log_err("fio: pid=%d, got signal=%d\n", td->pid, sig);
+ td_set_runstate(td, TD_REAPED);
+ goto reaped;
+ }
+ }
+
if (td->runstate != TD_EXITED) {
if (td->runstate < TD_RUNNING)
pending++;
if (pthread_join(td->thread, (void *) &ret))
perror("thread_join");
- } else
- waitpid(td->pid, NULL, 0);
+ } else {
+ int status;
+ ret = waitpid(td->pid, &status, 0);
+ if (ret < 0)
+ perror("waitpid");
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ if (!exit_value)
+ exit_value++;
+ }
+ }
+
+reaped:
(*nr_running)--;
(*m_rate) -= td->ratemin;
(*t_rate) -= td->rate;
if (fork())
fio_sem_down(&startup_sem);
else {
- fork_main(shm_id, i);
- exit(0);
+ int ret = fork_main(shm_id, i);
+
+ exit(ret);
}
}
}