/* Finish a context. If the context has no parent, its state will be set * to 'x86_ctx_finished'. If it has, its state is set to 'x86_ctx_zombie', waiting for * a call to 'waitpid'. * The children of the finished context will set their 'parent' attribute to NULL. * The zombie children will be finished. */ void X86ContextFinish(X86Context *self, int state) { X86Emu *emu = self->emu; X86Context *aux; /* Context already finished */ if (X86ContextGetState(self, X86ContextFinished | X86ContextZombie)) return; /* If context is waiting for host events, cancel spawned host threads. */ X86ContextHostThreadSuspendCancel(self); X86ContextHostThreadTimerCancel(self); /* From now on, all children have lost their parent. If a child is * already zombie, finish it, since its parent won't be able to waitpid it * anymore. */ DOUBLE_LINKED_LIST_FOR_EACH(emu, context, aux) { if (aux->parent == self) { aux->parent = NULL; if (X86ContextGetState(aux, X86ContextZombie)) X86ContextSetState(aux, X86ContextFinished); } } /* Send finish signal to parent */ if (self->exit_signal && self->parent) { x86_sys_debug(" sending signal %d to pid %d\n", self->exit_signal, self->parent->pid); x86_sigset_add(&self->parent->signal_mask_table->pending, self->exit_signal); X86EmuProcessEventsSchedule(emu); } /* If clear_child_tid was set, a futex() call must be performed on * that pointer. Also wake up futexes in the robust list. */ if (self->clear_child_tid) { unsigned int zero = 0; mem_write(self->mem, self->clear_child_tid, 4, &zero); X86ContextFutexWake(self, self->clear_child_tid, 1, -1); } X86ContextExitRobustList(self); /* If we are in a signal handler, stop it. */ if (X86ContextGetState(self, X86ContextHandler)) X86ContextReturnFromSignalHandler(self); /* Finish context */ X86ContextSetState(self, self->parent ? X86ContextZombie : X86ContextFinished); self->exit_code = state; X86EmuProcessEventsSchedule(emu); }
void opencl_si_request_work() { if (driver_state.wait_for_ndrange_completion && !list_count(si_emu->running_work_groups) && !list_count(si_emu->waiting_work_groups)) { opencl_debug("ND-Range is complete\n"); driver_state.ndrange_complete = 1; } else { opencl_debug("SI is ready for more work\n"); driver_state.ready_for_work = 1; } X86EmuProcessEventsSchedule(x86_emu); }
/* Suspend a context, using the specified callback function and data to decide * whether the process can wake up every time the x86 emulation events are * processed. */ void X86ContextSuspend(X86Context *self, X86ContextCanWakeupFunc can_wakeup_callback_func, void *can_wakeup_callback_data, X86ContextWakeupFunc wakeup_callback_func, void *wakeup_callback_data) { X86Emu *emu = self->emu; /* Checks */ assert(!X86ContextGetState(self, X86ContextSuspended)); assert(!self->can_wakeup_callback_func); assert(!self->can_wakeup_callback_data); /* Suspend context */ self->can_wakeup_callback_func = can_wakeup_callback_func; self->can_wakeup_callback_data = can_wakeup_callback_data; self->wakeup_callback_func = wakeup_callback_func; self->wakeup_callback_data = wakeup_callback_data; X86ContextSetState(self, X86ContextSuspended | X86ContextCallback); X86EmuProcessEventsSchedule(emu); }
void evg_opencl_command_queue_complete(struct evg_opencl_command_queue_t *command_queue, struct evg_opencl_command_t *command) { X86Context *context = command->context; struct linked_list_t *command_list; /* Check that command is in command queue */ command_list = command_queue->command_list; linked_list_find(command_list, command); if (command_list->error_code) fatal("%s: command is not in command queue", __FUNCTION__); /* Remove command */ linked_list_remove(command_list); /* x86 contexts might be waiting for the command queue to get empty * (e.g., suspended in a 'clFinish' call. Check events. */ assert(context); X86EmuProcessEventsSchedule(context->emu); }
/* Finish a context group. This call does a subset of action of the 'x86_ctx_finish' * call, but for all parent and child contexts sharing a memory map. */ void X86ContextFinishGroup(X86Context *self, int state) { X86Emu *emu = self->emu; X86Context *aux; /* Get group parent */ if (self->group_parent) self = self->group_parent; assert(!self->group_parent); /* Only one level */ /* Context already finished */ if (X86ContextGetState(self, X86ContextFinished | X86ContextZombie)) return; /* Finish all contexts in the group */ DOUBLE_LINKED_LIST_FOR_EACH(emu, context, aux) { if (aux->group_parent != self && aux != self) continue; if (X86ContextGetState(aux, X86ContextZombie)) X86ContextSetState(aux, X86ContextFinished); if (X86ContextGetState(aux, X86ContextHandler)) X86ContextReturnFromSignalHandler(aux); X86ContextHostThreadSuspendCancel(aux); X86ContextHostThreadTimerCancel(aux); /* Child context of 'ctx' goes to state 'finished'. * Context 'ctx' goes to state 'zombie' or 'finished' if it has a parent */ if (aux == self) X86ContextSetState(aux, aux->parent ? X86ContextZombie : X86ContextFinished); else X86ContextSetState(aux, X86ContextFinished); aux->exit_code = state; } /* Process events */ X86EmuProcessEventsSchedule(emu); }