/src/compiler/ucos-vs2008/UCOS_SIM/src/ucosii/os_sem.c

http://ftk.googlecode.com/ · C · 493 lines · 285 code · 37 blank · 171 comment · 70 complexity · fec2d060c56ad9b8f9a9b33dfd7a5593 MD5 · raw file

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * SEMAPHORE MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2005, Jean J. Labrosse, Weston, FL
  8. * All Rights Reserved
  9. *
  10. * File : OS_SEM.C
  11. * By : Jean J. Labrosse
  12. * Version : V2.80
  13. *********************************************************************************************************
  14. */
  15. #ifndef OS_MASTER_FILE
  16. #include <ucos_ii.h>
  17. #endif
  18. #if OS_SEM_EN > 0
  19. /*
  20. *********************************************************************************************************
  21. * ACCEPT SEMAPHORE
  22. *
  23. * Description: This function checks the semaphore to see if a resource is available or, if an event
  24. * occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
  25. * resource is not available or the event did not occur.
  26. *
  27. * Arguments : pevent is a pointer to the event control block
  28. *
  29. * Returns : > 0 if the resource is available or the event did not occur the semaphore is
  30. * decremented to obtain the resource.
  31. * == 0 if the resource is not available or the event did not occur or,
  32. * if 'pevent' is a NULL pointer or,
  33. * if you didn't pass a pointer to a semaphore
  34. *********************************************************************************************************
  35. */
  36. #if OS_SEM_ACCEPT_EN > 0
  37. INT16U OSSemAccept (OS_EVENT *pevent)
  38. {
  39. INT16U cnt;
  40. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  41. OS_CPU_SR cpu_sr = 0;
  42. #endif
  43. #if OS_ARG_CHK_EN > 0
  44. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  45. return (0);
  46. }
  47. #endif
  48. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  49. return (0);
  50. }
  51. OS_ENTER_CRITICAL();
  52. cnt = pevent->OSEventCnt;
  53. if (cnt > 0) { /* See if resource is available */
  54. pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */
  55. }
  56. OS_EXIT_CRITICAL();
  57. return (cnt); /* Return semaphore count */
  58. }
  59. #endif
  60. /*$PAGE*/
  61. /*
  62. *********************************************************************************************************
  63. * CREATE A SEMAPHORE
  64. *
  65. * Description: This function creates a semaphore.
  66. *
  67. * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is
  68. * available (or no event has occurred). You initialize the semaphore to a
  69. * non-zero value to specify how many resources are available (e.g. if you have
  70. * 10 resources, you would initialize the semaphore to 10).
  71. *
  72. * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  73. * created semaphore
  74. * == (void *)0 if no event control blocks were available
  75. *********************************************************************************************************
  76. */
  77. OS_EVENT *OSSemCreate (INT16U cnt)
  78. {
  79. OS_EVENT *pevent;
  80. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  81. OS_CPU_SR cpu_sr = 0;
  82. #endif
  83. if (OSIntNesting > 0) { /* See if called from ISR ... */
  84. return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
  85. }
  86. OS_ENTER_CRITICAL();
  87. pevent = OSEventFreeList; /* Get next free event control block */
  88. if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
  89. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  90. }
  91. OS_EXIT_CRITICAL();
  92. if (pevent != (OS_EVENT *)0) { /* Get an event control block */
  93. pevent->OSEventType = OS_EVENT_TYPE_SEM;
  94. pevent->OSEventCnt = cnt; /* Set semaphore value */
  95. pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */
  96. #if OS_EVENT_NAME_SIZE > 1
  97. pevent->OSEventName[0] = '?'; /* Unknown name */
  98. pevent->OSEventName[1] = OS_ASCII_NUL;
  99. #endif
  100. OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
  101. }
  102. return (pevent);
  103. }
  104. /*$PAGE*/
  105. /*
  106. *********************************************************************************************************
  107. * DELETE A SEMAPHORE
  108. *
  109. * Description: This function deletes a semaphore and readies all tasks pending on the semaphore.
  110. *
  111. * Arguments : pevent is a pointer to the event control block associated with the desired
  112. * semaphore.
  113. *
  114. * opt determines delete options as follows:
  115. * opt == OS_DEL_NO_PEND Delete semaphore ONLY if no task pending
  116. * opt == OS_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
  117. * In this case, all the tasks pending will be readied.
  118. *
  119. * err is a pointer to an error code that can contain one of the following values:
  120. * OS_NO_ERR The call was successful and the semaphore was deleted
  121. * OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR
  122. * OS_ERR_INVALID_OPT An invalid option was specified
  123. * OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
  124. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  125. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  126. *
  127. * Returns : pevent upon error
  128. * (OS_EVENT *)0 if the semaphore was successfully deleted.
  129. *
  130. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  131. * the semaphore MUST check the return code of OSSemPend().
  132. * 2) OSSemAccept() callers will not know that the intended semaphore has been deleted unless
  133. * they check 'pevent' to see that it's a NULL pointer.
  134. * 3) This call can potentially disable interrupts for a long time. The interrupt disable
  135. * time is directly proportional to the number of tasks waiting on the semaphore.
  136. * 4) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in
  137. * applications where the semaphore is used for mutual exclusion because the resource(s)
  138. * will no longer be guarded by the semaphore.
  139. *********************************************************************************************************
  140. */
  141. #if OS_SEM_DEL_EN > 0
  142. OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  143. {
  144. BOOLEAN tasks_waiting;
  145. OS_EVENT *pevent_return;
  146. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  147. OS_CPU_SR cpu_sr = 0;
  148. #endif
  149. #if OS_ARG_CHK_EN > 0
  150. if (err == (INT8U *)0) { /* Validate 'err' */
  151. return (pevent);
  152. }
  153. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  154. *err = OS_ERR_PEVENT_NULL;
  155. return (pevent);
  156. }
  157. #endif
  158. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  159. *err = OS_ERR_EVENT_TYPE;
  160. return (pevent);
  161. }
  162. if (OSIntNesting > 0) { /* See if called from ISR ... */
  163. *err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  164. return (pevent);
  165. }
  166. OS_ENTER_CRITICAL();
  167. if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on semaphore */
  168. tasks_waiting = TRUE; /* Yes */
  169. } else {
  170. tasks_waiting = FALSE; /* No */
  171. }
  172. switch (opt) {
  173. case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
  174. if (tasks_waiting == FALSE) {
  175. #if OS_EVENT_NAME_SIZE > 1
  176. pevent->OSEventName[0] = '?'; /* Unknown name */
  177. pevent->OSEventName[1] = OS_ASCII_NUL;
  178. #endif
  179. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  180. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  181. pevent->OSEventCnt = 0;
  182. OSEventFreeList = pevent; /* Get next free event control block */
  183. OS_EXIT_CRITICAL();
  184. *err = OS_NO_ERR;
  185. pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  186. } else {
  187. OS_EXIT_CRITICAL();
  188. *err = OS_ERR_TASK_WAITING;
  189. pevent_return = pevent;
  190. }
  191. break;
  192. case OS_DEL_ALWAYS: /* Always delete the semaphore */
  193. while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for semaphore */
  194. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
  195. }
  196. #if OS_EVENT_NAME_SIZE > 1
  197. pevent->OSEventName[0] = '?'; /* Unknown name */
  198. pevent->OSEventName[1] = OS_ASCII_NUL;
  199. #endif
  200. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  201. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  202. pevent->OSEventCnt = 0;
  203. OSEventFreeList = pevent; /* Get next free event control block */
  204. OS_EXIT_CRITICAL();
  205. if (tasks_waiting == TRUE) { /* Reschedule only if task(s) were waiting */
  206. OS_Sched(); /* Find highest priority task ready to run */
  207. }
  208. *err = OS_NO_ERR;
  209. pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  210. break;
  211. default:
  212. OS_EXIT_CRITICAL();
  213. *err = OS_ERR_INVALID_OPT;
  214. pevent_return = pevent;
  215. break;
  216. }
  217. return (pevent_return);
  218. }
  219. #endif
  220. /*$PAGE*/
  221. /*
  222. *********************************************************************************************************
  223. * PEND ON SEMAPHORE
  224. *
  225. * Description: This function waits for a semaphore.
  226. *
  227. * Arguments : pevent is a pointer to the event control block associated with the desired
  228. * semaphore.
  229. *
  230. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  231. * wait for the resource up to the amount of time specified by this argument.
  232. * If you specify 0, however, your task will wait forever at the specified
  233. * semaphore or, until the resource becomes available (or the event occurs).
  234. *
  235. * err is a pointer to where an error message will be deposited. Possible error
  236. * messages are:
  237. *
  238. * OS_NO_ERR The call was successful and your task owns the resource
  239. * or, the event you are waiting for occurred.
  240. * OS_TIMEOUT The semaphore was not received within the specified
  241. * timeout.
  242. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  243. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  244. * would lead to a suspension.
  245. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  246. *
  247. * Returns : none
  248. *********************************************************************************************************
  249. */
  250. void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  251. {
  252. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  253. OS_CPU_SR cpu_sr = 0;
  254. #endif
  255. #if OS_ARG_CHK_EN > 0
  256. if (err == (INT8U *)0) { /* Validate 'err' */
  257. return;
  258. }
  259. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  260. *err = OS_ERR_PEVENT_NULL;
  261. return;
  262. }
  263. #endif
  264. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  265. *err = OS_ERR_EVENT_TYPE;
  266. return;
  267. }
  268. if (OSIntNesting > 0) { /* See if called from ISR ... */
  269. *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  270. return;
  271. }
  272. OS_ENTER_CRITICAL();
  273. if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */
  274. pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
  275. OS_EXIT_CRITICAL();
  276. *err = OS_NO_ERR;
  277. return;
  278. }
  279. /* Otherwise, must wait until event occurs */
  280. OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
  281. OSTCBCur->OSTCBPendTO = FALSE;
  282. OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
  283. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  284. OS_EXIT_CRITICAL();
  285. OS_Sched(); /* Find next highest priority task ready */
  286. OS_ENTER_CRITICAL();
  287. if (OSTCBCur->OSTCBPendTO == TRUE) { /* See if we timedout */
  288. OS_EventTO(pevent);
  289. OS_EXIT_CRITICAL();
  290. *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */
  291. return;
  292. }
  293. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  294. OS_EXIT_CRITICAL();
  295. *err = OS_NO_ERR;
  296. }
  297. /*$PAGE*/
  298. /*
  299. *********************************************************************************************************
  300. * POST TO A SEMAPHORE
  301. *
  302. * Description: This function signals a semaphore
  303. *
  304. * Arguments : pevent is a pointer to the event control block associated with the desired
  305. * semaphore.
  306. *
  307. * Returns : OS_NO_ERR The call was successful and the semaphore was signaled.
  308. * OS_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
  309. * signalled the semaphore more often than you waited on it with either
  310. * OSSemAccept() or OSSemPend().
  311. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  312. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  313. *********************************************************************************************************
  314. */
  315. INT8U OSSemPost (OS_EVENT *pevent)
  316. {
  317. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  318. OS_CPU_SR cpu_sr = 0;
  319. #endif
  320. #if OS_ARG_CHK_EN > 0
  321. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  322. return (OS_ERR_PEVENT_NULL);
  323. }
  324. #endif
  325. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  326. return (OS_ERR_EVENT_TYPE);
  327. }
  328. OS_ENTER_CRITICAL();
  329. if (pevent->OSEventGrp != 0) { /* See if any task waiting for semaphore*/
  330. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event */
  331. OS_EXIT_CRITICAL();
  332. OS_Sched(); /* Find HPT ready to run */
  333. return (OS_NO_ERR);
  334. }
  335. if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
  336. pevent->OSEventCnt++; /* Increment semaphore count to register event */
  337. OS_EXIT_CRITICAL();
  338. return (OS_NO_ERR);
  339. }
  340. OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
  341. return (OS_SEM_OVF);
  342. }
  343. /*$PAGE*/
  344. /*
  345. *********************************************************************************************************
  346. * QUERY A SEMAPHORE
  347. *
  348. * Description: This function obtains information about a semaphore
  349. *
  350. * Arguments : pevent is a pointer to the event control block associated with the desired
  351. * semaphore
  352. *
  353. * p_sem_data is a pointer to a structure that will contain information about the
  354. * semaphore.
  355. *
  356. * Returns : OS_NO_ERR The call was successful and the message was sent
  357. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non semaphore.
  358. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  359. * OS_ERR_PDATA_NULL If 'p_sem_data' is a NULL pointer
  360. *********************************************************************************************************
  361. */
  362. #if OS_SEM_QUERY_EN > 0
  363. INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
  364. {
  365. #if OS_LOWEST_PRIO <= 63
  366. INT8U *psrc;
  367. INT8U *pdest;
  368. #else
  369. INT16U *psrc;
  370. INT16U *pdest;
  371. #endif
  372. INT8U i;
  373. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  374. OS_CPU_SR cpu_sr = 0;
  375. #endif
  376. #if OS_ARG_CHK_EN > 0
  377. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  378. return (OS_ERR_PEVENT_NULL);
  379. }
  380. if (p_sem_data == (OS_SEM_DATA *)0) { /* Validate 'p_sem_data' */
  381. return (OS_ERR_PDATA_NULL);
  382. }
  383. #endif
  384. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  385. return (OS_ERR_EVENT_TYPE);
  386. }
  387. OS_ENTER_CRITICAL();
  388. p_sem_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */
  389. psrc = &pevent->OSEventTbl[0];
  390. pdest = &p_sem_data->OSEventTbl[0];
  391. for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  392. *pdest++ = *psrc++;
  393. }
  394. p_sem_data->OSCnt = pevent->OSEventCnt; /* Get semaphore count */
  395. OS_EXIT_CRITICAL();
  396. return (OS_NO_ERR);
  397. }
  398. #endif /* OS_SEM_QUERY_EN */
  399. /*$PAGE*/
  400. /*
  401. *********************************************************************************************************
  402. * SET SEMAPHORE
  403. *
  404. * Description: This function sets the semaphore count to the value specified as an argument. Typically,
  405. * this value would be 0.
  406. *
  407. * You would typically use this function when a semaphore is used as a signaling mechanism
  408. * and, you want to reset the count value.
  409. *
  410. * Arguments : pevent is a pointer to the event control block
  411. *
  412. * cnt is the new value for the semaphore count. You would pass 0 to reset the
  413. * semaphore count.
  414. *
  415. * err is a pointer to an error code returned by the function as follows:
  416. *
  417. * OS_NO_ERR The call was successful and the semaphore value was set.
  418. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  419. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  420. * OS_ERR_TASK_WAITING If tasks are waiting on the semaphore.
  421. *********************************************************************************************************
  422. */
  423. #if OS_SEM_SET_EN > 0
  424. void OSSemSet (OS_EVENT *pevent, INT16U cnt, INT8U *err)
  425. {
  426. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  427. OS_CPU_SR cpu_sr = 0;
  428. #endif
  429. #if OS_ARG_CHK_EN > 0
  430. if (err == (INT8U *)0) { /* Validate 'err' */
  431. return;
  432. }
  433. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  434. *err = OS_ERR_PEVENT_NULL;
  435. return;
  436. }
  437. #endif
  438. if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  439. *err = OS_ERR_EVENT_TYPE;
  440. return;
  441. }
  442. OS_ENTER_CRITICAL();
  443. *err = OS_NO_ERR;
  444. if (pevent->OSEventCnt > 0) { /* See if semaphore already has a count */
  445. pevent->OSEventCnt = cnt; /* Yes, set it to the new value specified. */
  446. } else { /* No */
  447. if (pevent->OSEventGrp == 0) { /* See if task(s) waiting? */
  448. pevent->OSEventCnt = cnt; /* No, OK to set the value */
  449. } else {
  450. *err = OS_ERR_TASK_WAITING;
  451. }
  452. }
  453. OS_EXIT_CRITICAL();
  454. }
  455. #endif
  456. #endif /* OS_SEM_EN */