void syscall_futex_wait(cpu_int_state_t *state) { // Extract arguments uintptr_t futex_vaddr = state->state.rsi; uint32_t value_cmp = (uint32_t) state->state.rbx; // Check if (!memory_user_accessible(futex_vaddr & ~0xFFF)) { state->state.rax = 0; return; } // Compare values uint32_t *futex = (uint32_t *) futex_vaddr; if (value_cmp != *futex) { state->state.rax = 0; return; } // Enter sleep thread_current->sleep_mode = THREAD_SLEEP_FUTEX; thread_current->sleep_ctx = (void *) futex_vaddr; thread_freeze(thread_current); // Ensure that 1 is returned on wakeup state->state.rax = 1; // Switch threads SYSCALL_SWITCH_THREAD; }
/* * thread_stop_freeze * Block the thread in the kernel and freeze the processor set. * return value: * TRUE - the thread has blocked interruptibly, is stopped, and * the processor set assignment is frozen * FALSE - the thread is no longer in the processor set, so it * isn't stopped, and the processor set assignment * is released. */ int thread_stop_freeze( thread_t thread, processor_set_t pset ) { thread_act_t thr_act; spl_t s; /* * hold it, and wait for it to stop. */ thr_act = thread_lock_act(thread); thread_hold(thr_act); act_unlock_thread(thr_act); thread_stop(thread); s = splsched(); wake_lock(thread); while( thread->state & (TH_RUN|TH_UNINT) ) { thread->wake_active = TRUE; assert_wait((event_t)&thread->wake_active, FALSE); wake_unlock(thread); splx(s); thread_block( (void (*)(void)) 0 ); (void) splsched(); wake_lock(thread); } /* * Now, the thread has blocked uninterruptibly; freeze the * assignment and make sure it's still part of the processor set. */ wake_unlock(thread); thread_freeze(thread); thread_lock(thread); /* * if the processor set has changed, release the freeze and * then unstop it. */ if( thread->processor_set != pset ) { thread_unlock(thread); splx(s); thread_unfreeze(thread); thread_unstop(thread); return FALSE; } thread_unlock(thread); splx(s); return TRUE; }
void syscall_ipc_send(cpu_int_state_t *state) { // Extract arguments uint32_t pid = (uint32_t) state->state.rdi; uint16_t flags = (uint32_t) state->state.rbx; uint32_t length = (uint32_t) state->state.rcx; // Check if process exists process_t *process_target = (pid == process_current->pid) ? process_current : process_get(pid); if (0 == process_target) SYSCALL_RETURN_ERROR(1); // Check handler if (0 == process_target->message_handler) SYSCALL_RETURN_ERROR(2); // Check buffer size if (length > thread_current->ipc_buffer_sz[IPC_BUFFER_SEND]) SYSCALL_RETURN_ERROR(3); // Spawn handler thread thread_t *handler = thread_spawn( process_target, process_target->message_handler); // Set thread role ipc_role_ctx_t *role_ctx = (ipc_role_ctx_t *) heap_alloc(sizeof(ipc_role_ctx_t)); role_ctx->flags = flags; role_ctx->sender_process = process_current->pid; role_ctx->sender_thread = thread_current->tid; handler->role = THREAD_ROLE_IPC_RECEIVER; handler->role_ctx = role_ctx; // Move buffer to handler thread if (length > 0) ipc_buffer_move( thread_current, IPC_BUFFER_SEND, handler, IPC_BUFFER_RECV, process_target); // Write header to registers ipc_message_header( IPC_BUFFER_RECV, length, flags, process_current->pid, handler->tid, &handler->state); // Freeze the invoking thread, if a response is expected if (0 == (flags & IPC_FLAG_IGNORE_RESPONSE)) thread_freeze(thread_current); // Switch to handler thread thread_switch(handler, state); }