xref: /haiku/src/system/libroot/os/locks/mutex.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
3  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
4  * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5  * Distributed under the terms of the MIT License.
6  *
7  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9  */
10 
11 
12 #include <locks.h>
13 
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <syscalls.h>
18 #include <user_mutex_defs.h>
19 
20 
21 #define MAX_UNSUCCESSFUL_SPINS	100
22 
23 
24 extern int32 __gCPUCount;
25 
26 
27 // #pragma mark - mutex
28 
29 
30 void
31 __mutex_init(mutex *lock, const char *name)
32 {
33 	lock->name = name;
34 	lock->lock = 0;
35 	lock->flags = 0;
36 }
37 
38 
39 void
40 __mutex_init_etc(mutex *lock, const char *name, uint32 flags)
41 {
42 	lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name;
43 	lock->lock = 0;
44 	lock->flags = flags;
45 
46 	if (__gCPUCount < 2)
47 		lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE);
48 }
49 
50 
51 void
52 __mutex_destroy(mutex *lock)
53 {
54 	if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0)
55 		free(const_cast<char*>(lock->name));
56 }
57 
58 
59 status_t
60 __mutex_lock(mutex *lock)
61 {
62 	uint32 count = 0;
63 	const uint32 kMaxCount
64 		= (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1;
65 
66 	int32 oldValue;
67 	do {
68 		oldValue = atomic_test_and_set(&lock->lock, B_USER_MUTEX_LOCKED, 0);
69 		if (oldValue == 0 || (oldValue & B_USER_MUTEX_DISABLED) != 0)
70 			return B_OK;
71 	} while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0);
72 
73 	// we have to call the kernel
74 	status_t error;
75 	do {
76 		error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0);
77 	} while (error == B_INTERRUPTED);
78 
79 	return error;
80 }
81 
82 
83 void
84 __mutex_unlock(mutex *lock)
85 {
86 	// clear the locked flag
87 	int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED);
88 	if ((oldValue & B_USER_MUTEX_WAITING) != 0
89 			&& (oldValue & B_USER_MUTEX_DISABLED) == 0) {
90 		_kern_mutex_unblock(&lock->lock, 0);
91 	}
92 
93 	if ((oldValue & B_USER_MUTEX_LOCKED) == 0) {
94 #if 0
95 		debugger("mutex was not actually locked!");
96 #else
97 		// The above happens too often at present (see bug #18451).
98 		_kern_debug_output("libroot __mutex_unlock: mutex was not actually locked!\n");
99 #endif
100 	}
101 }
102