xref: /haiku/src/system/libroot/os/locks/mutex.cpp (revision f71274580bc2625bf438140839fe38193ece28e6)
1258b34c5SIngo Weinhold /*
2258b34c5SIngo Weinhold  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3*f7127458SIngo Weinhold  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
4258b34c5SIngo Weinhold  * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5258b34c5SIngo Weinhold  * Distributed under the terms of the MIT License.
6258b34c5SIngo Weinhold  *
7258b34c5SIngo Weinhold  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8258b34c5SIngo Weinhold  * Distributed under the terms of the NewOS License.
9258b34c5SIngo Weinhold  */
10258b34c5SIngo Weinhold 
11258b34c5SIngo Weinhold 
12258b34c5SIngo Weinhold #include <locks.h>
13258b34c5SIngo Weinhold 
14*f7127458SIngo Weinhold #include <stdlib.h>
15*f7127458SIngo Weinhold #include <string.h>
16*f7127458SIngo Weinhold 
17*f7127458SIngo Weinhold #include <syscalls.h>
18*f7127458SIngo Weinhold #include <user_mutex_defs.h>
19258b34c5SIngo Weinhold 
20258b34c5SIngo Weinhold 
21258b34c5SIngo Weinhold // #pragma mark - mutex
22258b34c5SIngo Weinhold 
23258b34c5SIngo Weinhold 
24*f7127458SIngo Weinhold void
25258b34c5SIngo Weinhold mutex_init(mutex *lock, const char *name)
26258b34c5SIngo Weinhold {
27*f7127458SIngo Weinhold 	lock->name = name;
28*f7127458SIngo Weinhold 	lock->lock = 0;
29*f7127458SIngo Weinhold 	lock->flags = 0;
30*f7127458SIngo Weinhold }
31258b34c5SIngo Weinhold 
32258b34c5SIngo Weinhold 
33*f7127458SIngo Weinhold void
34*f7127458SIngo Weinhold mutex_init_etc(mutex *lock, const char *name, uint32 flags)
35*f7127458SIngo Weinhold {
36*f7127458SIngo Weinhold 	lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name;
37*f7127458SIngo Weinhold 	lock->lock = 0;
38*f7127458SIngo Weinhold 	lock->flags = flags;
39258b34c5SIngo Weinhold }
40258b34c5SIngo Weinhold 
41258b34c5SIngo Weinhold 
42258b34c5SIngo Weinhold void
43258b34c5SIngo Weinhold mutex_destroy(mutex *lock)
44258b34c5SIngo Weinhold {
45*f7127458SIngo Weinhold 	if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0)
46*f7127458SIngo Weinhold 		free(const_cast<char*>(lock->name));
47258b34c5SIngo Weinhold }
48258b34c5SIngo Weinhold 
49258b34c5SIngo Weinhold 
50258b34c5SIngo Weinhold status_t
51258b34c5SIngo Weinhold mutex_lock(mutex *lock)
52258b34c5SIngo Weinhold {
53*f7127458SIngo Weinhold 	// set the locked flag
54*f7127458SIngo Weinhold 	int32 oldValue = atomic_or(&lock->lock, B_USER_MUTEX_LOCKED);
55*f7127458SIngo Weinhold 
56*f7127458SIngo Weinhold 	if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0
57*f7127458SIngo Weinhold 			|| (oldValue & B_USER_MUTEX_DISABLED) != 0) {
58*f7127458SIngo Weinhold 		// No one has the lock or is waiting for it, or the mutex has been
59*f7127458SIngo Weinhold 		// disabled.
60258b34c5SIngo Weinhold 		return B_OK;
61*f7127458SIngo Weinhold 	}
62258b34c5SIngo Weinhold 
63*f7127458SIngo Weinhold 	// we have to call the kernel
64*f7127458SIngo Weinhold 	status_t error;
65258b34c5SIngo Weinhold 	do {
66*f7127458SIngo Weinhold 		error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0);
67*f7127458SIngo Weinhold 	} while (error == B_INTERRUPTED);
68258b34c5SIngo Weinhold 
69*f7127458SIngo Weinhold 	return error;
70258b34c5SIngo Weinhold }
71258b34c5SIngo Weinhold 
72258b34c5SIngo Weinhold 
73258b34c5SIngo Weinhold void
74258b34c5SIngo Weinhold mutex_unlock(mutex *lock)
75258b34c5SIngo Weinhold {
76*f7127458SIngo Weinhold 	// clear the locked flag
77*f7127458SIngo Weinhold 	int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED);
78*f7127458SIngo Weinhold 	if ((oldValue & B_USER_MUTEX_WAITING) != 0
79*f7127458SIngo Weinhold 			&& (oldValue & B_USER_MUTEX_DISABLED) == 0) {
80*f7127458SIngo Weinhold 		_kern_mutex_unlock(&lock->lock, 0);
81258b34c5SIngo Weinhold 	}
82258b34c5SIngo Weinhold }
83