minor corrections by M.Taguchi
[reactos.git] / posix / lib / psxdll / pthread / mutex.c
1 /* $Id: mutex.c,v 1.4 2002/10/29 04:45:38 rex Exp $
2 */
3 /*
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS POSIX+ Subsystem
6 * FILE: subsys/psx/lib/psxdll/pthread/mutex.c
7 * PURPOSE: Mutex functions
8 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
9 * UPDATE HISTORY:
10 * 19/12/2001: Created
11 */
12
13 #include <ntos.h>
14 #include <ddk/ntddk.h>
15 #include <sys/types.h>
16 #include <pthread.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <psx/debug.h>
20 #include <psx/pthread.h>
21 #include <psx/errno.h>
22 #include <psx/safeobj.h>
23
24 int pthread_mutex_init(pthread_mutex_t *mutex,
25 const pthread_mutexattr_t *attr)
26 {
27 struct __mutex *pmMutex;
28 struct __mutexattr *pmaMutexAttrs;
29 BOOL bShared;
30 OBJECT_ATTRIBUTES oaMutexAttrs;
31 NTSTATUS nErrCode;
32
33 /* invalid return buffer */
34 if(mutex == NULL)
35 return (EINVAL);
36
37 /* object still open */
38 if(__safeobj_validate(*mutex, __PTHREAD_MUTEX_MAGIC))
39 return (EBUSY);
40
41 if(attr == NULL)
42 {
43 /* use default attributes */
44 /* create new mutex object */
45 pmMutex = (struct __mutex *)malloc(sizeof(struct __mutex));
46
47 /* malloc() failure */
48 if(!pmMutex)
49 return (ENOMEM);
50
51 /* set the attributes */
52 bShared = FALSE;
53 pmMutex->type = PTHREAD_MUTEX_RECURSIVE;
54 }
55 else if(__safeobj_validate(*attr, __PTHREAD_MUTEX_ATTR_MAGIC))
56 {
57 /* use provided attributes */
58 /* create new mutex object */
59 pmMutex = (struct __mutex *)malloc(sizeof(struct __mutex));
60
61 /* malloc() failure */
62 if(!pmMutex)
63 return (ENOMEM);
64
65 /* get the attributes object */
66 pmaMutexAttrs = (struct __mutexattr *) *attr;
67
68 /* set the attributes */
69 bShared = (pmaMutexAttrs->pshared != PTHREAD_PROCESS_PRIVATE);
70 pmMutex->type = pmaMutexAttrs->type;
71 }
72 else
73 return (EINVAL);
74
75 /* necessary for the mutex to be considered valid later */
76 pmMutex->signature = __PTHREAD_MUTEX_MAGIC;
77
78 /* creation of the native mutex object */
79 pmMutex->handle = 0;
80
81 /* initialize generic object attributes */
82 oaMutexAttrs.Length = sizeof(OBJECT_ATTRIBUTES);
83 oaMutexAttrs.RootDirectory = NULL;
84 oaMutexAttrs.ObjectName = NULL;
85 oaMutexAttrs.Attributes = 0;
86 oaMutexAttrs.SecurityDescriptor = NULL;
87 oaMutexAttrs.SecurityQualityOfService = NULL;
88
89 /* process-exclusive mutex */
90 if(bShared)
91 oaMutexAttrs.Attributes |= OBJ_EXCLUSIVE;
92
93 /* try to create the object */
94 nErrCode = NtCreateMutant
95 (
96 &pmMutex->handle,
97 MUTANT_ALL_ACCESS,
98 &oaMutexAttrs,
99 FALSE
100 );
101
102 /* failure */
103 if(!NT_SUCCESS(nErrCode))
104 {
105 /* free the internal mutex object */
106 free(pmMutex);
107 /* return errno */
108 return (__status_to_errno(nErrCode));
109 }
110
111 /* return the pointer to the mutex */
112 *mutex = (pthread_mutex_t)pmMutex;
113
114 /* success */
115 return (0);
116
117 }
118
119 int pthread_mutex_destroy(pthread_mutex_t *mutex)
120 {
121 struct __mutex *pmMutex;
122 NTSTATUS nErrCode;
123 MUTANT_BASIC_INFORMATION mbiMutexInfo;
124
125 /* invalid pointer or pointer to invalid object */
126 if(mutex == NULL || !__safeobj_validate(*mutex, __PTHREAD_MUTEX_MAGIC))
127 {
128 return (EINVAL);
129 }
130
131 pmMutex = (struct __mutex *)*mutex;
132
133 /* query the mutex's status */
134 nErrCode = NtQueryMutant
135 (
136 pmMutex->handle,
137 MutantBasicInformation,
138 &mbiMutexInfo,
139 sizeof(MUTANT_BASIC_INFORMATION),
140 NULL
141 );
142
143 /* failure */
144 if(!NT_SUCCESS(nErrCode))
145 {
146 return (__status_to_errno(nErrCode));
147 }
148
149 /* the thread is owned - cannot destroy it */
150 if(mbiMutexInfo.Count <= 0)
151 {
152 return (EBUSY);
153 }
154
155 /* try to close the handle */
156 nErrCode = NtClose(pmMutex->handle);
157
158 /* failure */
159 if(!NT_SUCCESS(nErrCode))
160 {
161 return (__status_to_errno(nErrCode));
162 }
163
164 /* free the object, nil the pointer */
165 free(*mutex);
166 *mutex = NULL;
167
168 /* success */
169 return (0);
170
171 }
172
173 int pthread_mutex_lock(pthread_mutex_t *mutex)
174 {
175 struct __mutex * pmMutex;
176 NTSTATUS nErrCode;
177
178 /* invalid pointer or pointer to invalid object */
179 if(mutex == NULL || !__safeobj_validate(*mutex, __PTHREAD_MUTEX_MAGIC))
180 return (EINVAL);
181
182 pmMutex = (struct __mutex *)*mutex;
183
184 /* decide the behavior from the mutex type */
185 switch(pmMutex->type)
186 {
187 case PTHREAD_MUTEX_NORMAL:
188 {
189 /* unconditionally try to lock the mutex */
190 /* FIXME? should we "artificially" hang the thread if it's the mutex owner, since
191 NT mutexes always behave recursively? */
192
193 #if 0
194 if(0 /* mutex owner */ == pthread_self() */)
195 NtDelayExecution(FALSE, NULL);
196 #endif
197
198 nErrCode = NtWaitForSingleObject(pmMutex->handle, FALSE, NULL);
199 break;
200 }
201
202 case PTHREAD_MUTEX_ERRORCHECK:
203 {
204 /* prevent a thread from recursively locking the same mutex */
205 if(0 /* mutex owner */ == pthread_self()) /* FIXME: implement the correct logic */
206 return (EDEADLK);
207 else
208 nErrCode = NtWaitForSingleObject(pmMutex->handle, FALSE, NULL);
209
210 break;
211 }
212
213 case PTHREAD_MUTEX_RECURSIVE:
214 {
215 /* allow recursive locking */
216 /* ASSERT: this is the default behavior for NT */
217 nErrCode = NtWaitForSingleObject(pmMutex->handle, FALSE, NULL);
218 break;
219 }
220
221 default:
222 /* we should never reach this point */
223 INFO("you should never read this");
224
225 }
226
227 if(nErrCode == STATUS_ABANDONED)
228 {
229 FIXME("mutex abandoned, not sure on what to do: should we try to lock the mutex again?");
230 }
231 else if(!NT_SUCCESS(nErrCode))
232 {
233 return (__status_to_errno(nErrCode));
234 }
235
236 /* success */
237 return (0);
238
239 }
240
241 int pthread_mutex_trylock(pthread_mutex_t *mutex)
242 {
243 struct __mutex * pmMutex;
244 NTSTATUS nErrCode;
245 MUTANT_BASIC_INFORMATION mbiMutexInfo;
246
247 /* invalid pointer or pointer to invalid object */
248 if(mutex == NULL || !__safeobj_validate(*mutex, __PTHREAD_MUTEX_MAGIC))
249 return (EINVAL);
250
251 pmMutex = (struct __mutex *)*mutex;
252
253 /* query the mutex's status */
254 nErrCode = NtQueryMutant
255 (
256 pmMutex->handle,
257 MutantBasicInformation,
258 &mbiMutexInfo,
259 sizeof(MUTANT_BASIC_INFORMATION),
260 NULL
261 );
262
263 /* failure */
264 if(!NT_SUCCESS(nErrCode))
265 {
266 return (__status_to_errno(nErrCode));
267 }
268
269 /* mutex already locked */
270 if(mbiMutexInfo.Count <= 0)
271 return (EBUSY);
272
273 /* mutex not locked - mutex type attribute doesn't matter */
274 nErrCode = NtWaitForSingleObject(pmMutex->handle, FALSE, NULL);
275
276 if(!NT_SUCCESS(nErrCode))
277 {
278 return (__status_to_errno(nErrCode));
279 }
280
281 /* success */
282 return (0);
283
284 }
285
286 int pthread_mutex_unlock(pthread_mutex_t *mutex)
287 {
288 struct __mutex * pmMutex;
289 NTSTATUS nErrCode;
290
291 /* invalid pointer or pointer to invalid object */
292 if(mutex == NULL || !__safeobj_validate(*mutex, __PTHREAD_MUTEX_MAGIC))
293 return (EINVAL);
294
295 pmMutex = (struct __mutex *)*mutex;
296
297 /* try to release the mutex */
298 nErrCode = NtReleaseMutant(pmMutex->handle, NULL);
299
300 /* failure */
301 if(!NT_SUCCESS(nErrCode))
302 {
303 return (__status_to_errno(nErrCode));
304 }
305
306 /* success */
307 return (0);
308
309 }
310
311 /* mutex attributes routines */
312
313 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
314 {
315 struct __mutexattr * pmaMutexAttrs;
316
317 /* invalid return pointer */
318 if(!attr)
319 return (EINVAL);
320
321 /* allocate internal structure for mutex attributes */
322 pmaMutexAttrs = (struct __mutexattr *)malloc(sizeof(struct __mutexattr));
323
324 /* failure */
325 if(pmaMutexAttrs == 0)
326 return (ENOMEM);
327
328 /* attribute defaults */
329 pmaMutexAttrs->pshared = PTHREAD_PROCESS_PRIVATE;
330 pmaMutexAttrs->type = PTHREAD_MUTEX_DEFAULT;
331
332 /* return the pointer to the attributes object */
333 *attr = (pthread_mutexattr_t)pmaMutexAttrs;
334
335 /* success */
336 return (0);
337
338 }
339
340 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
341 {
342 /* invalid pointer or pointer to invalid object */
343 if(attr == NULL || !__safeobj_validate(*attr, __PTHREAD_MUTEX_ATTR_MAGIC))
344 return (EINVAL);
345
346 /* deallocate internal structure */
347 free(*attr);
348
349 /* success */
350 return (0);
351
352 }
353
354 #define PTHREAD_MUTEXATTR_GET(PATTR,PVAR,FIELD) \
355 if( \
356 (PATTR) == NULL || \
357 (PVAR) == NULL || \
358 !__safeobj_validate(*(PATTR), __PTHREAD_MUTEX_ATTR_MAGIC) \
359 ) \
360 return (EINVAL); \
361 else \
362 { \
363 (*(PVAR)) = ((struct __mutexattr *)*(PATTR))->FIELD; \
364 return (0); \
365 }
366
367 int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
368 int *pshared)
369 {
370 PTHREAD_MUTEXATTR_GET(attr, pshared, pshared)
371 }
372
373 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
374 {
375 PTHREAD_MUTEXATTR_GET(attr, type, type)
376 }
377
378 int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
379 int pshared)
380 {
381 /* invalid pointer or pointer to invalid object */
382 if(attr == NULL || !__safeobj_validate(*attr, __PTHREAD_MUTEX_ATTR_MAGIC))
383 return (EINVAL);
384
385 /* validate value */
386 switch(pshared)
387 {
388 case PTHREAD_PROCESS_SHARED: break;
389 case PTHREAD_PROCESS_PRIVATE: break;
390 default: return (EINVAL);
391 }
392
393 ((struct __mutexattr *)*attr)->pshared = pshared;
394
395 return (0);
396
397 }
398
399 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
400 {
401 /* invalid pointer or pointer to invalid object */
402 if(attr == NULL || !__safeobj_validate(*attr, __PTHREAD_MUTEX_ATTR_MAGIC))
403 return (EINVAL);
404
405 /* validate value */
406 switch(type)
407 {
408 case PTHREAD_MUTEX_NORMAL: break;
409 case PTHREAD_MUTEX_ERRORCHECK: break;
410 case PTHREAD_MUTEX_RECURSIVE: break;
411 default: return (EINVAL);
412 }
413
414 ((struct __mutexattr *)*attr)->type = type;
415
416 return (0);
417
418 }
419
420 /* STUBS */
421
422 int pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
423 int prioceiling, int *old_ceiling)
424 {
425 TODO("realtime threads not currently implemented");
426 return (ENOSYS);
427 }
428
429 int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
430 int *prioceiling)
431 {
432 TODO("realtime threads not currently implemented");
433 return (ENOSYS);
434 }
435
436 int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
437 int *protocol)
438 {
439 TODO("realtime threads not currently implemented");
440 return (ENOSYS);
441 }
442
443 int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
444 int protocol)
445 {
446 TODO("realtime threads not currently implemented");
447 return (ENOSYS);
448 }
449
450 int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
451 int prioceiling)
452 {
453 TODO("realtime threads not currently implemented");
454 return (ENOSYS);
455 }
456
457 int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
458 int *prioceiling)
459 {
460 TODO("realtime threads not currently implemented");
461 return (ENOSYS);
462 }
463
464 /* EOF */
465