1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - OS -
3 File: os_mutex.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-11-12#$
14 $Rev: 9293 $
15 $Author: yada $
16 *---------------------------------------------------------------------------*/
17
18 #include <nitro/types.h>
19 #include <nitro.h>
20
21 void OSi_UnlockMutexCore(OSMutex *mutex, u32 type);
22
23 void OSi_EnqueueTail(OSThread *thread, OSMutex *mutex);
24 void OSi_DequeueItem(OSThread *thread, OSMutex *mutex);
25 OSMutex *OSi_DequeueHead(OSThread *thread);
26
27 /*---------------------------------------------------------------------------*
28 Name: OS_InitMutex
29
30 Description: initialize mutex
31
32 Arguments: mutex pointer to mutex structure
33 to be initialized
34
35 Returns: None
36 *---------------------------------------------------------------------------*/
OS_InitMutex(OSMutex * mutex)37 void OS_InitMutex(OSMutex *mutex)
38 {
39 SDK_ASSERT(mutex);
40
41 OS_InitThreadQueue(&mutex->queue);
42 mutex->thread = NULL;
43 OS_SetMutexCount( mutex, 0 );
44 OS_SetMutexType( mutex, OS_MUTEX_TYPE_NONE );
45 }
46
47 /*---------------------------------------------------------------------------*
48 Name: OS_LockMutex
49
50 Description: lock mutex
51
52 Arguments: mutex pointer to mutex structure
53
54 Returns: None
55 *---------------------------------------------------------------------------*/
OS_LockMutex(OSMutex * mutex)56 void OS_LockMutex(OSMutex *mutex)
57 {
58 OSIntrMode e = OS_DisableInterrupts();
59 OSThread *currentThread = OS_GetCurrentThread();
60
61 while(1)
62 {
63 //---- try lock mutex
64 if ( OS_TryLockMutex(mutex) )
65 {
66 break;
67 }
68
69 currentThread->mutex = mutex;
70 OS_SleepThread(&mutex->queue);
71 currentThread->mutex = NULL;
72 }
73
74 (void)OS_RestoreInterrupts(e);
75 }
76
77 /*---------------------------------------------------------------------------*
78 Name: OS_UnlockMutex
79
80 Description: unlock mutex
81
82 Arguments: mutex pointer to mutex structure
83
84 Returns: None
85 *---------------------------------------------------------------------------*/
OS_UnlockMutex(OSMutex * mutex)86 void OS_UnlockMutex(OSMutex *mutex)
87 {
88 OSi_UnlockMutexCore(mutex, OS_MUTEX_TYPE_STD);
89 }
90
91 /*---------------------------------------------------------------------------*
92 Name: OSi_UnlockAllMutex
93
94 Description: unlocks all the mutexes locked by the thread
95
96 Arguments: mutex pointer to mutex structure
97
98 Returns: None.
99 *---------------------------------------------------------------------------*/
OSi_UnlockAllMutex(OSThread * thread)100 void OSi_UnlockAllMutex(OSThread *thread)
101 {
102 OSMutex *mutex;
103
104 SDK_ASSERT(thread);
105
106 #ifndef SDK_THREAD_INFINITY
107 while (thread->mutexQueueHead)
108 {
109 mutex = OSi_DequeueHead(thread);
110 SDK_ASSERT(mutex->thread == thread);
111
112 OS_SetMutexCount( mutex, 0 );
113 mutex->thread = NULL;
114 OS_SetMutexType( mutex, OS_MUTEX_TYPE_NONE );
115 OS_WakeupThread(&(mutex->queue));
116 }
117 #else
118 while (thread->mutexQueue.head)
119 {
120 mutex = OSi_RemoveMutexLinkFromQueue(&thread->mutexQueue);
121 SDK_ASSERT(mutex->thread == thread);
122
123 OS_SetMutexCount( mutex, 0 );
124 mutex->thread = NULL;
125 OS_SetMutexType( mutex, OS_MUTEX_TYPE_NONE );
126 OS_WakeupThread(&mutex->queue);
127 }
128 #endif
129 }
130
131 /*---------------------------------------------------------------------------*
132 Name: OS_TryLockMutex
133
134 Description: try to lock mutex
135
136 Arguments: mutex pointer to mutex structure
137
138 Returns: True if lock
139 *---------------------------------------------------------------------------*/
OS_TryLockMutex(OSMutex * mutex)140 BOOL OS_TryLockMutex(OSMutex *mutex)
141 {
142 OSIntrMode saved = OS_DisableInterrupts();
143 OSThread *currentThread = OS_GetCurrentThread();
144 BOOL locked;
145
146 SDK_ASSERT(mutex);
147
148 // ---- able to lock mutex
149 if (mutex->thread == NULL)
150 {
151 mutex->thread = currentThread;
152 OS_SetMutexType( mutex, OS_MUTEX_TYPE_STD );
153 OS_IncreaseMutexCount(mutex);
154 OSi_EnqueueTail(currentThread, mutex);
155 locked = TRUE;
156 }
157 // ---- current thread is same with thread locking mutex
158 else if (mutex->thread == currentThread)
159 {
160 OS_IncreaseMutexCount(mutex);
161 locked = TRUE;
162 }
163 // ---- current thread is different from locking mutex
164 else
165 {
166 locked = FALSE;
167 }
168
169 (void)OS_RestoreInterrupts(saved);
170 return locked;
171 }
172
173 //================================================================================
174 // Read / Write Lock
175 //================================================================================
176 /*---------------------------------------------------------------------------*
177 Name: OS_LockMutexR
178
179 Description: lock RW mutex as READ access
180
181 Arguments: mutex pointer to RW mutex structure
182
183 Returns: None
184 *---------------------------------------------------------------------------*/
OS_LockMutexR(OSMutex * mutex)185 void OS_LockMutexR(OSMutex *mutex)
186 {
187 OSIntrMode e = OS_DisableInterrupts();
188 OSThread *currentThread = OS_GetCurrentThread();
189
190 while(1)
191 {
192 //---- try lock by READ
193 if ( OS_TryLockMutexR(mutex) )
194 {
195 break;
196 }
197
198 currentThread->mutex = mutex;
199 OS_SleepThread(&mutex->queue);
200 currentThread->mutex = NULL;
201 }
202
203 (void)OS_RestoreInterrupts(e);
204 }
205
206 /*---------------------------------------------------------------------------*
207 Name: OS_LockMutexW
208
209 Description: lock RW mutex as WRITE access
210
211 Arguments: mutex pointer to RW mutex structure
212
213 Returns: None
214 *---------------------------------------------------------------------------*/
OS_LockMutexW(OSMutex * mutex)215 void OS_LockMutexW(OSMutex *mutex)
216 {
217 OSIntrMode e = OS_DisableInterrupts();
218 OSThread *currentThread = OS_GetCurrentThread();
219
220 while(1)
221 {
222 //---- try lock by WRITE
223 if ( OS_TryLockMutexW(mutex) )
224 {
225 break;
226 }
227
228 currentThread->mutex = mutex;
229 OS_SleepThread(&mutex->queue);
230 currentThread->mutex = NULL;
231 }
232
233 (void)OS_RestoreInterrupts(e);
234 }
235
236 /*---------------------------------------------------------------------------*
237 Name: OS_TryLockMutexR
238
239 Description: try to lock RW mutex as READ access
240
241 Arguments: mutex pointer to RW mutex structure
242
243 Returns: TRUE if locked
244 *---------------------------------------------------------------------------*/
OS_TryLockMutexR(OSMutex * mutex)245 BOOL OS_TryLockMutexR(OSMutex *mutex)
246 {
247 OSIntrMode e = OS_DisableInterrupts();
248 BOOL locked = FALSE;
249 OSThread * currentThread = OS_GetCurrentThread();
250
251 switch( OS_GetMutexType(mutex) )
252 {
253 case OS_MUTEX_TYPE_NONE:
254 mutex->thread = currentThread;
255 OS_SetMutexType( mutex, OS_MUTEX_TYPE_R );
256 OS_SetMutexCount( mutex, 1 );
257 OSi_EnqueueTail(currentThread, mutex);
258 locked = TRUE;
259 break;
260
261 case OS_MUTEX_TYPE_R:
262 OS_IncreaseMutexCount(mutex);
263 locked = TRUE;
264 break;
265
266 case OS_MUTEX_TYPE_W:
267 default:
268 break;
269 }
270
271 (void)OS_RestoreInterrupts(e);
272 return locked;
273 }
274
275 /*---------------------------------------------------------------------------*
276 Name: OS_TryLockMutexW
277
278 Description: try to lock RW mutex as WRITE access
279
280 Arguments: mutex pointer to RW mutex structure
281
282 Returns: TRUE if locked
283 *---------------------------------------------------------------------------*/
OS_TryLockMutexW(OSMutex * mutex)284 BOOL OS_TryLockMutexW(OSMutex *mutex)
285 {
286 OSIntrMode e = OS_DisableInterrupts();
287 BOOL locked = FALSE;
288 OSThread * currentThread = OS_GetCurrentThread();
289
290 switch( OS_GetMutexType(mutex) )
291 {
292 case OS_MUTEX_TYPE_NONE:
293 mutex->thread = currentThread;
294 OS_SetMutexType( mutex, OS_MUTEX_TYPE_W );
295 OS_SetMutexCount( mutex, 1 );
296 OSi_EnqueueTail(currentThread, mutex);
297 locked = TRUE;
298 break;
299
300 case OS_MUTEX_TYPE_W:
301 if ( mutex->thread == currentThread )
302 {
303 OS_IncreaseMutexCount(mutex);
304 locked = TRUE;
305 }
306 break;
307
308 case OS_MUTEX_TYPE_R:
309 default:
310 break;
311 }
312
313 (void)OS_RestoreInterrupts(e);
314 return locked;
315 }
316
317 /*---------------------------------------------------------------------------*
318 Name: OSi_UnlockMutexCore
319
320 Description: core routine to unlock mutex
321
322 Arguments: mutex pointer to RW mutex structure
323 type mutex type. if different from OS_GetMutexType(), error.
324 OS_MUTEX_TYPE_STD
325 OS_MUTEX_TYPE_R
326 OS_MUTEX_TYPE_W
327 OS_MUTEX_TYPE_NONE (no check)
328
329 Returns: None
330 *---------------------------------------------------------------------------*/
OSi_UnlockMutexCore(OSMutex * mutex,u32 type)331 void OSi_UnlockMutexCore(OSMutex *mutex, u32 type )
332 {
333 OSIntrMode e = OS_DisableInterrupts();
334 OSThread *currentThread = OS_GetCurrentThread();
335 BOOL unlocked = FALSE;
336
337 SDK_ASSERT(mutex);
338
339 //---- check unlock type
340 if ( type != OS_MUTEX_TYPE_NONE && type != OS_GetMutexType(mutex) )
341 {
342 //OS_TPanic("Illegal unlock mutex\n");
343 OS_TWarning("Illegal unlock mutex");
344 (void)OS_RestoreInterrupts(e);
345 return;
346 }
347
348 switch( OS_GetMutexType(mutex) )
349 {
350 case OS_MUTEX_TYPE_STD:
351 case OS_MUTEX_TYPE_W:
352 if ( mutex->thread == currentThread )
353 {
354 OS_DecreaseMutexCount(mutex);
355 if ( OS_GetMutexCount(mutex) == 0 )
356 {
357 unlocked = TRUE;
358 }
359 }
360 break;
361
362 case OS_MUTEX_TYPE_R:
363 OS_DecreaseMutexCount(mutex);
364 if ( OS_GetMutexCount(mutex) == 0 )
365 {
366 unlocked = TRUE;
367 }
368 break;
369
370 default:
371 OS_TWarning("Illegal unlock mutex");
372 (void)OS_RestoreInterrupts(e);
373 return;
374 //OS_TPanic("Illegal unlock mutex\n");
375 //break;
376 }
377
378 //---- unlock mutex
379 if ( unlocked )
380 {
381 OSi_DequeueItem(currentThread, mutex);
382 mutex->thread = NULL;
383 OS_SetMutexType( mutex, OS_MUTEX_TYPE_NONE );
384 OS_WakeupThread(&mutex->queue);
385 }
386
387 (void)OS_RestoreInterrupts(e);
388 }
389
390 /*---------------------------------------------------------------------------*
391 Name: OS_UnlockMutexR
392
393 Description: unlock mutex locked as READ access
394
395 Arguments: mutex pointer to mutex structure
396
397 Returns: None
398 *---------------------------------------------------------------------------*/
OS_UnlockMutexR(OSMutex * mutex)399 void OS_UnlockMutexR(OSMutex *mutex)
400 {
401 OSi_UnlockMutexCore( mutex, OS_MUTEX_TYPE_R );
402 }
403
404 /*---------------------------------------------------------------------------*
405 Name: OS_UnlockMutexW
406
407 Description: unlock mutex locked as WRITE access
408
409 Arguments: mutex pointer to mutex structure
410
411 Returns: None
412 *---------------------------------------------------------------------------*/
OS_UnlockMutexW(OSMutex * mutex)413 void OS_UnlockMutexW(OSMutex *mutex)
414 {
415 OSi_UnlockMutexCore( mutex, OS_MUTEX_TYPE_W );
416 }
417
418 /*---------------------------------------------------------------------------*
419 Name: OS_UnlockMutexRW
420
421 Description: unlock mutex locked as READ/WRITE access
422
423 Arguments: mutex pointer to mutex structure
424
425 Returns: None
426 *---------------------------------------------------------------------------*/
OS_UnlockMutexRW(OSMutex * mutex)427 void OS_UnlockMutexRW(OSMutex *mutex)
428 {
429 OSi_UnlockMutexCore( mutex, OS_MUTEX_TYPE_NONE );
430 }
431
432 /*---------------------------------------------------------------------------*
433 Name: OS_LockMutexFromRToW
434
435 Description: Promote mutexR lock to mutexW lock without unlock.
436 Wait till success.
437
438 Arguments: mutex pointer to mutex structure
439
440 Returns: None
441 *---------------------------------------------------------------------------*/
OS_LockMutexFromRToW(OSMutex * mutex)442 void OS_LockMutexFromRToW(OSMutex *mutex)
443 {
444 OSIntrMode e = OS_DisableInterrupts();
445 OSThread *currentThread = OS_GetCurrentThread();
446
447 while(1)
448 {
449 if ( OS_TryLockMutexFromRToW(mutex) )
450 {
451 break;
452 }
453
454 currentThread->mutex = mutex;
455 OS_SleepThread(&mutex->queue);
456 currentThread->mutex = NULL;
457 }
458
459 (void)OS_RestoreInterrupts(e);
460 }
461
462 /*---------------------------------------------------------------------------*
463 Name: OS_TryLockMutexFromRToW
464
465 Description: Try to promote mutexR lock to mutexW lock without unlock.
466
467 Arguments: mutex pointer to mutex structure
468
469 Returns: TRUE if success
470 *---------------------------------------------------------------------------*/
OS_TryLockMutexFromRToW(OSMutex * mutex)471 BOOL OS_TryLockMutexFromRToW(OSMutex *mutex)
472 {
473 OSIntrMode e = OS_DisableInterrupts();
474 BOOL locked = FALSE;
475
476 //---- change mutex type if no other thread is locked. and mutex is R
477 if ( OS_GetMutexCount(mutex) == 1 && mutex->queue.head == NULL && OS_GetMutexType(mutex) == OS_MUTEX_TYPE_R )
478 {
479 OS_SetMutexType( mutex, OS_MUTEX_TYPE_W );
480 locked = TRUE;
481 }
482
483 (void)OS_RestoreInterrupts(e);
484 return locked;
485 }
486
487 /*---------------------------------------------------------------------------*
488 Name: OS_LockMutexFromWToR
489
490 Description: Demote mutexW lock to mutexR lock without unlock.
491 Wait till success.
492
493 Arguments: mutex pointer to mutex structure
494
495 Returns: None
496 *---------------------------------------------------------------------------*/
OS_LockMutexFromWToR(OSMutex * mutex)497 void OS_LockMutexFromWToR(OSMutex *mutex)
498 {
499 OSIntrMode e = OS_DisableInterrupts();
500 OSThread *currentThread = OS_GetCurrentThread();
501
502 while(1)
503 {
504 if ( OS_TryLockMutexFromWToR(mutex) )
505 {
506 break;
507 }
508
509 currentThread->mutex = mutex;
510 OS_SleepThread(&mutex->queue);
511 currentThread->mutex = NULL;
512 }
513
514 (void)OS_RestoreInterrupts(e);
515 }
516
517 /*---------------------------------------------------------------------------*
518 Name: OS_TryLockMutexFromWToR
519
520 Description: Try to demote mutexW lock to mutexR lock without unlock.
521
522 Arguments: mutex pointer to mutex structure
523
524 Returns: TRUE if success
525 *---------------------------------------------------------------------------*/
OS_TryLockMutexFromWToR(OSMutex * mutex)526 BOOL OS_TryLockMutexFromWToR(OSMutex *mutex)
527 {
528 OSIntrMode e = OS_DisableInterrupts();
529 BOOL locked = FALSE;
530
531 //---- change mutex type if no other thread is locked. and mutex is W
532 if ( OS_GetMutexCount(mutex) == 1 && mutex->queue.head == NULL && OS_GetMutexType(mutex) == OS_MUTEX_TYPE_W )
533 {
534 OS_SetMutexType( mutex, OS_MUTEX_TYPE_R );
535 locked = TRUE;
536 }
537
538 (void)OS_RestoreInterrupts(e);
539 return locked;
540 }
541
542
543 //===========================================================================
544 // MUTEX QUEUE
545 //===========================================================================
546 /*---------------------------------------------------------------------------*
547 Name: OSi_EnqueueTail
548
549 Description: internal function.
550 add mutex to thread's mutex list
551
552 Arguments: thread pointer to thread
553 mutex pointer to mutex to be add
554
555 Returns: None.
556 *---------------------------------------------------------------------------*/
OSi_EnqueueTail(OSThread * thread,OSMutex * mutex)557 void OSi_EnqueueTail(OSThread *thread, OSMutex *mutex)
558 {
559 #ifndef SDK_THREAD_INFINITY
560 OSMutex *prev = thread->mutexQueueTail;
561
562 SDK_ASSERT(thread && mutex);
563
564 if (!prev)
565 {
566 thread->mutexQueueHead = mutex;
567 }
568 else
569 {
570 prev->next = mutex;
571 }
572
573 mutex->prev = prev;
574 mutex->next = NULL;
575 thread->mutexQueueTail = mutex;
576 #else
577 OSMutex *prev = thread->mutexQueue.tail;
578
579 SDK_ASSERT(thread && mutex);
580
581 if (!prev)
582 {
583 thread->mutexQueue.head = mutex;
584 }
585 else
586 {
587 prev->link.next = mutex;
588 }
589
590 mutex->link.prev = prev;
591 mutex->link.next = NULL;
592 thread->mutexQueue.tail = mutex;
593 #endif
594 }
595
596 /*---------------------------------------------------------------------------*
597 Name: OSi_DequeueItem
598
599 Description: internal function.
600 remove specified mutex from thread's mutex list
601
602 Arguments: thread pointer to thread
603 mutex pointer to mutex to be remove
604
605 Returns: None.
606 *---------------------------------------------------------------------------*/
OSi_DequeueItem(OSThread * thread,OSMutex * mutex)607 void OSi_DequeueItem(OSThread *thread, OSMutex *mutex)
608 {
609 #ifndef SDK_THREAD_INFINITY
610 OSMutex *next = mutex->next;
611 OSMutex *prev = mutex->prev;
612
613 SDK_ASSERT(thread && mutex);
614
615 if (!next)
616 {
617 thread->mutexQueueTail = prev;
618 }
619 else
620 {
621 next->prev = prev;
622 }
623
624 if (!prev)
625 {
626 thread->mutexQueueHead = next;
627 }
628 else
629 {
630 prev->next = next;
631 }
632 #else
633 OSMutex *next = mutex->link.next;
634 OSMutex *prev = mutex->link.prev;
635
636 SDK_ASSERT(thread && mutex);
637
638 if (!next)
639 {
640 thread->mutexQueue.tail = prev;
641 }
642 else
643 {
644 next->link.prev = prev;
645 }
646
647 if (!prev)
648 {
649 thread->mutexQueue.head = next;
650 }
651 else
652 {
653 prev->link.next = next;
654 }
655 #endif
656 }
657
658 /*---------------------------------------------------------------------------*
659 Name: OSi_DequeueHead
660
661 Description: remove top mutex from thread's list, and return mutex
662
663 Arguments: thread pointer to thread
664
665 Returns: mutex which listed at top of thread
666 *---------------------------------------------------------------------------*/
OSi_DequeueHead(OSThread * thread)667 OSMutex *OSi_DequeueHead(OSThread *thread)
668 {
669 #ifndef SDK_THREAD_INFINITY
670 OSMutex *mutex = thread->mutexQueueHead;
671 OSMutex *next = mutex->next;
672
673 SDK_ASSERT(thread);
674
675 if (!next)
676 {
677 thread->mutexQueueTail = NULL;
678 }
679 else
680 {
681 next->prev = NULL;
682 }
683
684 thread->mutexQueueHead = next;
685 #else
686 OSMutex *mutex = thread->mutexQueue.head;
687 OSMutex *next = mutex->link.next;
688
689 SDK_ASSERT(thread);
690
691 if (!next)
692 {
693 thread->mutexQueue.tail = NULL;
694 }
695 else
696 {
697 next->link.prev = NULL;
698 }
699
700 thread->mutexQueue.head = next;
701 #endif
702
703 return mutex;
704 }
705