xref: /haiku/src/system/libroot/os/locks/mutex.cpp (revision 65a76a0fb932805d6f1714e507c871c863037222)
1258b34c5SIngo Weinhold /*
2258b34c5SIngo Weinhold  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3f7127458SIngo 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 
14f7127458SIngo Weinhold #include <stdlib.h>
15f7127458SIngo Weinhold #include <string.h>
16f7127458SIngo Weinhold 
17f7127458SIngo Weinhold #include <syscalls.h>
18f7127458SIngo Weinhold #include <user_mutex_defs.h>
19258b34c5SIngo Weinhold 
20258b34c5SIngo Weinhold 
217e1c4534SPawel Dziepak #define MAX_UNSUCCESSFUL_SPINS	100
227e1c4534SPawel Dziepak 
237e1c4534SPawel Dziepak 
247e1c4534SPawel Dziepak extern int32 __gCPUCount;
257e1c4534SPawel Dziepak 
267e1c4534SPawel Dziepak 
27258b34c5SIngo Weinhold // #pragma mark - mutex
28258b34c5SIngo Weinhold 
29258b34c5SIngo Weinhold 
30f7127458SIngo Weinhold void
31b916156aSJulian Harnath __mutex_init(mutex *lock, const char *name)
32258b34c5SIngo Weinhold {
33f7127458SIngo Weinhold 	lock->name = name;
34f7127458SIngo Weinhold 	lock->lock = 0;
35f7127458SIngo Weinhold 	lock->flags = 0;
36f7127458SIngo Weinhold }
37258b34c5SIngo Weinhold 
38258b34c5SIngo Weinhold 
39f7127458SIngo Weinhold void
40b916156aSJulian Harnath __mutex_init_etc(mutex *lock, const char *name, uint32 flags)
41f7127458SIngo Weinhold {
42f7127458SIngo Weinhold 	lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name;
43f7127458SIngo Weinhold 	lock->lock = 0;
44f7127458SIngo Weinhold 	lock->flags = flags;
457e1c4534SPawel Dziepak 
467e1c4534SPawel Dziepak 	if (__gCPUCount < 2)
477e1c4534SPawel Dziepak 		lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE);
48258b34c5SIngo Weinhold }
49258b34c5SIngo Weinhold 
50258b34c5SIngo Weinhold 
51258b34c5SIngo Weinhold void
52b916156aSJulian Harnath __mutex_destroy(mutex *lock)
53258b34c5SIngo Weinhold {
54f7127458SIngo Weinhold 	if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0)
55f7127458SIngo Weinhold 		free(const_cast<char*>(lock->name));
56258b34c5SIngo Weinhold }
57258b34c5SIngo Weinhold 
58258b34c5SIngo Weinhold 
59258b34c5SIngo Weinhold status_t
60b916156aSJulian Harnath __mutex_lock(mutex *lock)
61258b34c5SIngo Weinhold {
6282727571SPawel Dziepak 	uint32 count = 0;
637e1c4534SPawel Dziepak 	const uint32 kMaxCount
647e1c4534SPawel Dziepak 		= (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1;
657e1c4534SPawel Dziepak 
667e1c4534SPawel Dziepak 	int32 oldValue;
677e1c4534SPawel Dziepak 	do {
68f7127458SIngo Weinhold 		// set the locked flag
697e1c4534SPawel Dziepak 		oldValue = atomic_or(&lock->lock, B_USER_MUTEX_LOCKED);
70f7127458SIngo Weinhold 
71f7127458SIngo Weinhold 		if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0
72f7127458SIngo Weinhold 				|| (oldValue & B_USER_MUTEX_DISABLED) != 0) {
73f7127458SIngo Weinhold 			// No one has the lock or is waiting for it, or the mutex has been
74f7127458SIngo Weinhold 			// disabled.
75258b34c5SIngo Weinhold 			return B_OK;
76f7127458SIngo Weinhold 		}
777e1c4534SPawel Dziepak 	} while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0);
78258b34c5SIngo Weinhold 
79f7127458SIngo Weinhold 	// we have to call the kernel
80f7127458SIngo Weinhold 	status_t error;
81258b34c5SIngo Weinhold 	do {
82f7127458SIngo Weinhold 		error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0);
83f7127458SIngo Weinhold 	} while (error == B_INTERRUPTED);
84258b34c5SIngo Weinhold 
85f7127458SIngo Weinhold 	return error;
86258b34c5SIngo Weinhold }
87258b34c5SIngo Weinhold 
88258b34c5SIngo Weinhold 
89258b34c5SIngo Weinhold void
90b916156aSJulian Harnath __mutex_unlock(mutex *lock)
91258b34c5SIngo Weinhold {
92f7127458SIngo Weinhold 	// clear the locked flag
93f7127458SIngo Weinhold 	int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED);
94f7127458SIngo Weinhold 	if ((oldValue & B_USER_MUTEX_WAITING) != 0
95f7127458SIngo Weinhold 			&& (oldValue & B_USER_MUTEX_DISABLED) == 0) {
96f7127458SIngo Weinhold 		_kern_mutex_unlock(&lock->lock, 0);
97258b34c5SIngo Weinhold 	}
98*65a76a0fSAugustin Cavalier 
99*65a76a0fSAugustin Cavalier 	if ((oldValue & B_USER_MUTEX_LOCKED) == 0)
100*65a76a0fSAugustin Cavalier 		debugger("mutex was not actually locked!");
101258b34c5SIngo Weinhold }
102