Пример #1
0
static status_t
mutex_lock(pthread_mutex_t* mutex, bigtime_t timeout)
{
	thread_id thisThread = find_thread(NULL);

	if (mutex->owner == thisThread) {
		// recursive locking handling
		if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE) {
			if (mutex->owner_count == INT32_MAX)
				return EAGAIN;

			mutex->owner_count++;
			return 0;
		}

		// deadlock check (not for PTHREAD_MUTEX_NORMAL as per the specs)
		if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK
			|| MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) {
			// we detect this kind of deadlock and return an error
			return timeout < 0 ? EBUSY : EDEADLK;
		}
	}

	// set the locked flag
	int32 oldValue = atomic_or((int32*)&mutex->lock, B_USER_MUTEX_LOCKED);

	if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) {
		// someone else has the lock or is at least waiting for it
		if (timeout < 0)
			return EBUSY;

		// we have to call the kernel
		status_t error;
		do {
			error = _kern_mutex_lock((int32*)&mutex->lock, NULL,
				timeout == B_INFINITE_TIMEOUT
					? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
				timeout);
		} while (error == B_INTERRUPTED);

		if (error != B_OK)
			return error;
	}

	// we have locked the mutex for the first time
	mutex->owner = thisThread;
	mutex->owner_count = 1;

	return 0;
}
Пример #2
0
static status_t
mutex_lock(pthread_mutex_t *mutex, bigtime_t timeout)
{
	thread_id thisThread = find_thread(NULL);
	status_t status = B_OK;

	if (mutex == NULL)
		return B_BAD_VALUE;

	// If statically initialized, we need to create the semaphore, now.
	if (mutex->sem == -42) {
		sem_id sem = create_sem(0, "pthread_mutex");
		if (sem < 0)
			return EAGAIN;

		if (atomic_test_and_set((vint32*)&mutex->sem, sem, -42) != -42)
			delete_sem(sem);
	}

	if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK
		&& mutex->owner == thisThread) {
		// we detect this kind of deadlock and return an error
		return EDEADLK;
	}

	if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE
		&& mutex->owner == thisThread) {
		// if we already hold the mutex, we don't need to grab it again
		mutex->owner_count++;
		return B_OK;
	}

	if (atomic_add((vint32*)&mutex->count, 1) > 0) {
		// this mutex is already locked by someone else, so we need
		// to wait
		status = acquire_sem_etc(mutex->sem, 1,
			timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
			timeout);
	}

	if (status == B_OK) {
		// we have locked the mutex for the first time
		mutex->owner = thisThread;
		mutex->owner_count = 1;
	}

	return status;
}
Пример #3
0
int
pthread_mutex_unlock(pthread_mutex_t *mutex)
{
	if (mutex == NULL)
		return B_BAD_VALUE;

	if (mutex->owner != find_thread(NULL))
		return EPERM;

	if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE
		&& mutex->owner_count-- > 1) {
		return B_OK;
	}

	mutex->owner = -1;

	if (atomic_add((vint32*)&mutex->count, -1) > 1)
		return release_sem(mutex->sem);

	return B_OK;
}
Пример #4
0
int
pthread_mutex_unlock(pthread_mutex_t* mutex)
{
	if (mutex->owner != find_thread(NULL))
		return EPERM;

	if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE
		&& --mutex->owner_count > 0) {
		// still locked
		return 0;
	}

	mutex->owner = -1;

	// clear the locked flag
	int32 oldValue = atomic_and((int32*)&mutex->lock,
		~(int32)B_USER_MUTEX_LOCKED);
	if ((oldValue & B_USER_MUTEX_WAITING) != 0)
		_kern_mutex_unlock((int32*)&mutex->lock, 0);

	return 0;
}