3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
6 * Copyright (C) 2005-2009 by Embedded and Real-Time Systems Laboratory
7 * Graduate School of Information Science, Nagoya Univ., JAPAN
9 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
10 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
15 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
19 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
22 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
24 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
26 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 * @(#) $Id: mutex.c 1694 2010-01-01 15:59:09Z ertl-hiro $
45 #include "kernel_impl.h"
54 #ifndef LOG_LOC_MTX_ENTER
55 #define LOG_LOC_MTX_ENTER(mtxid)
56 #endif /* LOG_LOC_MTX_ENTER */
58 #ifndef LOG_LOC_MTX_LEAVE
59 #define LOG_LOC_MTX_LEAVE(ercd)
60 #endif /* LOG_LOC_MTX_LEAVE */
62 #ifndef LOG_PLOC_MTX_ENTER
63 #define LOG_PLOC_MTX_ENTER(mtxid)
64 #endif /* LOG_PLOC_MTX_ENTER */
66 #ifndef LOG_PLOC_MTX_LEAVE
67 #define LOG_PLOC_MTX_LEAVE(ercd)
68 #endif /* LOG_PLOC_MTX_LEAVE */
70 #ifndef LOG_TLOC_MTX_ENTER
71 #define LOG_TLOC_MTX_ENTER(mtxid, tmout)
72 #endif /* LOG_TLOC_MTX_ENTER */
74 #ifndef LOG_TLOC_MTX_LEAVE
75 #define LOG_TLOC_MTX_LEAVE(ercd)
76 #endif /* LOG_TLOC_MTX_LEAVE */
78 #ifndef LOG_UNL_MTX_ENTER
79 #define LOG_UNL_MTX_ENTER(mtxid)
80 #endif /* LOG_UNL_MTX_ENTER */
82 #ifndef LOG_UNL_MTX_LEAVE
83 #define LOG_UNL_MTX_LEAVE(ercd)
84 #endif /* LOG_UNL_MTX_LEAVE */
86 #ifndef LOG_INI_MTX_ENTER
87 #define LOG_INI_MTX_ENTER(mtxid)
88 #endif /* LOG_INI_MTX_ENTER */
90 #ifndef LOG_INI_MTX_LEAVE
91 #define LOG_INI_MTX_LEAVE(ercd)
92 #endif /* LOG_INI_MTX_LEAVE */
94 #ifndef LOG_REF_MTX_ENTER
95 #define LOG_REF_MTX_ENTER(mtxid, pk_rmtx)
96 #endif /* LOG_REF_MTX_ENTER */
98 #ifndef LOG_REF_MTX_LEAVE
99 #define LOG_REF_MTX_LEAVE(ercd, pk_rmtx)
100 #endif /* LOG_REF_MTX_LEAVE */
105 #define tnum_mtx ((uint_t)(tmax_mtxid - TMIN_MTXID + 1))
108 * ミューテックスIDからミューテックス管理ブロックを取り出すためのマクロ
110 #define INDEX_MTX(mtxid) ((uint_t)((mtxid) - TMIN_MTXID))
111 #define get_mtxcb(mtxid) (&(mtxcb_table[INDEX_MTX(mtxid)]))
114 * ミューテックス管理ブロック中のmutex_queueへのポインタから,ミューテッ
115 * クス管理ブロックへのポインタを取り出すためのマクロ
117 #define MTXCB_QUEUE(p_queue) \
118 ((MTXCB *)(((char *) p_queue) - offsetof(MTXCB, mutex_queue)))
121 * ミューテックスのプロトコルを判断するマクロ
123 #define MTXPROTO_MASK 0x03U
124 #define MTXPROTO(p_mtxcb) ((p_mtxcb)->p_mtxinib->mtxatr & MTXPROTO_MASK)
125 #define MTX_CEILING(p_mtxcb) (MTXPROTO(p_mtxcb) == TA_CEILING)
130 #ifdef TOPPERS_mtxhook
132 bool_t (*mtxhook_check_ceilpri)(TCB *p_tcb, uint_t bpriority) = NULL;
133 bool_t (*mtxhook_scan_ceilmtx)(TCB *p_tcb) = NULL;
134 bool_t (*mtxhook_release_all)(TCB *p_tcb) = NULL;
136 #endif /* TOPPERS_mtxhook */
141 #ifdef TOPPERS_mtxini
144 initialize_mutex(void)
149 mtxhook_check_ceilpri = mutex_check_ceilpri;
150 mtxhook_scan_ceilmtx = mutex_scan_ceilmtx;
151 mtxhook_release_all = mutex_release_all;
153 for (p_mtxcb = mtxcb_table, i = 0; i < tnum_mtx; p_mtxcb++, i++) {
154 queue_initialize(&(p_mtxcb->wait_queue));
155 p_mtxcb->p_mtxinib = &(mtxinib_table[i]);
156 p_mtxcb->p_loctsk = NULL;
160 #endif /* TOPPERS_mtxini */
165 #ifdef TOPPERS_mtxchk
168 mutex_check_ceilpri(TCB *p_tcb, uint_t bpriority)
174 * タスクがロックしている優先度上限ミューテックスの中で,上限優先
175 * 度がbpriorityよりも低いものがあれば,falseを返す.
177 p_queue = p_tcb->mutex_queue.p_next;
178 while (p_queue != &(p_tcb->mutex_queue)) {
179 p_mtxcb = MTXCB_QUEUE(p_queue);
180 if (MTX_CEILING(p_mtxcb) && bpriority < p_mtxcb->p_mtxinib->ceilpri) {
183 p_queue = p_queue->p_next;
187 * タスクが優先度上限ミューテックスのロックを待っている場合に,そ
188 * の上限優先度がbpriorityよりも低くければ,falseを返す.
190 if (TSTAT_WAIT_MTX(p_tcb->tstat)) {
191 p_mtxcb = ((WINFO_MTX *)(p_tcb->p_winfo))->p_mtxcb;
192 if (MTX_CEILING(p_mtxcb) && bpriority < p_mtxcb->p_mtxinib->ceilpri) {
198 * いずれの条件にも当てはまらなければtrueを返す.
203 #endif /* TOPPERS_mtxchk */
206 * 優先度上限ミューテックスをロックしているかのチェック
208 #ifdef TOPPERS_mtxscan
211 mutex_scan_ceilmtx(TCB *p_tcb)
216 p_queue = p_tcb->mutex_queue.p_next;
217 while (p_queue != &(p_tcb->mutex_queue)) {
218 p_mtxcb = MTXCB_QUEUE(p_queue);
219 if (MTX_CEILING(p_mtxcb)) {
222 p_queue = p_queue->p_next;
227 #endif /* TOPPERS_mtxscan */
232 #ifdef TOPPERS_mtxcalc
235 mutex_calc_priority(TCB *p_tcb)
241 priority = p_tcb->bpriority;
242 p_queue = p_tcb->mutex_queue.p_next;
243 while (p_queue != &(p_tcb->mutex_queue)) {
244 p_mtxcb = MTXCB_QUEUE(p_queue);
245 if (MTX_CEILING(p_mtxcb) && p_mtxcb->p_mtxinib->ceilpri < priority) {
246 priority = p_mtxcb->p_mtxinib->ceilpri;
248 p_queue = p_queue->p_next;
253 #endif /* TOPPERS_mtxcalc */
256 * 要素優先度が上がる(または増える)場合の現在優先度変更処理
259 mutex_raise_priority(TCB *p_tcb, uint_t newpri)
261 if (newpri < p_tcb->priority) {
262 return(change_priority(p_tcb, newpri, true));
268 * 要素優先度が下がる(または減る)場合の現在優先度変更処理
271 mutex_drop_priority(TCB *p_tcb, uint_t oldpri)
275 if (oldpri == p_tcb->priority) {
276 newpri = mutex_calc_priority(p_tcb);
277 if (newpri != p_tcb->priority) {
278 return(change_priority(p_tcb, newpri, true));
288 mutex_acquire(TCB *p_loctsk, MTXCB *p_mtxcb)
290 p_mtxcb->p_loctsk = p_loctsk;
291 queue_insert_prev(&(p_loctsk->mutex_queue), &(p_mtxcb->mutex_queue));
292 if (MTX_CEILING(p_mtxcb)) {
293 return(mutex_raise_priority(p_loctsk, p_mtxcb->p_mtxinib->ceilpri));
301 #ifdef TOPPERS_mtxrel
304 mutex_release(MTXCB *p_mtxcb)
308 if (queue_empty(&(p_mtxcb->wait_queue))) {
309 p_mtxcb->p_loctsk = NULL;
314 * ミューテックス待ちキューの先頭タスク(p_tcb)に,ミューテッ
317 p_tcb = (TCB *) queue_delete_next(&(p_mtxcb->wait_queue));
318 wait_dequeue_tmevtb(p_tcb);
319 p_tcb->p_winfo->wercd = E_OK;
321 p_mtxcb->p_loctsk = p_tcb;
322 queue_insert_prev(&(p_tcb->mutex_queue), &(p_mtxcb->mutex_queue));
323 if (MTX_CEILING(p_mtxcb)) {
324 if (p_mtxcb->p_mtxinib->ceilpri < p_tcb->priority) {
325 p_tcb->priority = p_mtxcb->p_mtxinib->ceilpri;
328 return(make_non_wait(p_tcb));
332 #endif /* TOPPERS_mtxrel */
335 * タスクがロックしているすべてのミューテックスのロック解除
337 #ifdef TOPPERS_mtxrela
340 mutex_release_all(TCB *p_tcb)
343 bool_t dspreq = false;
345 while (!queue_empty(&(p_tcb->mutex_queue))) {
346 p_mtxcb = MTXCB_QUEUE(p_tcb->mutex_queue.p_next);
347 queue_delete(&(p_mtxcb->mutex_queue));
348 if (mutex_release(p_mtxcb)) {
355 #endif /* TOPPERS_mtxrela */
360 #ifdef TOPPERS_loc_mtx
369 LOG_LOC_MTX_ENTER(mtxid);
372 p_mtxcb = get_mtxcb(mtxid);
375 if (MTX_CEILING(p_mtxcb)
376 && p_runtsk->bpriority < p_mtxcb->p_mtxinib->ceilpri) {
379 else if (p_mtxcb->p_loctsk == NULL) {
380 (void) mutex_acquire(p_runtsk, p_mtxcb);
382 * 優先度上限ミューテックスをロックした場合,p_runtskの優先度
383 * が上がる可能性があるが,ディスパッチが必要になることはない.
385 assert(!(p_runtsk != p_schedtsk && dspflg));
388 else if (p_mtxcb->p_loctsk == p_runtsk) {
392 p_runtsk->tstat = (TS_WAITING | TS_WAIT_MTX);
393 wobj_make_wait((WOBJCB *) p_mtxcb, (WINFO_WOBJ *) &winfo_mtx);
395 ercd = winfo_mtx.winfo.wercd;
400 LOG_LOC_MTX_LEAVE(ercd);
404 #endif /* TOPPERS_loc_mtx */
409 #ifdef TOPPERS_ploc_mtx
417 LOG_PLOC_MTX_ENTER(mtxid);
420 p_mtxcb = get_mtxcb(mtxid);
423 if (MTX_CEILING(p_mtxcb)
424 && p_runtsk->bpriority < p_mtxcb->p_mtxinib->ceilpri) {
427 else if (p_mtxcb->p_loctsk == NULL) {
428 (void) mutex_acquire(p_runtsk, p_mtxcb);
430 * 優先度上限ミューテックスをロックした場合,p_runtskの優先度
431 * が上がる可能性があるが,ディスパッチが必要になることはない.
433 assert(!(p_runtsk != p_schedtsk && dspflg));
436 else if (p_mtxcb->p_loctsk == p_runtsk) {
445 LOG_PLOC_MTX_LEAVE(ercd);
449 #endif /* TOPPERS_ploc_mtx */
452 * ミューテックスのロック(タイムアウトあり)
454 #ifdef TOPPERS_tloc_mtx
457 tloc_mtx(ID mtxid, TMO tmout)
464 LOG_TLOC_MTX_ENTER(mtxid, tmout);
468 p_mtxcb = get_mtxcb(mtxid);
471 if (MTX_CEILING(p_mtxcb)
472 && p_runtsk->bpriority < p_mtxcb->p_mtxinib->ceilpri) {
475 else if (p_mtxcb->p_loctsk == NULL) {
476 (void) mutex_acquire(p_runtsk, p_mtxcb);
478 * 優先度上限ミューテックスをロックした場合,p_runtskの優先度
479 * が上がる可能性があるが,ディスパッチが必要になることはない.
481 assert(!(p_runtsk != p_schedtsk && dspflg));
484 else if (p_mtxcb->p_loctsk == p_runtsk) {
487 else if (tmout == TMO_POL) {
491 p_runtsk->tstat = (TS_WAITING | TS_WAIT_MTX);
492 wobj_make_wait_tmout((WOBJCB *) p_mtxcb, (WINFO_WOBJ *) &winfo_mtx,
495 ercd = winfo_mtx.winfo.wercd;
500 LOG_TLOC_MTX_LEAVE(ercd);
504 #endif /* TOPPERS_tloc_mtx */
509 #ifdef TOPPERS_unl_mtx
515 bool_t dspreq = false;
518 LOG_UNL_MTX_ENTER(mtxid);
521 p_mtxcb = get_mtxcb(mtxid);
524 if (p_mtxcb->p_loctsk != p_runtsk) {
528 queue_delete(&(p_mtxcb->mutex_queue));
529 if (MTX_CEILING(p_mtxcb)) {
530 if (mutex_drop_priority(p_runtsk, p_mtxcb->p_mtxinib->ceilpri)) {
534 if (mutex_release(p_mtxcb)) {
545 LOG_UNL_MTX_LEAVE(ercd);
549 #endif /* TOPPERS_unl_mtx */
554 #ifdef TOPPERS_ini_mtx
564 LOG_INI_MTX_ENTER(mtxid);
567 p_mtxcb = get_mtxcb(mtxid);
570 dspreq = init_wait_queue(&(p_mtxcb->wait_queue));
571 p_loctsk = p_mtxcb->p_loctsk;
572 if (p_loctsk != NULL) {
573 queue_delete(&(p_mtxcb->mutex_queue));
574 p_mtxcb->p_loctsk = NULL;
575 if (MTX_CEILING(p_mtxcb)) {
576 if (mutex_drop_priority(p_loctsk, p_mtxcb->p_mtxinib->ceilpri)) {
588 LOG_INI_MTX_LEAVE(ercd);
592 #endif /* TOPPERS_ini_mtx */
597 #ifdef TOPPERS_ref_mtx
600 ref_mtx(ID mtxid, T_RMTX *pk_rmtx)
605 LOG_REF_MTX_ENTER(mtxid, pk_rmtx);
608 p_mtxcb = get_mtxcb(mtxid);
611 pk_rmtx->htskid = (p_mtxcb->p_loctsk != NULL) ? TSKID(p_mtxcb->p_loctsk)
613 pk_rmtx->wtskid = wait_tskid(&(p_mtxcb->wait_queue));
618 LOG_REF_MTX_LEAVE(ercd, pk_rmtx);
622 #endif /* TOPPERS_ref_mtx */