1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16:
17: 18: 19: 20:
21:
22: #include "kernel.h"
23: #include "task.h"
24: #include "wait.h"
25: #include "check.h"
26: #include <sys/rominfo.h>
27:
28: #ifdef NUM_MTXID
29:
30: EXPORT ID max_mtxid;
31:
32: #ifndef __mtxcb__
33: #define __mtxcb__
34: typedef struct mutex_control_block MTXCB;
35: #endif
36:
37: 38: 39:
40: struct mutex_control_block {
41: QUEUE wait_queue;
42: ID mtxid;
43: void *exinf;
44: ATR mtxatr;
45: UB ceilpri;
46: TCB *mtxtsk;
47: MTXCB *mtxlist;
48: #if USE_OBJECT_NAME
49: UB name[OBJECT_NAME_LENGTH];
50: #endif
51: };
52:
53: LOCAL MTXCB *mtxcb_table;
54: LOCAL QUEUE free_mtxcb;
55:
56: #define get_mtxcb(id) ( &mtxcb_table[INDEX_MTX(id)] )
57:
58:
59: 60: 61:
62: EXPORT ER mutex_initialize(void)
63: {
64: MTXCB *mtxcb, *end;
65: W n;
66:
67:
68: n = _tk_get_cfn(SCTAG_TMAXMTXID, &max_mtxid, 1);
69: if ( n < 1 || NUM_MTXID < 1 ) {
70: return E_SYS;
71: }
72:
73:
74: mtxcb_table = Imalloc((UINT)NUM_MTXID * sizeof(MTXCB));
75: if ( mtxcb_table == NULL ) {
76: return E_NOMEM;
77: }
78:
79:
80: QueInit(&free_mtxcb);
81: end = mtxcb_table + NUM_MTXID;
82: for( mtxcb = mtxcb_table; mtxcb < end; mtxcb++ ) {
83: mtxcb->mtxid = 0;
84: QueInsert(&mtxcb->wait_queue, &free_mtxcb);
85: }
86:
87: return E_OK;
88: }
89:
90:
91: 92: 93:
94: #define mtx_waited(mtxcb) ( !isQueEmpty(&(mtxcb)->wait_queue) )
95:
96: 97: 98:
99: #define mtx_head_pri(mtxcb) ( ((TCB*)(mtxcb)->wait_queue.next)->priority )
100:
101: 102: 103: 104: 105: 106: 107:
108: LOCAL void release_mutex( TCB *tcb, MTXCB *relmtxcb )
109: {
110: MTXCB *mtxcb, **prev;
111: INT newpri, pri;
112:
113:
114: newpri = tcb->bpriority;
115:
116:
117: pri = newpri;
118: prev = &tcb->mtxlist;
119: while ( (mtxcb = *prev) != NULL ) {
120: if ( mtxcb == relmtxcb ) {
121:
122: *prev = mtxcb->mtxlist;
123: continue;
124: }
125:
126: switch ( mtxcb->mtxatr & TA_CEILING ) {
127: case TA_CEILING:
128: pri = mtxcb->ceilpri;
129: break;
130: case TA_INHERIT:
131: if ( mtx_waited(mtxcb) ) {
132: pri = mtx_head_pri(mtxcb);
133: }
134: break;
135: default:
136:
137: break;
138: }
139: if ( newpri > pri ) {
140: newpri = pri;
141: }
142:
143: prev = &mtxcb->mtxlist;
144: }
145:
146: if ( newpri != tcb->priority ) {
147:
148: change_task_priority(tcb, newpri);
149: }
150: }
151:
152: 153: 154:
155: #define reset_priority(tcb) release_mutex((tcb), NULL)
156:
157: 158: 159: 160: 161: 162:
163: EXPORT void signal_all_mutex( TCB *tcb )
164: {
165: MTXCB *mtxcb, *next_mtxcb;
166: TCB *next_tcb;
167:
168: next_mtxcb = tcb->mtxlist;
169: while ( (mtxcb = next_mtxcb) != NULL ) {
170: next_mtxcb = mtxcb->mtxlist;
171:
172: if ( mtx_waited(mtxcb) ) {
173: next_tcb = (TCB*)mtxcb->wait_queue.next;
174:
175:
176: wait_release_ok(next_tcb);
177:
178:
179: mtxcb->mtxtsk = next_tcb;
180: mtxcb->mtxlist = next_tcb->mtxlist;
181: next_tcb->mtxlist = mtxcb;
182:
183: if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {
184: if ( next_tcb->priority > mtxcb->ceilpri ) {
185: 186: 187:
188: change_task_priority(next_tcb,
189: mtxcb->ceilpri);
190: }
191: }
192: } else {
193:
194: mtxcb->mtxtsk = NULL;
195: }
196: }
197: }
198:
199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209:
210: EXPORT INT chg_pri_mutex( TCB *tcb, INT priority )
211: {
212: MTXCB *mtxcb;
213: INT hi_pri, low_pri, pri;
214:
215: hi_pri = priority;
216: low_pri = int_priority(MIN_PRI);
217:
218:
219: if ( (tcb->state & TS_WAIT) != 0 && (tcb->wspec->tskwait & TTW_MTX) != 0 ) {
220: mtxcb = get_mtxcb(tcb->wid);
221: if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {
222: pri = mtxcb->ceilpri;
223: if ( pri > low_pri ) {
224: low_pri = pri;
225: }
226: }
227: }
228:
229:
230: pri = hi_pri;
231: for ( mtxcb = tcb->mtxlist; mtxcb != NULL; mtxcb = mtxcb->mtxlist ) {
232: switch ( mtxcb->mtxatr & TA_CEILING ) {
233: case TA_CEILING:
234: pri = mtxcb->ceilpri;
235: if ( pri > low_pri ) {
236: low_pri = pri;
237: }
238: break;
239: case TA_INHERIT:
240: if ( mtx_waited(mtxcb) ) {
241: pri = mtx_head_pri(mtxcb);
242: }
243: break;
244: default:
245:
246: break;
247: }
248: if ( pri < hi_pri ) {
249: hi_pri = pri;
250: }
251: }
252:
253: if ( priority < low_pri ) {
254: return E_ILUSE;
255: }
256: return hi_pri;
257: }
258:
259:
260: 261: 262:
263: LOCAL void mtx_chg_pri( TCB *tcb, INT oldpri )
264: {
265: MTXCB *mtxcb;
266: TCB *mtxtsk;
267:
268: mtxcb = get_mtxcb(tcb->wid);
269: gcb_change_priority((GCB*)mtxcb, tcb);
270:
271: if ( (mtxcb->mtxatr & TA_CEILING) == TA_INHERIT ) {
272: mtxtsk = mtxcb->mtxtsk;
273: if ( mtxtsk->priority > tcb->priority ) {
274: 275: 276:
277: change_task_priority(mtxtsk, tcb->priority);
278:
279: } else if ( mtxtsk->priority == oldpri ) {
280: 281:
282: reset_priority(mtxtsk);
283: }
284: }
285: }
286:
287: 288: 289:
290: LOCAL void mtx_rel_wai( TCB *tcb )
291: {
292: MTXCB *mtxcb;
293: TCB *mtxtsk;
294:
295: mtxcb = get_mtxcb(tcb->wid);
296: mtxtsk = mtxcb->mtxtsk;
297:
298: if ( mtxtsk->priority == tcb->priority ) {
299: 300:
301: reset_priority(mtxtsk);
302: }
303: }
304:
305: 306: 307:
308: LOCAL CONST WSPEC wspec_mtx_tfifo = { TTW_MTX, NULL, NULL };
309: LOCAL CONST WSPEC wspec_mtx_tpri = { TTW_MTX, mtx_chg_pri, NULL };
310: LOCAL CONST WSPEC wspec_mtx_inherit = { TTW_MTX, mtx_chg_pri, mtx_rel_wai };
311:
312:
313: 314: 315:
316: SYSCALL ID _tk_cre_mtx( CONST T_CMTX *pk_cmtx )
317: {
318: #if CHK_RSATR
319: const ATR VALID_MTXATR = {
320: TA_CEILING
321: |TA_NODISWAI
322: #if USE_OBJECT_NAME
323: |TA_DSNAME
324: #endif
325: };
326: #endif
327: MTXCB *mtxcb;
328: ID mtxid;
329: INT ceilpri;
330: ER ercd;
331:
332: CHECK_RSATR(pk_cmtx->mtxatr, VALID_MTXATR);
333:
334: if ( (pk_cmtx->mtxatr & TA_CEILING) == TA_CEILING ) {
335: CHECK_PRI(pk_cmtx->ceilpri);
336: ceilpri = int_priority(pk_cmtx->ceilpri);
337: } else {
338: ceilpri = 0;
339: }
340:
341: BEGIN_CRITICAL_SECTION;
342:
343: mtxcb = (MTXCB*)QueRemoveNext(&free_mtxcb);
344: if ( mtxcb == NULL ) {
345: ercd = E_LIMIT;
346: } else {
347: mtxid = ID_MTX(mtxcb - mtxcb_table);
348:
349:
350: QueInit(&mtxcb->wait_queue);
351: mtxcb->mtxid = mtxid;
352: mtxcb->exinf = pk_cmtx->exinf;
353: mtxcb->mtxatr = pk_cmtx->mtxatr;
354: mtxcb->ceilpri = ceilpri;
355: mtxcb->mtxtsk = NULL;
356: mtxcb->mtxlist = NULL;
357: #if USE_OBJECT_NAME
358: if ( (pk_cmtx->mtxatr & TA_DSNAME) != 0 ) {
359: STRNCPY((char*)mtxcb->name, (char*)pk_cmtx->dsname,
360: (UINT)OBJECT_NAME_LENGTH);
361: }
362: #endif
363: ercd = mtxid;
364: }
365: END_CRITICAL_SECTION;
366:
367: return ercd;
368: }
369:
370: 371: 372:
373: SYSCALL ER _tk_del_mtx( ID mtxid )
374: {
375: MTXCB *mtxcb;
376: ER ercd = E_OK;
377:
378: CHECK_MTXID(mtxid);
379:
380: mtxcb = get_mtxcb(mtxid);
381:
382: BEGIN_CRITICAL_SECTION;
383: if ( mtxcb->mtxid == 0 ) {
384: ercd = E_NOEXS;
385: } else {
386: 387: 388: 389:
390: if ( mtxcb->mtxtsk != NULL ) {
391: release_mutex(mtxcb->mtxtsk, mtxcb);
392: }
393:
394:
395: wait_delete(&mtxcb->wait_queue);
396:
397:
398: QueInsert(&mtxcb->wait_queue, &free_mtxcb);
399: mtxcb->mtxid = 0;
400: }
401: END_CRITICAL_SECTION;
402:
403: return ercd;
404: }
405:
406:
407: 408: 409:
410: SYSCALL ER _tk_loc_mtx( ID mtxid, TMO tmout )
411: {
412: return _tk_loc_mtx_u(mtxid, to_usec_tmo(tmout));
413: }
414:
415: SYSCALL ER _tk_loc_mtx_u( ID mtxid, TMO_U tmout )
416: {
417: MTXCB *mtxcb;
418: TCB *mtxtsk;
419: ATR mtxatr;
420: ER ercd = E_OK;
421:
422: CHECK_MTXID(mtxid);
423: CHECK_TMOUT(tmout);
424: CHECK_DISPATCH();
425:
426: mtxcb = get_mtxcb(mtxid);
427:
428: BEGIN_CRITICAL_SECTION;
429: if ( mtxcb->mtxid == 0 ) {
430: ercd = E_NOEXS;
431: goto error_exit;
432: }
433: if ( mtxcb->mtxtsk == ctxtsk ) {
434: ercd = E_ILUSE;
435: goto error_exit;
436: }
437:
438: mtxatr = mtxcb->mtxatr & TA_CEILING;
439: if ( mtxatr == TA_CEILING ) {
440: if ( ctxtsk->bpriority < mtxcb->ceilpri ) {
441:
442: ercd = E_ILUSE;
443: goto error_exit;
444: }
445: }
446:
447:
448: if ( is_diswai((GCB*)mtxcb, ctxtsk, TTW_MTX) ) {
449: ercd = E_DISWAI;
450: goto error_exit;
451: }
452:
453: mtxtsk = mtxcb->mtxtsk;
454: if ( mtxtsk == NULL ) {
455:
456: mtxcb->mtxtsk = ctxtsk;
457: mtxcb->mtxlist = ctxtsk->mtxlist;
458: ctxtsk->mtxlist = mtxcb;
459:
460: if ( mtxatr == TA_CEILING ) {
461: if ( ctxtsk->priority > mtxcb->ceilpri ) {
462: 463:
464: change_task_priority(ctxtsk, mtxcb->ceilpri);
465: }
466: }
467: } else {
468: ercd = E_TMOUT;
469: if ( tmout == TMO_POL ) {
470: goto error_exit;
471: }
472:
473: if ( mtxatr == TA_INHERIT ) {
474: if ( mtxtsk->priority > ctxtsk->priority ) {
475: 476: 477:
478: change_task_priority(mtxtsk, ctxtsk->priority);
479: }
480: }
481:
482:
483: ctxtsk->wspec = ( mtxatr == TA_TFIFO )? &wspec_mtx_tfifo:
484: ( mtxatr == TA_INHERIT )? &wspec_mtx_inherit:
485: &wspec_mtx_tpri;
486: ctxtsk->wercd = &ercd;
487: ctxtsk->wid = mtxcb->mtxid;
488: make_wait(tmout, mtxcb->mtxatr);
489: if ( mtxatr == TA_TFIFO ) {
490: QueInsert(&ctxtsk->tskque, &mtxcb->wait_queue);
491: } else {
492: queue_insert_tpri(ctxtsk, &mtxcb->wait_queue);
493: }
494: }
495:
496: error_exit:
497: END_CRITICAL_SECTION;
498:
499: return ercd;
500: }
501:
502: 503: 504:
505: SYSCALL ER _tk_unl_mtx( ID mtxid )
506: {
507: MTXCB *mtxcb;
508: TCB *tcb;
509: ER ercd = E_OK;
510:
511: CHECK_MTXID(mtxid);
512: CHECK_INTSK();
513:
514: mtxcb = get_mtxcb(mtxid);
515:
516: BEGIN_CRITICAL_SECTION;
517: if ( mtxcb->mtxid == 0 ) {
518: ercd = E_NOEXS;
519: goto error_exit;
520: }
521: if ( mtxcb->mtxtsk != ctxtsk ) {
522: ercd = E_ILUSE;
523: goto error_exit;
524: }
525:
526: 527:
528: release_mutex(ctxtsk, mtxcb);
529:
530: if ( mtx_waited(mtxcb) ) {
531: tcb = (TCB*)mtxcb->wait_queue.next;
532:
533:
534: wait_release_ok(tcb);
535:
536:
537: mtxcb->mtxtsk = tcb;
538: mtxcb->mtxlist = tcb->mtxlist;
539: tcb->mtxlist = mtxcb;
540:
541: if ( (mtxcb->mtxatr & TA_CEILING) == TA_CEILING ) {
542: if ( tcb->priority > mtxcb->ceilpri ) {
543: 544:
545: change_task_priority(tcb, mtxcb->ceilpri);
546: }
547: }
548: } else {
549:
550: mtxcb->mtxtsk = NULL;
551: }
552:
553: error_exit:
554: END_CRITICAL_SECTION;
555:
556: return ercd;
557: }
558:
559:
560: 561: 562:
563: SYSCALL ER _tk_ref_mtx( ID mtxid, T_RMTX *pk_rmtx )
564: {
565: MTXCB *mtxcb;
566: ER ercd = E_OK;
567:
568: CHECK_MTXID(mtxid);
569:
570: mtxcb = get_mtxcb(mtxid);
571:
572: BEGIN_CRITICAL_SECTION;
573: if ( mtxcb->mtxid == 0 ) {
574: ercd = E_NOEXS;
575: } else {
576: pk_rmtx->exinf = mtxcb->exinf;
577: pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )?
578: mtxcb->mtxtsk->tskid: 0;
579: pk_rmtx->wtsk = wait_tskid(&mtxcb->wait_queue);
580: }
581: END_CRITICAL_SECTION;
582:
583: return ercd;
584: }
585:
586:
587: 588: 589:
590: #if USE_DBGSPT
591:
592: 593: 594:
595: #if USE_OBJECT_NAME
596: EXPORT ER mutex_getname(ID id, UB **name)
597: {
598: MTXCB *mtxcb;
599: ER ercd = E_OK;
600:
601: CHECK_MTXID(id);
602:
603: BEGIN_DISABLE_INTERRUPT;
604: mtxcb = get_mtxcb(id);
605: if ( mtxcb->mtxid == 0 ) {
606: ercd = E_NOEXS;
607: goto error_exit;
608: }
609: if ( (mtxcb->mtxatr & TA_DSNAME) == 0 ) {
610: ercd = E_OBJ;
611: goto error_exit;
612: }
613: *name = mtxcb->name;
614:
615: error_exit:
616: END_DISABLE_INTERRUPT;
617:
618: return ercd;
619: }
620: #endif
621:
622: 623: 624:
625: SYSCALL INT _td_lst_mtx( ID list[], INT nent )
626: {
627: MTXCB *mtxcb, *end;
628: INT n = 0;
629:
630: BEGIN_DISABLE_INTERRUPT;
631: end = mtxcb_table + NUM_MTXID;
632: for ( mtxcb = mtxcb_table; mtxcb < end; mtxcb++ ) {
633: if ( mtxcb->mtxid == 0 ) {
634: continue;
635: }
636:
637: if ( n++ < nent ) {
638: *list++ = mtxcb->mtxid;
639: }
640: }
641: END_DISABLE_INTERRUPT;
642:
643: return n;
644: }
645:
646: 647: 648:
649: SYSCALL ER _td_ref_mtx( ID mtxid, TD_RMTX *pk_rmtx )
650: {
651: MTXCB *mtxcb;
652: ER ercd = E_OK;
653:
654: CHECK_MTXID(mtxid);
655:
656: mtxcb = get_mtxcb(mtxid);
657:
658: BEGIN_DISABLE_INTERRUPT;
659: if ( mtxcb->mtxid == 0 ) {
660: ercd = E_NOEXS;
661: } else {
662: pk_rmtx->exinf = mtxcb->exinf;
663: pk_rmtx->htsk = ( mtxcb->mtxtsk != NULL )?
664: mtxcb->mtxtsk->tskid: 0;
665: pk_rmtx->wtsk = wait_tskid(&mtxcb->wait_queue);
666: }
667: END_DISABLE_INTERRUPT;
668:
669: return ercd;
670: }
671:
672: 673: 674:
675: SYSCALL INT _td_mtx_que( ID mtxid, ID list[], INT nent )
676: {
677: MTXCB *mtxcb;
678: QUEUE *q;
679: ER ercd = E_OK;
680:
681: CHECK_MTXID(mtxid);
682:
683: mtxcb = get_mtxcb(mtxid);
684:
685: BEGIN_DISABLE_INTERRUPT;
686: if ( mtxcb->mtxid == 0 ) {
687: ercd = E_NOEXS;
688: } else {
689: INT n = 0;
690: for ( q = mtxcb->wait_queue.next; q != &mtxcb->wait_queue; q = q->next ) {
691: if ( n++ < nent ) {
692: *list++ = ((TCB*)q)->tskid;
693: }
694: }
695: ercd = n;
696: }
697: END_DISABLE_INTERRUPT;
698:
699: return ercd;
700: }
701:
702: #endif
703: #endif