mutexPxLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:10k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* mutexPxLib.c - kernel mutexs and condition variables library */
  2. /* Copyright 1993-1994 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01d,24jan94,smb  added instrumentation macros
  8. 01c,12jan94,kdl  added includes of intLib.h, sysLib.h; general cleanup.
  9. 01b,13dec93,dvs  made NOMANUAL
  10. 01a,18feb93,rrr  written.
  11. */
  12. /*
  13. DESCRIPTION
  14. This library provides the interface to kernel mutexs and condition variables.
  15. Mutexs provide mutually exclusive access to resources.  Condition variables,
  16. when used with mutexes, provide synchronization between threads.
  17. The example below illustrates the use of a mutex.  The first step is to
  18. initialize the mutex (see mutex_init() for more details).
  19. .CS
  20. .ne 4
  21.     mutex_t mutex;
  22.     mutex_init (&mutex, ...);
  23. .CE
  24. Then guard a critical section or resource by taking the mutex with
  25. mutex_lock(), and exit the section or release the resource by giving the
  26. mutex with a mutex_unlock().  For example:
  27. .CS
  28. .ne 4
  29.     mutex_lock (&mutex);
  30. ... /@ critical region, only accessible by a single thread at a time @/
  31.     mutex_unlock (&mutex);
  32. .CE
  33. A condition variable works in conjunction with a mutex to provide
  34. synchronization between multiple threads. A thread will block at a
  35. call to cond_wait() and remain blocked until another thread signals
  36. the condition with a call to cond_signal().  A condition variable is
  37. considered a resource and must be protected with a mutex.
  38. See cond_wait() and cond_signal() for more details.
  39. The following example is for a one byte pipe.  The writer will sit on the
  40. pipe until it can write the data.  The reader will abort the read if a
  41. signal occurs.
  42. .CS
  43. .ne 4
  44.     struct pipe
  45.         {
  46.         mutex_t p_mutex;
  47.         cond_t  p_writer;
  48.         cond_t  p_reader;
  49.         int     p_empty;
  50.         char    p_data;
  51.         };
  52.     pipe_init (struct pipe *pPipe)
  53.         {
  54.         mutex_init (&pPipe->p_mutex, MUTEX_THREAD);
  55.         cond_init (&pPipe->p_reader, &pPipe->p_mutex);
  56.         cond_init (&pPipe->p_writer, &pPipe->p_mutex);
  57.         pPipe->p_empty = TRUE;
  58.         }
  59.     pipe_write (struct pipe *pPipe, char data)
  60.         {
  61.         mutex_lock (&pPipe->p_mutex);
  62.         while (pPipe->p_empty != TRUE)
  63.     cond_wait (&pPipe->p_writer, &pPipe->p_mutex, 0, "pipe write", 0);
  64.         pPipe->p_empty = FALSE;
  65.         pPipe->p_data = data;
  66. cond_signal (&pPipe->p_reader, &pPipe->p_mutex);
  67.         mutex_unlock (&pPipe->p_mutex);
  68.         }
  69.     pipe_read (struct pipe *pPipe)
  70.         {
  71.         char data;
  72.         int error;
  73.         mutex_lock (&pPipe->p_mutex);
  74.         while (pPipe->p_empty == TRUE)
  75.     {
  76.     error = cond_wait (&pPipe->p_reader, &pPipe->p_mutex,
  77. SIGCATCH, "pipe read", 0);
  78.             if (error != 0)
  79.                 {
  80. mutex_unlock (&pPipe->p_mutex);
  81.                 errno = error;
  82.                 return -1;
  83.                 }
  84.     }
  85.         pPipe->p_empty = TRUE;
  86.         data = pPipe->p_data;
  87. cond_signal (&pPipe->p_writer, &pPipe->p_mutex);
  88.         mutex_unlock (&pPipe->p_mutex);
  89. return data;
  90.         }
  91. .CE
  92. NOMANUAL
  93. */
  94. #include "vxWorks.h"
  95. #include "private/sigLibP.h"
  96. #include "private/mutexPxLibP.h"
  97. #include "private/windLibP.h"
  98. #include "private/eventP.h"
  99. #include "timers.h"
  100. #include "errno.h"
  101. #include "intLib.h"
  102. #include "sysLib.h"
  103. /* locals */
  104. /* globals */
  105. /*******************************************************************************
  106. *
  107. * mutex_init - initialize a kernel mutex
  108. *
  109. * This routine initializes a kernel mutex.
  110. *
  111. * NOMANUAL
  112. */
  113. void mutex_init
  114.     (
  115.     mutex_t     *pMutex,
  116.     void *dummy
  117.     )
  118.     {
  119.     pMutex->m_owner = 0;
  120.     qInit (&pMutex->m_queue, Q_PRI_LIST, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  121.     }
  122. /*******************************************************************************
  123. *
  124. * mutex_destroy - Destroy a kernel mutex
  125. *
  126. * This routine destroys a kernel mutex.
  127. *
  128. * NOMANUAL
  129. */
  130. void mutex_destroy
  131.     (
  132.     mutex_t *pMutex
  133.     )
  134.     {
  135.     kernelState = TRUE; /* ENTER KERNEL */
  136.     if (Q_FIRST (&pMutex->m_queue) != NULL)
  137. {
  138.         /* windview - level 2 event logging */
  139.         EVT_TASK_1 (EVENT_OBJ_SEMFLUSH, pMutex);
  140. windPendQFlush (&pMutex->m_queue);
  141. }
  142.     windExit(); /* EXIT KERNEL */
  143.     }
  144. /*******************************************************************************
  145. *
  146. * cond_init - initialize a kernel condition variable
  147. *
  148. * This routine initializes a kernel condition variable.
  149. *
  150. * NOMANUAL
  151. */
  152. void cond_init
  153.     (
  154.     cond_t *pCond,
  155.     void *pDummy
  156.     )
  157.     {
  158.     pCond->c_mutex = NULL;
  159.     qInit (&pCond->c_queue, Q_PRI_LIST, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  160.     }
  161. /*******************************************************************************
  162. *
  163. * cond_destroy - Destroy a kernel condition variable
  164. *
  165. * This routine destroys a kernel condition variable.
  166. *
  167. * NOMANUAL
  168. */
  169. void cond_destroy
  170.     (
  171.     cond_t *pCond
  172.     )
  173.     {
  174.     kernelState = TRUE; /* ENTER KERNEL */
  175.     if (Q_FIRST (&pCond->c_queue) != NULL)
  176. {
  177.         /* windview - level 2 event logging */
  178.         EVT_TASK_1 (EVENT_OBJ_SEMFLUSH, pCond);
  179. windPendQFlush (&pCond->c_queue);
  180. }
  181.     windExit(); /* EXIT KERNEL */
  182.     }
  183. /*******************************************************************************
  184. *
  185. * mutex_lock - Take a kernel mutex
  186. *
  187. * This routine takes a kernel mutex.
  188. *
  189. * NOMANUAL
  190. */
  191. void mutex_lock
  192.     (
  193.     mutex_t *pMutex
  194.     )
  195.     {
  196.     int level;
  197.     level = intLock (); /* LOCK INTERRUPTS */
  198.     if (pMutex->m_owner == NULL)
  199. {
  200. pMutex->m_owner = (int) taskIdCurrent;
  201. intUnlock (level); /* UNLOCK INTERRUPTS */
  202. return;
  203. }
  204.     kernelState = TRUE; /* ENTER KERNEL */
  205.     intUnlock (level); /* UNLOCK INTERRUPTS */
  206.     /* windview - level 2 event logging */
  207.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, pMutex);
  208.     windPendQPut (&pMutex->m_queue, WAIT_FOREVER);
  209.     windExit (); /* EXIT KERNEL */
  210.     }
  211. /*******************************************************************************
  212. *
  213. * mutex_unlock - Release a kernel mutex
  214. *
  215. * This routine releases a kernel mutex.
  216. *
  217. * NOMANUAL
  218. */
  219. void mutex_unlock
  220.     (
  221.     mutex_t *pMutex
  222.     )
  223.     {
  224.     int level;
  225.     if (pMutex->m_owner != (int) taskIdCurrent)
  226. return;
  227.     level = intLock (); /* LOCK INTERRUPTS */
  228.     if ((pMutex->m_owner = (int) Q_FIRST (&pMutex->m_queue)) != NULL)
  229. {
  230. kernelState = TRUE; /* ENTER KERNEL */
  231. intUnlock (level); /* UNLOCK INTERRRUPTS */
  232.         /* windview - level 2 event logging */
  233.         EVT_TASK_1 (EVENT_OBJ_SEMGIVE, pMutex);
  234. windPendQGet (&pMutex->m_queue);
  235. windExit (); /* EXIT KERNEL */
  236. }
  237.     else
  238. intUnlock (level); /* UNLOCK INTERRUPTS */
  239.     }
  240. /*******************************************************************************
  241. *
  242. * cond_signal - Signal a condition variable
  243. *
  244. * This routine signals a condition variable.  That is it will resume a
  245. * single thread that was suspended on a cond_wait().
  246. *
  247. * NOMANUAL
  248. */
  249. void cond_signal
  250.     (
  251.     cond_t *pCond
  252.     )
  253.     {
  254.     WIND_TCB *pTcb;
  255.     kernelState = TRUE; /* ENTER KERNEL */
  256.     if (Q_FIRST (&pCond->c_queue) != NULL)
  257. {
  258. if (pCond->c_mutex->m_owner == NULL)
  259.     {
  260.     pCond->c_mutex->m_owner = (int) Q_FIRST(&pCond->c_queue); 
  261.             /* windview - level 2 event logging */
  262.             EVT_TASK_1 (EVENT_OBJ_SEMGIVE, pCond);
  263.     windPendQGet (&pCond->c_queue);
  264.     }
  265. else
  266.     {
  267.     pTcb = (WIND_TCB *) Q_GET (&pCond->c_queue);
  268.     Q_PUT (&pCond->c_mutex->m_queue, pTcb, pTcb->priority);
  269.     }
  270. if (Q_FIRST (&pCond->c_queue) == NULL)
  271.     pCond->c_mutex = NULL;
  272. }
  273.     windExit(); /* EXIT KERNEL */
  274.     }
  275. /*******************************************************************************
  276. *
  277. * cond_timedwait - Wait on a condition variable
  278. *
  279. * This routine suspends the calling thread on the condition variable
  280. * pointed to by pCond.  The thread will resume when another thread signals
  281. * the condition variable using the function cond_signal().  The mutex
  282. * pointed to by pMutex must be owned by the calling thread.  While the
  283. * thread is suspended, the mutex will be given back.  When the thread
  284. * resumes, the mutex will be taken back.
  285. *
  286. * The argument pTimeout is optional.  If it is NULL, then cond_timedwait will
  287. * wait indefinitely.  If it is not NULL, then it points to a timespec
  288. * structure with the minimum time cond_timedwait should suspend the thread.
  289. * If the minimum time has been reached, then cond_timedwait() return EAGAIN.
  290. *
  291. * RETURNS
  292. * Cond_wait() returns 0 if another thread resumed it using cond_signal().
  293. * Otherwise it returns EINTR if a signal occured during the wait or EAGAIN
  294. * if the time expired.  In all cases the mutex pMutex is given during the
  295. * time suspended are taken back when the function returns.
  296. *
  297. * NOMANUAL
  298. */
  299. int cond_timedwait
  300.     (
  301.     cond_t *pCond, /* Cond to wait on */
  302.     mutex_t *pMutex, /* Mutex to give */
  303.     const struct timespec *pTimeout /* max time to wait */
  304.     )
  305.     {
  306.     int tickRate;
  307.     int wait;
  308.     int retval;
  309.     if (pTimeout != 0)
  310. {
  311. tickRate = sysClkRateGet();
  312. wait = pTimeout->tv_sec * tickRate +
  313. pTimeout->tv_nsec / (1000000000 / tickRate);
  314. }
  315.     else
  316. wait = WAIT_FOREVER;
  317.     kernelState = TRUE; /* ENTER KERNEL */
  318.     if (pCond->c_mutex != 0 && pCond->c_mutex != pMutex)
  319. {
  320. windExit(); /* EXIT KERNEL */
  321. return (EINVAL);
  322. }
  323.     pCond->c_mutex = pMutex;
  324.     /* windview - level 2 event logging */
  325.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, pCond);
  326.     windPendQPut (&pCond->c_queue, wait);
  327.     if ((pMutex->m_owner = (int) Q_FIRST (&pMutex->m_queue)) != NULL)
  328. {
  329.         /* windview - level 2 event logging */
  330.         EVT_TASK_1 (EVENT_OBJ_SEMGIVE, pMutex);
  331. windPendQGet (&pMutex->m_queue);
  332. }
  333.     if ((retval = windExit ()) != 0) /* EXIT KERNEL */
  334. {
  335. mutex_lock(pMutex);
  336. return (retval == RESTART) ? EINTR : EAGAIN;
  337. }
  338.     return (0);
  339.     }