GadgetSeed  0.9.6
mutex.c
[詳解]
1 /** @file
2  @brief MUTEX操作
3 
4  @date 2011.03.20
5  @author Takashi SHUDO
6 */
7 
8 #include "tkprintf.h"
9 #include "timer.h"
10 #include "mutex.h"
11 #include "calltrace.h"
12 
13 #include "queue_opration.h"
14 #include "mutex_opration.h"
15 
16 //#define DEBUGKBITS 0x03
17 #include "dkprintf.h"
18 
19 
20 struct st_mutex mutex_queue_list; ///< MUTEXキュー
21 
22 void init_mutex(void)
23 {
24  DKFPRINTF(0x01, "done\n");
25 
26  init_queue(&mutex_queue_list.list);
27 }
28 
29 /**
30  @brief MUTEXを登録する
31 
32  システムのキューに登録される
33 
34  @param[in] mutex MUTEX
35  @param[in] name MUTEX名
36 */
37 void mutex_register_ISR(struct st_mutex *mutex, const char *name)
38 {
39  DKFPRINTF(0x01, "mutex = %p, name = %s\n", mutex, name);
40 
41  mutex->lock_ps = 0;
42  mutex->name = name;
43 
44  init_queue(&mutex->wait_ps);
45 
46  add_queue(&mutex_queue_list.list, (struct st_queue *)mutex);
47 }
48 
49 /**
50  @brief MUTEXを登録解除する
51 
52  システムのキューより削除される
53 
54  @param[in] mutex MUTEX
55 */
56 int mutex_unregister_ISR(struct st_mutex *mutex)
57 {
58  DKFPRINTF(0x01, "mutex = %p\n", mutex);
59 
60  /*
61  本当は待ちキューがあれば破棄失敗
62  */
63 
64  del_queue((struct st_queue *)mutex);
65 
66  return 0;
67 }
68 
69 /* NOT API
70  @brief MUTEXをロックする
71 
72  既にロックされていた場合、自タスクを実行キューから外し
73  mutex_wait() をコールし MUTEX 待ちキューに登録する
74 
75  @param[in] mutex MUTEX
76  @param[in] tcb MUTEXをロックするタスクのTCB
77 
78  @return
79 
80  0: ロック成功
81  1: ロック解除待ち
82 */
83 int _mutex_lock(struct st_mutex *mutex, struct st_tcb *tcb)
84 {
85  int rtc = 0;
86  DKFPRINTF(0x02, "%s %d\n", mutex->name, tcb->id);
87 
88  if(mutex->lock_ps == 0) {
89  // ロックされていないMUTEX
90  mutex->lock_ps = tcb;
91  DKFPRINTF(0x01, "(%p:%s) Lock PID=%d \"%s\"\n",
92  mutex, mutex->name, tcb->id, tcb->name);
93  rtc = 0;
94  } else if(mutex->lock_ps == tcb) {
95  // 自タスクで既にロック済みだったMUTEX
96 #ifdef CHECK_MULTI_LOCK_MUTEX
97 #ifdef __x86_64__
98  SYSERR_PRINT("(%p:%s) Already Locked PID=%d \"%s\"\n",
99  mutex, mutex->name, tcb->id, tcb->name);
100 #else
101  unsigned long long stime = get_system_utime();
102  SYSERR_PRINT("(%p:%s) Already Locked PID=%d \"%s\" Lock PID=%d \"%s\" time = %08ld.%03ld\n",
103  mutex, mutex->name,
104  mutex->lock_ps->id, mutex->lock_ps->name,
105  tcb->id, tcb->name,
106  stime / 1000, stime % 1000);
107 #endif
108  print_queues();
109  print_calltrace();
110 #endif
111  rtc = -1;
112  } else {
113  // 既にロック済みのMUTEX
114  DKFPRINTF(0x01, "(%p:%s) Wait Unlock PID=%d \"%s\"\n",
115  mutex, mutex->name, tcb->id, tcb->name);
116  rtc = 1;
117  }
118 
119  //print_queues(); // DEBUG
120 
121  return rtc;
122 }
123 
124 /* NOT API
125  @brief MUTEXを待つ
126 */
127 void _mutex_wait(struct st_mutex *mutex, struct st_tcb *tcb)
128 {
129  add_queue(&mutex->wait_ps, (struct st_queue *)tcb);
130 }
131 
132 /* NOT API
133  @brief MUTEXをアンロックする
134 
135  自身がロックしたMUTEXでなければ失敗
136  待ちタスクがあった場合、次の待ちタスクが実行される
137 
138  @return
139 
140  0: ロックされていない、または tcb がロックした MUTEX ではない
141  またはアンロックしたけど待ちタスクがいない
142 
143  !=0: 待ちタスク tcb
144 */
145 struct st_tcb * _mutex_unlock(struct st_mutex *mutex, struct st_tcb *tcb)
146 {
147  struct st_tcb *wup_tcb = 0;
148 
149  DKFPRINTF(0x02, "MUTEX UNLOCK %s %d\n", mutex->name, tcb->id);
150 
151  if(mutex->lock_ps == 0) {
152  // ロックされていないMUTEX
153 #ifdef CHECK_MULTI_LOCK_MUTEX
154  SYSERR_PRINT("(%p:%s) Not locked PID=%d \"%s\"\n",
155  mutex, mutex->name, tcb->id, tcb->name);
156  print_queues();
157  print_calltrace();
158 #endif
159  return (struct st_tcb *)0;
160  } else if(mutex->lock_ps != tcb) {
161  // 他のタスクにロックされていたMUTEX
162  SYSERR_PRINT("(%p:%s) Cannot Unlock PID=%d \"%s\"\n",
163  mutex, mutex->name, tcb->id, tcb->name);
164  SYSERR_PRINT("MUTEX Lock PID=%d \"%s\"\n",
165  mutex->lock_ps->id, mutex->lock_ps->name);
166  wup_tcb = (struct st_tcb *)0;
167  } else {
168  // 自タスクでロックしていたMUTEX
169  struct st_tcb *l_ps = mutex->lock_ps;
170  DKFPRINTF(0x01, "(%p:%s) Unlock PID=%d \"%s\"\n",
171  mutex, mutex->name, tcb->id, tcb->name);
172  mutex->lock_ps = 0;
173  DKFPRINTF(0x02, "MUTEX UNLOCK SUCCESS %s %d\n", mutex->name, tcb->id);
174 
175  if(check_queue(&mutex->wait_ps) == 0) {
176  // ロック待ちのタスクが無かった
177  DKFPRINTF(0x01, "(%p:%s) No Wait Process PID=%d \"%s\"\n",
178  mutex, mutex->name, tcb->id, tcb->name);
179  wup_tcb = (struct st_tcb *)0;
180  goto end;
181  }
182 
183  // ロック待ちのタスクが有る
184  // 次のロック待ちタスクを待ちキューから取り出し
185  wup_tcb = (struct st_tcb *)del_next_queue(&mutex->wait_ps);
186  if(l_ps == wup_tcb) {
187  SYSERR_PRINT("Next queue is some queue ? %d %d\n", l_ps->id, wup_tcb->id);
188  }
189  // 今ロックしているタスクに設定
190  mutex->lock_ps = wup_tcb;
191  DKPRINTF(0x02, "MUTEX UNLOCK next process %s %d\n", mutex->name, mutex->lock_ps->id);
192  DKPRINTF(0x01, "(%p:%s) Unlocked Wakeup PID=%d \"%s\"\n",
193  mutex, mutex->name, wup_tcb->id, wup_tcb->name);
194  }
195 
196 end:
197  //print_queues(); // DEBUG
198  // いまロックしているタスクを返す
199  return wup_tcb;
200 }
void mutex_register_ISR(struct st_mutex *mutex, const char *name)
MUTEXを登録する
Definition: mutex.c:37
MUTEX操作
unsigned long long get_system_utime(void)
システム時間を取得する
Definition: timer.c:202
struct st_queue list
MUTEXのキュー
Definition: mutex.h:14
カーネルタイマ
キュー構造
Definition: queue.h:13
カーネル用機能限定printf
char name[TASK_NAME_LEN+1]
タスク名
Definition: tcb.h:39
int mutex_unregister_ISR(struct st_mutex *mutex)
MUTEXを登録解除する
Definition: mutex.c:56
MUTEX
Definition: mutex.h:13
MUTEX制御
struct st_mutex mutex_queue_list
MUTEXキュー
Definition: mutex.c:20
struct st_tcb * lock_ps
ロックしているタスク
Definition: mutex.h:15
キュー操作
デバッグ用システムコールトレース
struct st_queue wait_ps
アンロック待ちタスクキュー
Definition: mutex.h:16
カーネル、ドライバ(非タスク)デバッグ用マクロ
int id
タスクID
Definition: tcb.h:38
タスクコンテキスト
Definition: tcb.h:32
const char * name
MUTEX名文字列
Definition: mutex.h:17