add: } else { #ifdef DEBUG_LAST_ACQUIRER sSems[slot].u.used.last_acquirer = thread_get_current_thread_id(); #endif
context: switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count,	uint32 flags, bigtime_t timeout){	int slot = id % sMaxSems;	int state;	status_t status = B_OK;		if (sSemsActive == false)		return B_NO_MORE_SEMS;	if (!kernel_startup && !are_interrupts_enabled())		panic("acquire_sem_etc: called with interrupts disabled for sem %#lx\n", id);	if (id < 0)		return B_BAD_SEM_ID;	if (count <= 0		|| (flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) == (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) {		return B_BAD_VALUE;	}	state = disable_interrupts();	GRAB_SEM_LOCK(sSems[slot]);	if (sSems[slot].id != id) {		TRACE(("acquire_sem_etc: bad sem_id %ld\n", id));		status = B_BAD_SEM_ID;		goto err;	}	// ToDo: the B_CHECK_PERMISSION flag should be made private, as it	//	doesn't have any use outside the kernel	if ((flags & B_CHECK_PERMISSION) != 0		&& sSems[slot].u.used.owner == team_get_kernel_team_id()) {		dprintf("thread %ld tried to acquire kernel semaphore.\n", thread_get_current_thread()->id);		status = B_NOT_ALLOWED;		goto err;	}	if (sSems[slot].u.used.count - count < 0 && (flags & B_RELATIVE_TIMEOUT) != 0		&& timeout <= 0) {		// immediate timeout		status = B_WOULD_BLOCK;		goto err;	}	if ((sSems[slot].u.used.count -= count) < 0) {		// we need to block		struct thread *thread = thread_get_current_thread();		timer timeout_timer; // stick it on the stack, since we may be blocking here		struct sem_timeout_args args;		TRACE_BLOCK(("acquire_sem_etc(id = %ld): block name = %s, thread = %p,"					 " name = %s\n", id, sSems[slot].u.used.name, thread, thread->name));		// do a quick check to see if the thread has any pending signals		// this should catch most of the cases where the thread had a signal		if (((flags & B_CAN_INTERRUPT) && thread->sig_pending)			|| ((flags & B_KILL_CAN_INTERRUPT)				&& (thread->sig_pending & KILL_SIGNALS))) {			sSems[slot].u.used.count += count;			status = B_INTERRUPTED;			goto err;		}		if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) == 0)			timeout = B_INFINITE_TIMEOUT;		thread->next_state = B_THREAD_WAITING;		thread->sem.flags = flags;		thread->sem.blocking = id;		thread->sem.acquire_count = count;		thread->sem.count = min(-sSems[slot].u.used.count, count);			// store the count we need to restore upon release		thread->sem.acquire_status = B_NO_ERROR;		thread_enqueue(thread, &sSems[slot].u.used.queue);		if (timeout != B_INFINITE_TIMEOUT) {			TRACE(("sem_acquire_etc: setting timeout sem for %Ld usecs, semid %d, tid %d\n",				timeout, id, thread->id));			// set up an event to go off with the thread struct as the data			args.blocked_sem_id = id;			args.blocked_thread = thread->id;			args.sem_count = count;			// ToDo: another evil hack: pass the args into timer->entry.prev			timeout_timer.entry.prev = (qent *)&args;			add_timer(&timeout_timer, &sem_timeout, timeout,				flags & B_RELATIVE_TIMEOUT ?					B_ONE_SHOT_RELATIVE_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER);					}		RELEASE_SEM_LOCK(sSems[slot]);		if (semToBeReleased >= B_OK)			release_sem_etc(semToBeReleased, 1, B_DO_NOT_RESCHEDULE);		GRAB_THREAD_LOCK();		// check again to see if a signal is pending.		// it may have been delivered while setting up the sem, though it's pretty unlikely		if (((flags & B_CAN_INTERRUPT) && thread->sig_pending)			|| ((flags & B_KILL_CAN_INTERRUPT)				&& (thread->sig_pending & KILL_SIGNALS))) {			struct thread_queue wakeupQueue;			// ok, so a tiny race happened where a signal was delivered to this thread while			// it was setting up the sem. We can only be sure a signal wasn't delivered			// here, since the threadlock is held. The previous check would have found most			// instances, but there was a race, so we have to handle it. It'll be more messy...			clear_thread_queue(&wakeupQueue);			GRAB_SEM_LOCK(sSems[slot]);			if (sSems[slot].id == id) {				remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_INTERRUPTED);			}			RELEASE_SEM_LOCK(sSems[slot]);			while ((thread = thread_dequeue(&wakeupQueue)) != NULL) {				scheduler_enqueue_in_run_queue(thread);			}			// fall through and reschedule since another thread with a higher priority may have been woken up		}		scheduler_reschedule();		RELEASE_THREAD_LOCK();		if (timeout != B_INFINITE_TIMEOUT) {			if (thread->sem.acquire_status != B_TIMED_OUT) {				// cancel the timer event, the sem may have been deleted or interrupted				// with the timer still active				cancel_timer(&timeout_timer);			}		}		restore_interrupts(state);		TRACE_BLOCK(("acquire_sem_etc(id = %ld): exit block name = %s, "					 "thread = %p (%s)\n", id, sSems[slot].u.used.name, thread,					 thread->name));		return thread->sem.acquire_status;	}err:	RELEASE_SEM_LOCK(sSems[slot]);	restore_interrupts(state);	return status;}