1f7127458SIngo Weinhold /*
2f7127458SIngo Weinhold * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3f7127458SIngo Weinhold * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4f7127458SIngo Weinhold * Distributed under the terms of the MIT License.
5f7127458SIngo Weinhold */
6f7127458SIngo Weinhold
7f7127458SIngo Weinhold
8f7127458SIngo Weinhold #include <pthread.h>
9f7127458SIngo Weinhold #include "pthread_private.h"
10f7127458SIngo Weinhold
1165a76a0fSAugustin Cavalier #include <assert.h>
12f7127458SIngo Weinhold #include <stdio.h>
13f7127458SIngo Weinhold #include <stdlib.h>
14f7127458SIngo Weinhold #include <string.h>
15f7127458SIngo Weinhold
16f7127458SIngo Weinhold #include <syscalls.h>
17f7127458SIngo Weinhold #include <user_mutex_defs.h>
18b8fdef84SAugustin Cavalier #include <time_private.h>
19f7127458SIngo Weinhold
20f7127458SIngo Weinhold
21f7127458SIngo Weinhold #define MUTEX_TYPE_BITS 0x0000000f
22f7127458SIngo Weinhold #define MUTEX_TYPE(mutex) ((mutex)->flags & MUTEX_TYPE_BITS)
23f7127458SIngo Weinhold
24f7127458SIngo Weinhold
25f7127458SIngo Weinhold static const pthread_mutexattr pthread_mutexattr_default = {
26f7127458SIngo Weinhold PTHREAD_MUTEX_DEFAULT,
27f7127458SIngo Weinhold false
28f7127458SIngo Weinhold };
29f7127458SIngo Weinhold
30f7127458SIngo Weinhold
31f7127458SIngo Weinhold int
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * _attr)32f7127458SIngo Weinhold pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* _attr)
33f7127458SIngo Weinhold {
34f7127458SIngo Weinhold const pthread_mutexattr* attr = _attr != NULL
35f7127458SIngo Weinhold ? *_attr : &pthread_mutexattr_default;
36f7127458SIngo Weinhold
37f7127458SIngo Weinhold mutex->lock = 0;
38f7127458SIngo Weinhold mutex->owner = -1;
39f7127458SIngo Weinhold mutex->owner_count = 0;
40f7127458SIngo Weinhold mutex->flags = attr->type | (attr->process_shared ? MUTEX_FLAG_SHARED : 0);
41f7127458SIngo Weinhold
42f7127458SIngo Weinhold return 0;
43f7127458SIngo Weinhold }
44f7127458SIngo Weinhold
45f7127458SIngo Weinhold
46f7127458SIngo Weinhold int
pthread_mutex_destroy(pthread_mutex_t * mutex)47f7127458SIngo Weinhold pthread_mutex_destroy(pthread_mutex_t* mutex)
48f7127458SIngo Weinhold {
49f7127458SIngo Weinhold return 0;
50f7127458SIngo Weinhold }
51f7127458SIngo Weinhold
52f7127458SIngo Weinhold
533c2901a9SAugustin Cavalier status_t
__pthread_mutex_lock(pthread_mutex_t * mutex,uint32 flags,bigtime_t timeout)54e41d4bd1SJérôme Duval __pthread_mutex_lock(pthread_mutex_t* mutex, uint32 flags, bigtime_t timeout)
55f7127458SIngo Weinhold {
56f7127458SIngo Weinhold thread_id thisThread = find_thread(NULL);
57f7127458SIngo Weinhold
58f7127458SIngo Weinhold if (mutex->owner == thisThread) {
59f7127458SIngo Weinhold // recursive locking handling
60f7127458SIngo Weinhold if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE) {
61f7127458SIngo Weinhold if (mutex->owner_count == INT32_MAX)
62f7127458SIngo Weinhold return EAGAIN;
63f7127458SIngo Weinhold
64f7127458SIngo Weinhold mutex->owner_count++;
65f7127458SIngo Weinhold return 0;
66f7127458SIngo Weinhold }
67f7127458SIngo Weinhold
68f7127458SIngo Weinhold // deadlock check (not for PTHREAD_MUTEX_NORMAL as per the specs)
69f7127458SIngo Weinhold if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK
70f7127458SIngo Weinhold || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) {
71f7127458SIngo Weinhold // we detect this kind of deadlock and return an error
72f7127458SIngo Weinhold return timeout < 0 ? EBUSY : EDEADLK;
73f7127458SIngo Weinhold }
74f7127458SIngo Weinhold }
75f7127458SIngo Weinhold
76f7127458SIngo Weinhold // set the locked flag
776f3f29c7SAugustin Cavalier const int32 oldValue = atomic_test_and_set((int32*)&mutex->lock, B_USER_MUTEX_LOCKED, 0);
786f3f29c7SAugustin Cavalier if (oldValue != 0) {
79f7127458SIngo Weinhold // someone else has the lock or is at least waiting for it
80f7127458SIngo Weinhold if (timeout < 0)
81f7127458SIngo Weinhold return EBUSY;
8293d7d1c5SAugustin Cavalier if ((mutex->flags & MUTEX_FLAG_SHARED) != 0)
8393d7d1c5SAugustin Cavalier flags |= B_USER_MUTEX_SHARED;
84f7127458SIngo Weinhold
85f7127458SIngo Weinhold // we have to call the kernel
86f7127458SIngo Weinhold status_t error;
87f7127458SIngo Weinhold do {
88e41d4bd1SJérôme Duval error = _kern_mutex_lock((int32*)&mutex->lock, NULL, flags, timeout);
89f7127458SIngo Weinhold } while (error == B_INTERRUPTED);
90f7127458SIngo Weinhold
91f7127458SIngo Weinhold if (error != B_OK)
92f7127458SIngo Weinhold return error;
93f7127458SIngo Weinhold }
94f7127458SIngo Weinhold
95f7127458SIngo Weinhold // we have locked the mutex for the first time
9665a76a0fSAugustin Cavalier assert(mutex->owner == -1);
97f7127458SIngo Weinhold mutex->owner = thisThread;
98f7127458SIngo Weinhold mutex->owner_count = 1;
99f7127458SIngo Weinhold
100f7127458SIngo Weinhold return 0;
101f7127458SIngo Weinhold }
102f7127458SIngo Weinhold
103f7127458SIngo Weinhold
104f7127458SIngo Weinhold int
pthread_mutex_lock(pthread_mutex_t * mutex)105f7127458SIngo Weinhold pthread_mutex_lock(pthread_mutex_t* mutex)
106f7127458SIngo Weinhold {
107e41d4bd1SJérôme Duval return __pthread_mutex_lock(mutex, 0, B_INFINITE_TIMEOUT);
108f7127458SIngo Weinhold }
109f7127458SIngo Weinhold
110f7127458SIngo Weinhold
111f7127458SIngo Weinhold int
pthread_mutex_trylock(pthread_mutex_t * mutex)112f7127458SIngo Weinhold pthread_mutex_trylock(pthread_mutex_t* mutex)
113f7127458SIngo Weinhold {
114e41d4bd1SJérôme Duval return __pthread_mutex_lock(mutex, B_ABSOLUTE_REAL_TIME_TIMEOUT, -1);
115f7127458SIngo Weinhold }
116f7127458SIngo Weinhold
117f7127458SIngo Weinhold
118f7127458SIngo Weinhold int
pthread_mutex_clocklock(pthread_mutex_t * mutex,clockid_t clock_id,const struct timespec * abstime)119e41d4bd1SJérôme Duval pthread_mutex_clocklock(pthread_mutex_t* mutex, clockid_t clock_id,
120e41d4bd1SJérôme Duval const struct timespec* abstime)
121f7127458SIngo Weinhold {
122f7127458SIngo Weinhold bigtime_t timeout = 0;
123b8fdef84SAugustin Cavalier bool invalidTime = false;
124b8fdef84SAugustin Cavalier if (abstime == NULL || !timespec_to_bigtime(*abstime, timeout))
125f7127458SIngo Weinhold invalidTime = true;
126f7127458SIngo Weinhold
127e41d4bd1SJérôme Duval uint32 flags = 0;
128e41d4bd1SJérôme Duval switch (clock_id) {
129e41d4bd1SJérôme Duval case CLOCK_REALTIME:
130e41d4bd1SJérôme Duval flags = B_ABSOLUTE_REAL_TIME_TIMEOUT;
131e41d4bd1SJérôme Duval break;
132e41d4bd1SJérôme Duval case CLOCK_MONOTONIC:
133e41d4bd1SJérôme Duval flags = B_ABSOLUTE_TIMEOUT;
134e41d4bd1SJérôme Duval break;
135e41d4bd1SJérôme Duval default:
136e41d4bd1SJérôme Duval invalidTime = true;
137e41d4bd1SJérôme Duval break;
138e41d4bd1SJérôme Duval }
139e41d4bd1SJérôme Duval
140e41d4bd1SJérôme Duval status_t status = __pthread_mutex_lock(mutex, flags, timeout);
141f7127458SIngo Weinhold
142*3a91fe8dSAugustin Cavalier if (status != B_OK && invalidTime)
143*3a91fe8dSAugustin Cavalier return EINVAL;
144f7127458SIngo Weinhold return status;
145f7127458SIngo Weinhold }
146f7127458SIngo Weinhold
147f7127458SIngo Weinhold
148f7127458SIngo Weinhold int
pthread_mutex_timedlock(pthread_mutex_t * mutex,const struct timespec * abstime)149e41d4bd1SJérôme Duval pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* abstime)
150e41d4bd1SJérôme Duval {
151e41d4bd1SJérôme Duval return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime);
152e41d4bd1SJérôme Duval }
153e41d4bd1SJérôme Duval
154e41d4bd1SJérôme Duval
155e41d4bd1SJérôme Duval int
pthread_mutex_unlock(pthread_mutex_t * mutex)156f7127458SIngo Weinhold pthread_mutex_unlock(pthread_mutex_t* mutex)
157f7127458SIngo Weinhold {
158f7127458SIngo Weinhold if (mutex->owner != find_thread(NULL))
159f7127458SIngo Weinhold return EPERM;
160f7127458SIngo Weinhold
161f7127458SIngo Weinhold if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE
162f7127458SIngo Weinhold && --mutex->owner_count > 0) {
163f7127458SIngo Weinhold // still locked
164f7127458SIngo Weinhold return 0;
165f7127458SIngo Weinhold }
166f7127458SIngo Weinhold
167f7127458SIngo Weinhold mutex->owner = -1;
168f7127458SIngo Weinhold
169f7127458SIngo Weinhold // clear the locked flag
170f7127458SIngo Weinhold int32 oldValue = atomic_and((int32*)&mutex->lock,
171f7127458SIngo Weinhold ~(int32)B_USER_MUTEX_LOCKED);
17293d7d1c5SAugustin Cavalier if ((oldValue & B_USER_MUTEX_WAITING) != 0) {
17393d7d1c5SAugustin Cavalier _kern_mutex_unblock((int32*)&mutex->lock,
17493d7d1c5SAugustin Cavalier (mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0);
17593d7d1c5SAugustin Cavalier }
176f7127458SIngo Weinhold
17765a76a0fSAugustin Cavalier if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK
17865a76a0fSAugustin Cavalier || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) {
17965a76a0fSAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) == 0)
18065a76a0fSAugustin Cavalier return EPERM;
18165a76a0fSAugustin Cavalier }
18265a76a0fSAugustin Cavalier
183f7127458SIngo Weinhold return 0;
184f7127458SIngo Weinhold }
185f7127458SIngo Weinhold
186f7127458SIngo Weinhold
187f7127458SIngo Weinhold int
pthread_mutex_getprioceiling(const pthread_mutex_t * mutex,int * _prioCeiling)1880bec83a8SJérôme Duval pthread_mutex_getprioceiling(const pthread_mutex_t* mutex, int* _prioCeiling)
189f7127458SIngo Weinhold {
190f7127458SIngo Weinhold if (mutex == NULL || _prioCeiling == NULL)
191f7127458SIngo Weinhold return EINVAL;
192f7127458SIngo Weinhold
193f7127458SIngo Weinhold *_prioCeiling = 0;
194f7127458SIngo Weinhold // not implemented
195f7127458SIngo Weinhold
196f7127458SIngo Weinhold return 0;
197f7127458SIngo Weinhold }
198f7127458SIngo Weinhold
199f7127458SIngo Weinhold
200f7127458SIngo Weinhold int
pthread_mutex_setprioceiling(pthread_mutex_t * mutex,int prioCeiling,int * _oldCeiling)201f7127458SIngo Weinhold pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling,
202f7127458SIngo Weinhold int* _oldCeiling)
203f7127458SIngo Weinhold {
204f7127458SIngo Weinhold if (mutex == NULL)
205f7127458SIngo Weinhold return EINVAL;
206f7127458SIngo Weinhold
207f7127458SIngo Weinhold // not implemented
208f7127458SIngo Weinhold return EPERM;
209f7127458SIngo Weinhold }
210