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