void slave_consistency_process (struct slave_database *sdb) { int i; time_t now; while (1) { for (i=0; i<MAXTASKS; i++) { if ((sdb->comp->status.task[i].used) //&& (sdb->comp->status.task[i].status != TASKSTATUS_LOADING) && (kill(sdb->comp->status.task[i].pid,0) == -1)) { now = time(NULL); if ((sdb->comp->status.task[i].status != TASKSTATUS_LOADING) && now != -1 && ((now - sdb->comp->status.task[i].start_loading_time) < MAXTASKLOADINGTIME)) { // Still loading... no timeout continue; } // There is process registered as running, but not running. Or it could be loading but without the real process running after the timeout. semaphore_lock(sdb->semid); sdb->comp->status.task[i].used = 0; semaphore_release(sdb->semid); log_auto(L_WARNING,"Process registered as running was not running. Removed."); } else if ((sdb->comp->status.task[i].used) && (sdb->comp->status.task[i].status == TASKSTATUS_LOADING)) { // The process is already running but marked as loading. We have to update. semaphore_lock(sdb->semid); sdb->comp->status.task[i].status = TASKSTATUS_RUNNING; semaphore_release(sdb->semid); log_auto(L_DEBUG2,"Process previously loading is now running."); } } sleep (SLAVEDELAY); } }
/* * Routine: semaphore_dereference * * Release a reference on a semaphore. If this is the last reference, * the semaphore data structure is deallocated. */ void semaphore_dereference( semaphore_t semaphore) { uint32_t collisions; spl_t spl_level; if (semaphore == NULL) return; if (hw_atomic_sub(&semaphore->ref_count, 1) != 0) return; /* * Last ref, clean up the port [if any] * associated with the semaphore, destroy * it (if still active) and then free * the semaphore. */ ipc_port_t port = semaphore->port; if (IP_VALID(port)) { assert(!port->ip_srights); ipc_port_dealloc_kernel(port); } /* * Lock the semaphore to lock in the owner task reference. * Then continue to try to lock the task (inverse order). */ spl_level = splsched(); semaphore_lock(semaphore); for (collisions = 0; semaphore->active; collisions++) { task_t task = semaphore->owner; assert(task != TASK_NULL); if (task_lock_try(task)) { semaphore_destroy_internal(task, semaphore); /* semaphore unlocked */ splx(spl_level); task_unlock(task); goto out; } /* failed to get out-of-order locks */ semaphore_unlock(semaphore); splx(spl_level); mutex_pause(collisions); spl_level = splsched(); semaphore_lock(semaphore); } semaphore_unlock(semaphore); splx(spl_level); out: zfree(semaphore_zone, semaphore); }
void netcmd_semaphore_lock (void) { const int timeout_seconds = 600; if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000)) msg (M_FATAL, "Cannot lock net command semaphore"); }
/* * Routine: semaphore_destroy * * Destroys a semaphore. This call will only succeed if the * specified task is the SAME task name specified at the semaphore's * creation. * * All threads currently blocked on the semaphore are awoken. These * threads will return with the KERN_TERMINATED error. */ kern_return_t semaphore_destroy( task_t task, semaphore_t semaphore) { int old_count; spl_t spl_level; if (task == TASK_NULL || semaphore == SEMAPHORE_NULL) return KERN_INVALID_ARGUMENT; /* * Disown semaphore */ task_lock(task); if (semaphore->owner != task) { task_unlock(task); return KERN_INVALID_ARGUMENT; } remqueue(&task->semaphore_list, (queue_entry_t) semaphore); semaphore->owner = TASK_NULL; task->semaphores_owned--; task_unlock(task); spl_level = splsched(); semaphore_lock(semaphore); /* * Deactivate semaphore */ assert(semaphore->active); semaphore->active = FALSE; /* * Wakeup blocked threads */ old_count = semaphore->count; semaphore->count = 0; if (old_count < 0) { wait_queue_wakeup64_all_locked(&semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_RESTART, TRUE); /* unlock? */ } else { semaphore_unlock(semaphore); } splx(spl_level); /* * Deallocate * * Drop the semaphore reference, which in turn deallocates the * semaphore structure if the reference count goes to zero. */ ipc_port_dealloc_kernel(semaphore->port); semaphore_dereference(semaphore); return KERN_SUCCESS; }
void check_tasks (struct computer_status *cstatus, int64_t semid) { int i; semaphore_lock (semid); cstatus->ntasks = 0; for (i=0;i<MAXTASKS;i++) { if (cstatus->task[i].used) { if (cstatus->task[i].status == TASKSTATUS_RUNNING) { /* If the task is LOADING then there is no process running yet */ if (kill(cstatus->task[i].pid,0) == 0) { /* check if task is running */ cstatus->ntasks++; } else { /* task is registered but not running */ log_auto(L_WARNING,"Check tasks found no task where there should have been one."); cstatus->task[i].used = 0; } } else { // FIXME: LOADING or FINISHED ? cstatus->ntasks++; } } } semaphore_release (semid); }
void semaphore_destroy_all( task_t task) { uint32_t count; spl_t spl_level; count = 0; task_lock(task); while (!queue_empty(&task->semaphore_list)) { semaphore_t semaphore; semaphore = (semaphore_t) queue_first(&task->semaphore_list); if (count == 0) spl_level = splsched(); semaphore_lock(semaphore); semaphore_destroy_internal(task, semaphore); /* semaphore unlocked */ /* throttle number of semaphores per interrupt disablement */ if (++count == SEMASPERSPL) { count = 0; splx(spl_level); } } if (count != 0) splx(spl_level); task_unlock(task); }
/* * Routine: semaphore_destroy * * Destroys a semaphore and consume the caller's reference on the * semaphore. */ kern_return_t semaphore_destroy( task_t task, semaphore_t semaphore) { spl_t spl_level; if (semaphore == SEMAPHORE_NULL) return KERN_INVALID_ARGUMENT; if (task == TASK_NULL) { semaphore_dereference(semaphore); return KERN_INVALID_ARGUMENT; } task_lock(task); spl_level = splsched(); semaphore_lock(semaphore); if (semaphore->owner != task) { semaphore_unlock(semaphore); splx(spl_level); task_unlock(task); return KERN_INVALID_ARGUMENT; } semaphore_destroy_internal(task, semaphore); /* semaphore unlocked */ splx(spl_level); task_unlock(task); semaphore_dereference(semaphore); return KERN_SUCCESS; }
/* * Routine: semaphore_reference * * Take out a reference on a semaphore. This keeps the data structure * in existence (but the semaphore may be deactivated). */ void semaphore_reference( semaphore_t semaphore) { spl_t spl_level; spl_level = splsched(); semaphore_lock(semaphore); semaphore->ref_count++; semaphore_unlock(semaphore); splx(spl_level); }
std::tuple<VkResult, uint32_t> acquire_next_image(swapchain_type &swapchain, std::chrono::nanoseconds timeout, const semaphore::semaphore_type &semaphore, const fence::fence_type &fence) { uint32_t image_index; std::lock(internal::get_mutex(swapchain), internal::get_mutex(semaphore)); std::lock_guard<std::mutex> swapchain_lock(internal::get_mutex(swapchain), std::adopt_lock); std::lock_guard<std::mutex> semaphore_lock(internal::get_mutex(semaphore), std::adopt_lock); std::lock_guard<std::mutex> fence_lock(internal::get_mutex(fence), std::adopt_lock); const VkResult result(vkAcquireNextImageKHR( internal::get_instance(*internal::get_parent(swapchain)), internal::get_instance(swapchain), timeout.count(), internal::get_instance(semaphore), internal::get_instance(fence), &image_index)); return std::make_tuple(result, image_index); }
/* * Routine: semaphore_dereference * * Release a reference on a semaphore. If this is the last reference, * the semaphore data structure is deallocated. */ void semaphore_dereference( semaphore_t semaphore) { int ref_count; spl_t spl_level; if (semaphore != NULL) { spl_level = splsched(); semaphore_lock(semaphore); ref_count = --(semaphore->ref_count); semaphore_unlock(semaphore); splx(spl_level); if (ref_count == 0) { assert(wait_queue_empty(&semaphore->wait_queue)); zfree(semaphore_zone, semaphore); } } }
/* * Routine: semaphore_wait_internal * * Decrements the semaphore count by one. If the count is * negative after the decrement, the calling thread blocks * (possibly at a continuation and/or with a timeout). * * Assumptions: * The reference * A reference is held on the signal semaphore. */ kern_return_t semaphore_wait_internal( semaphore_t wait_semaphore, semaphore_t signal_semaphore, mach_timespec_t *wait_timep, void (*caller_cont)(kern_return_t)) { boolean_t nonblocking; int wait_result; spl_t spl_level; kern_return_t kr = KERN_ALREADY_WAITING; spl_level = splsched(); semaphore_lock(wait_semaphore); /* * Decide if we really have to wait. */ nonblocking = (wait_timep != (mach_timespec_t *)0) ? (wait_timep->tv_sec == 0 && wait_timep->tv_nsec == 0) : FALSE; if (!wait_semaphore->active) { kr = KERN_TERMINATED; } else if (wait_semaphore->count > 0) { wait_semaphore->count--; kr = KERN_SUCCESS; } else if (nonblocking) { kr = KERN_OPERATION_TIMED_OUT; } else { uint64_t abstime; thread_t self = current_thread(); wait_semaphore->count = -1; /* we don't keep an actual count */ thread_lock(self); /* * If it is a timed wait, calculate the wake up deadline. */ if (wait_timep != (mach_timespec_t *)0) { nanoseconds_to_absolutetime((uint64_t)wait_timep->tv_sec * NSEC_PER_SEC + wait_timep->tv_nsec, &abstime); clock_absolutetime_interval_to_deadline(abstime, &abstime); } else abstime = 0; (void)wait_queue_assert_wait64_locked( &wait_semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_ABORTSAFE, abstime, self); thread_unlock(self); } semaphore_unlock(wait_semaphore); splx(spl_level); /* * wait_semaphore is unlocked so we are free to go ahead and * signal the signal_semaphore (if one was provided). */ if (signal_semaphore != SEMAPHORE_NULL) { kern_return_t signal_kr; /* * lock the signal semaphore reference we got and signal it. * This will NOT block (we cannot block after having asserted * our intention to wait above). */ signal_kr = semaphore_signal_internal(signal_semaphore, THREAD_NULL, SEMAPHORE_SIGNAL_PREPOST); if (signal_kr == KERN_NOT_WAITING) signal_kr = KERN_SUCCESS; else if (signal_kr == KERN_TERMINATED) { /* * Uh!Oh! The semaphore we were to signal died. * We have to get ourselves out of the wait in * case we get stuck here forever (it is assumed * that the semaphore we were posting is gating * the decision by someone else to post the * semaphore we are waiting on). People will * discover the other dead semaphore soon enough. * If we got out of the wait cleanly (someone * already posted a wakeup to us) then return that * (most important) result. Otherwise, * return the KERN_TERMINATED status. */ thread_t self = current_thread(); clear_wait(self, THREAD_INTERRUPTED); kr = semaphore_convert_wait_result(self->wait_result); if (kr == KERN_ABORTED) kr = KERN_TERMINATED; } } /* * If we had an error, or we didn't really need to wait we can * return now that we have signalled the signal semaphore. */ if (kr != KERN_ALREADY_WAITING) return kr; /* * Now, we can block. If the caller supplied a continuation * pointer of his own for after the block, block with the * appropriate semaphore continuation. Thiswill gather the * semaphore results, release references on the semaphore(s), * and then call the caller's continuation. */ if (caller_cont) { thread_t self = current_thread(); self->sth_continuation = caller_cont; self->sth_waitsemaphore = wait_semaphore; self->sth_signalsemaphore = signal_semaphore; wait_result = thread_block((thread_continue_t)semaphore_wait_continue); } else { wait_result = thread_block(THREAD_CONTINUE_NULL); } return (semaphore_convert_wait_result(wait_result)); }
/* * Routine: semaphore_signal_internal * * Signals the semaphore as direct. * Assumptions: * Semaphore is locked. */ kern_return_t semaphore_signal_internal( semaphore_t semaphore, thread_t thread, int options) { kern_return_t kr; spl_t spl_level; spl_level = splsched(); semaphore_lock(semaphore); if (!semaphore->active) { semaphore_unlock(semaphore); splx(spl_level); return KERN_TERMINATED; } if (thread != THREAD_NULL) { if (semaphore->count < 0) { kr = wait_queue_wakeup64_thread_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, thread, THREAD_AWAKENED, TRUE); /* unlock? */ } else { semaphore_unlock(semaphore); kr = KERN_NOT_WAITING; } splx(spl_level); return kr; } if (options & SEMAPHORE_SIGNAL_ALL) { int old_count = semaphore->count; if (old_count < 0) { semaphore->count = 0; /* always reset */ kr = wait_queue_wakeup64_all_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_AWAKENED, TRUE); /* unlock? */ } else { if (options & SEMAPHORE_SIGNAL_PREPOST) semaphore->count++; semaphore_unlock(semaphore); kr = KERN_SUCCESS; } splx(spl_level); return kr; } if (semaphore->count < 0) { if (wait_queue_wakeup64_one_locked( &semaphore->wait_queue, SEMAPHORE_EVENT, THREAD_AWAKENED, FALSE) == KERN_SUCCESS) { semaphore_unlock(semaphore); splx(spl_level); return KERN_SUCCESS; } else semaphore->count = 0; /* all waiters gone */ } if (options & SEMAPHORE_SIGNAL_PREPOST) { semaphore->count++; } semaphore_unlock(semaphore); splx(spl_level); return KERN_NOT_WAITING; }
void launch_task (struct slave_database *sdb, uint16_t itask) { /* Here we get the job ready in the process task structure pointed by itask */ int rc; pid_t task_pid,waiter_pid; extern char **environ; char *exec_path; struct task *ttask; logtool = DRQ_LOG_TOOL_SLAVE_TASK; ttask = malloc (sizeof(*ttask)); memcpy(ttask,&sdb->comp->status.task[itask],sizeof(*ttask)); logger_task = ttask; if ((waiter_pid = fork()) == 0) { // // WAITER PROCESS // This process reports the execution of the command itself // set_signal_handlers_child_launcher (); if ((task_pid = fork()) == 0) { // // TASK PROCESS // This process executes the task // This child also creates the directory for logging if it doesn't exist // and prepares the file descriptors so every output will be logged // const char *new_argv[4]; int lfd; /* logger fd */ #ifdef __CYGWIN new_argv[0] = SHELL_NAME; new_argv[1] = "-c"; new_argv[2] = sdb->comp->status.task[itask].jobcmd; new_argv[3] = NULL; /* new_argv[0] = SHELL_NAME; */ /* if ((new_argv[1] = malloc(MAXCMDLEN)) == NULL) */ /* exit (1); */ /* cygwin_conv_to_posix_path(sdb->comp->status.task[itask].jobcmd,(char*)new_argv[1]); */ /* new_argv[2] = NULL; */ #else new_argv[0] = SHELL_NAME; new_argv[1] = "-c"; new_argv[2] = sdb->comp->status.task[itask].jobcmd; new_argv[3] = NULL; #endif setpgid(0,0); /* So this process doesn't receive signals from the others */ set_signal_handlers_task_exec (); if ((lfd = log_dumptask_open (&sdb->comp->status.task[itask])) != -1) { // Log on the logger file whatever goes to stdout and stderr dup2 (lfd,STDOUT_FILENO); dup2 (lfd,STDERR_FILENO); close (lfd); } task_environment_set(&sdb->comp->status.task[itask]); #ifdef __CYGWIN exec_path = SHELL_PATH; /* exec_path = malloc(PATH_MAX); */ /* char *dr_bin = getenv("DRQUEUE_BIN"); */ /* if (dr_bin) { */ /* snprintf (exec_path,PATH_MAX,"%s/tcsh.exe",dr_bin); */ /* } */ #else exec_path = SHELL_PATH; #endif execve(exec_path,(char*const*)new_argv,environ); // Wouldn't reach this point unless error on execve drerrno_system = errno; log_auto(L_ERROR,"launch_task(): error on execve. (%s)",strerror(drerrno_system)); slave_exit(SIGINT); } else if (task_pid == -1) { log_auto(L_ERROR,"lauch_task(): Fork failed. Task not created."); //semaphore_lock(sdb->semid); //sdb->comp->status.task[itask].used = 0; /* We don't need the task anymore */ //semaphore_release(sdb->semid); } // Then we set the process as loading // Later on, well make a check for every loading frame and if running change its status semaphore_lock(sdb->semid); sdb->comp->status.task[itask].status = TASKSTATUS_LOADING; sdb->comp->status.task[itask].start_loading_time = time(NULL); sdb->comp->status.task[itask].pid = task_pid; sdb->comp->status.ntasks = computer_ntasks (sdb->comp); sdb->comp->status.nrunning = computer_nrunning (sdb->comp); semaphore_release(sdb->semid); if (waitpid(task_pid,&rc,0) == -1) { // It forked on task_pid but waitpid says it doesn't exist. drerrno_system = errno; log_auto(L_ERROR,"lauch_task(): task process (%i) does not exist. (%s)",task_pid,strerror(drerrno_system)); semaphore_lock(sdb->semid); sdb->comp->status.task[itask].used = 0; /* We don't need the task anymore */ sdb->comp->status.ntasks = computer_ntasks (sdb->comp); sdb->comp->status.nrunning = computer_nrunning (sdb->comp); semaphore_release(sdb->semid); // FIXME: notify the master ? } else { // waitpid returned successfully /* We have to clean the task and send the info to the master */ /* consider WIFSIGNALED(status), WTERMSIG(status), WEXITSTATUS(status) */ /* we pass directly the status (translated to DR) to the master and he decides what to do with the frame */ semaphore_lock(sdb->semid); sdb->comp->status.task[itask].exitstatus = 0; sdb->comp->status.task[itask].status = TASKSTATUS_FINISHED; sdb->comp->status.ntasks = computer_ntasks (sdb->comp); sdb->comp->status.nrunning = computer_nrunning (sdb->comp); if (WIFSIGNALED(rc)) { /* Process exited abnormally either killed by us or by itself (SIGSEGV) */ /* printf ("\n\nSIGNALED with %i\n",WTERMSIG(rc)); */ sdb->comp->status.task[itask].exitstatus |= DR_SIGNALEDFLAG ; sdb->comp->status.task[itask].exitstatus |= WTERMSIG(rc); log_auto(L_INFO,"Task signaled"); } else { if (WIFEXITED(rc)) { /* printf ("\n\nEXITED with %i\n",WEXITSTATUS(rc)); */ sdb->comp->status.task[itask].exitstatus |= DR_EXITEDFLAG ; sdb->comp->status.task[itask].exitstatus |= WEXITSTATUS(rc); /* printf ("\n\nEXITED with %i\n",DR_WEXITSTATUS(sdb->comp->status.task[itask].exitstatus)); */ log_auto(L_INFO,"Task finished"); } else { log_auto(L_WARNING,"Task finished with rc = %i",rc); } } semaphore_release(sdb->semid); request_task_finished (sdb,itask); semaphore_lock(sdb->semid); sdb->comp->status.task[itask].used = 0; /* We don't need the task anymore */ semaphore_release(sdb->semid); } exit (0); } else if (waiter_pid == -1) { log_auto(L_WARNING,"Fork failed for task waiter"); semaphore_lock(sdb->semid); sdb->comp->status.task[itask].used = 0; /* We don't need the task anymore */ semaphore_release(sdb->semid); exit (1); } else { // in this "else" waiter_pid actually contains the PID of the waiter process } }
int database_save (struct database *wdb) { /* This function returns 1 on success and 0 on failure */ /* It logs failure and maybe it should leave that task to the calling function */ /* README : this function reads from the database memory without locking */ struct database_hdr hdr; char *basedir; char dir[BUFFERLEN]; char filename[BUFFERLEN]; int fd; uint32_t c; // FIXME: this all filename guessing should be inside a function if ((basedir = getenv ("DRQUEUE_DB")) == NULL) { /* This should never happen because we check it at the beginning of the program */ log_auto (L_ERROR,"database_save() : DRQUEUE_DB environment variable could not be found. Master db cannot be saved."); drerrno = DRE_NOENVROOT; return 0; } snprintf (dir, BUFFERLEN - 1, "%s", basedir); snprintf (filename, BUFFERLEN - 1, "%s/drqueue.db", dir); // Lock it semaphore_lock(wdb->semid); if (database_backup(wdb) == 0) { // FIXME: filename should be a value returned by a function log_auto (L_ERROR,"database_save() : there was an error while backing up old database. NOT SAVING current one. (file: %s)", filename); } // FIXME: // dbfd = database_file_open(filename) log_auto (L_INFO,"Storing DB into: '%s'",filename); if ((fd = open (filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { if (errno == ENOENT) { /* If its because the directory does not exist we try creating it first */ #ifdef _WIN32 if (mkdir (dir) == -1) { #else if (mkdir (dir, 0775) == -1) { #endif drerrno_system = errno; log_auto (L_WARNING,"Could not create database directory. Check permissions: %s. (%s)", dir,strerror(drerrno_system)); drerrno = DRE_COULDNOTCREATE; return 0; } if ((fd = open (filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { log_auto (L_WARNING,"Could not open database file for writing. Check permissions: %s. (%s)", filename,strerror(drerrno_system)); drerrno = DRE_COULDNOTCREATE; return 0; } } else { /* could not open the file for other reasons */ log_auto (L_WARNING,"Could not open database file for writing. Check permissions: %s", filename); drerrno = DRE_COULDNOTCREATE; return 0; } } // FIXME: database_header_save() hdr.magic = DB_MAGIC; hdr.version = database_version_id(); hdr.job_size = MAXJOBS; write_32b (fd, &hdr.magic); write_32b (fd, &hdr.version); write_16b (fd, &hdr.job_size); for (c = 0; c < hdr.job_size; c++) { logger_job = &wdb->job[c]; if (!database_job_save (fd, &wdb->job[c])) { // FIXME: report log_auto (L_ERROR,"database_save(): error saving job number %i. (%s)",c,strerror(drerrno_system)); return 0; } } logger_job = NULL; log_auto (L_INFO,"Database saved successfully."); semaphore_release(wdb->semid); // Unlock it return 1; } int database_job_save_frames (int sfd, struct job *job) { int nframes = job_nframes (job); struct frame_info *fi; int i; if ((fi = attach_frame_shared_memory (job->fishmid)) == (void *) -1) { // Store empty frames in an attemp to save other jobs // FIXME: Warning CORRUPT struct frame_info fi2; job_frame_info_init (&fi2); for (i = 0; i < nframes; i++) { if (!send_frame_info (sfd, &fi2)) { return 0; } } } else { for (i = 0; i < nframes; i++) { if (!send_frame_info (sfd, &fi[i])) { detach_frame_shared_memory (fi); return 0; } } detach_frame_shared_memory (fi); } return 1; }
/* * Routine: semaphore_signal_internal * * Signals the semaphore as direct. * Assumptions: * Semaphore is locked. */ kern_return_t semaphore_signal_internal( semaphore_t semaphore, thread_t thread, int options) { kern_return_t kr; spl_t spl_level; spl_level = splsched(); semaphore_lock(semaphore); if (!semaphore->active) { semaphore_unlock(semaphore); splx(spl_level); return KERN_TERMINATED; } if (thread != THREAD_NULL) { if (semaphore->count < 0) { kr = waitq_wakeup64_thread_locked( &semaphore->waitq, SEMAPHORE_EVENT, thread, THREAD_AWAKENED, WAITQ_UNLOCK); /* waitq/semaphore is unlocked */ } else { kr = KERN_NOT_WAITING; semaphore_unlock(semaphore); } splx(spl_level); return kr; } if (options & SEMAPHORE_SIGNAL_ALL) { int old_count = semaphore->count; kr = KERN_NOT_WAITING; if (old_count < 0) { semaphore->count = 0; /* always reset */ kr = waitq_wakeup64_all_locked( &semaphore->waitq, SEMAPHORE_EVENT, THREAD_AWAKENED, NULL, WAITQ_ALL_PRIORITIES, WAITQ_UNLOCK); /* waitq / semaphore is unlocked */ } else { if (options & SEMAPHORE_SIGNAL_PREPOST) semaphore->count++; kr = KERN_SUCCESS; semaphore_unlock(semaphore); } splx(spl_level); return kr; } if (semaphore->count < 0) { kr = waitq_wakeup64_one_locked( &semaphore->waitq, SEMAPHORE_EVENT, THREAD_AWAKENED, NULL, WAITQ_ALL_PRIORITIES, WAITQ_KEEP_LOCKED); if (kr == KERN_SUCCESS) { semaphore_unlock(semaphore); splx(spl_level); return KERN_SUCCESS; } else { semaphore->count = 0; /* all waiters gone */ } } if (options & SEMAPHORE_SIGNAL_PREPOST) { semaphore->count++; } semaphore_unlock(semaphore); splx(spl_level); return KERN_NOT_WAITING; }