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

VxWorks

开发平台:

C/C++

  1. /* _pthreadLib.c - POSIX 1003.1c thread library kernel support */
  2. /* Copyright 1984-2002 Wind River Systems, Inc.  */
  3. /* Copyright (c) 1995 by Dot4, Inc. */
  4. #include "copyright_wrs.h"
  5. /*
  6. modification history
  7. --------------------
  8. 01f,03may02,gls  fixed memory leak when user specifies stack (SPR #76769)
  9. 01e,22apr02,gls  removed references to AE in comments (SPR #75799)
  10. 01d,26nov01,gls  changed stackAddr to char * for DIAB support
  11. 01c,31oct01,jgn  fix rounding of stack size (SPR #71350)
  12. 01b,22oct01,jgn  correct scheduling policy inheritance (SPR #71125)
  13. 01a,10sep00,jgn  created from pthreadLib.c version 01c (SPR #33375) +
  14.  ensure TCB pdId set always (SPR #33711)
  15. */
  16. /*
  17. DESCRIPTION
  18. Kernel support routines for the VxWorks pthreads implementation. 
  19. NOMANUAL
  20. */
  21. /* includes */
  22. #include "vxWorks.h"
  23. #include "intLib.h"
  24. #include "kernelLib.h"
  25. #include "private/schedP.h"
  26. #include "private/taskLibP.h"
  27. #include "pthread.h"
  28. #include "semLib.h"
  29. #include "string.h"
  30. #include "taskLib.h"
  31. #include "taskArchLib.h"
  32. #include "taskHookLib.h"
  33. #include "limits.h"
  34. #undef PTHREADS_DEBUG
  35. #ifdef PTHREADS_DEBUG
  36. #undef LOCAL
  37. #define LOCAL
  38. #endif
  39. /* defines */
  40. #define DEF_STACK_SIZE  (20 * 1024)
  41. #define MY_PTHREAD ((internalPthread *)(taskIdCurrent->pPthread))
  42. #define CANCEL_LOCK(pThread)    semTake((pThread)->cancelSemId, WAIT_FOREVER)
  43. #define CANCEL_UNLOCK(pThread)  semGive((pThread)->cancelSemId)
  44. /*
  45.  * Need copies of these since we are going to have to pass in the current
  46.  * PD's numbering scheme to _pthreadCreate() and can't use the existing
  47.  * global variable that the original macros use...
  48.  */
  49. #define PX_VX_PRI_CONV(mode,pri) (mode ? (POSIX_HIGH_PRI - pri) : pri)
  50. /* locals */
  51. LOCAL BOOL pthreadLibInited = FALSE;
  52. LOCAL FUNCPTR pthreadDeleteTaskEntry = NULL;
  53. LOCAL pthread_attr_t defaultPthreadAttr =                               
  54.     {                                                                   
  55.     PTHREAD_INITIALIZED,        /* object status      */                
  56.     ((size_t) 0),               /* stacksize          */                
  57.     NULL,                       /* stackaddr          */                
  58.     PTHREAD_CREATE_JOINABLE,    /* detachstate        */                
  59.     PTHREAD_SCOPE_SYSTEM,       /* contentionscope    */                
  60.     PTHREAD_INHERIT_SCHED,      /* inheritsched       */                
  61.     SCHED_RR,                   /* schedpolicy        */                
  62.     NULL,                       /* name               */                
  63.     {0},                        /* struct sched_param */                
  64.     };
  65. /* externals */
  66. IMPORT BOOL vxTas (void *addr);
  67. IMPORT BOOL roundRobinOn;
  68. IMPORT ULONG roundRobinSlice;
  69. /* forward references */
  70. LOCAL void deleteHook (WIND_TCB *pTcb);
  71. /*******************************************************************************
  72. *
  73. * _pthreadLibInit - initialize POSIX threads support
  74. *
  75. * This routine initializes the POSIX threads (<pthreads>) support for
  76. * VxWorks. It should only be called via pthreadLibInit() since it needs to
  77. * register the delete hook's user level function.
  78. *
  79. * Multiple attempts to initialise are ignored, but the delete hook function will
  80. * be changed. This is to ensure that if the user level code is replaced then
  81. * the new function pointer will be available.
  82. *
  83. * RETURNS: N/A
  84. *
  85. * NOMANUAL
  86. */
  87. STATUS _pthreadLibInit
  88.     (
  89.     FUNCPTR deleteTask /* user level code for delete hook */
  90.     )
  91.     {
  92.     /* Always store this in case it is simply being changed */
  93.     pthreadDeleteTaskEntry = deleteTask;
  94.     taskLock();
  95.     if (pthreadLibInited)
  96. {
  97. taskUnlock();
  98. return OK;
  99. }
  100.     if (taskDeleteHookAdd((FUNCPTR) deleteHook) == ERROR)
  101. {
  102. if (_func_logMsg != NULL)
  103.     _func_logMsg ("taskDeleteHookAdd of pthread deleteHook failed!n",
  104.   0, 0, 0, 0, 0, 0);
  105. }
  106.     else
  107. {
  108. pthreadLibInited = TRUE;
  109. _func_pthread_setcanceltype = _pthreadSetCancelType;
  110. }
  111.     taskUnlock();
  112.     return ((pthreadLibInited == TRUE) ? OK : ERROR);
  113.     }
  114. /*
  115.  * Section 16 - Thread Management
  116.  */
  117. /*******************************************************************************
  118. *
  119. * _pthreadCreate - create a thread (POSIX)
  120. *
  121. * This is the actual thread creation function. It is called by the user level
  122. * pthread_create() function.
  123. *
  124. * NOMANUAL
  125. */
  126. int _pthreadCreate
  127.     (
  128.     pthread_t * pThread,
  129.     const pthread_attr_t * pAttr,
  130.     void * (*wrapperFunc)(void *),
  131.     void * (*start_routine)(void *),
  132.     void * arg,
  133.     int priNumMode
  134.     )
  135.     {
  136.     char name[NAME_MAX];
  137.     char *      pBufStart;      /* points to temp name buffer start */
  138.     char *      pBufEnd;        /* points to temp name buffer end */
  139.     char        temp;           /* working character */
  140.     int         value;          /* working value to convert to ascii */
  141.     int         nPreBytes;      /* nameless prefix string length */
  142.     int         nBytes    = 0;  /* working nameless name string length */
  143.     static int namecntr = {0};
  144.     static char * prefix = "pthr";
  145.     static char *digits = "0123456789";
  146.     WIND_TCB * pTcb;
  147.     internalPthread * pMyThread;
  148.     char * stackaddr = NULL;
  149.     int stacksize;
  150.     if (!pThread)
  151. return (EINVAL);
  152.     if (!pthreadLibInited)
  153. return (EINVAL);
  154.     if (pAttr && pAttr->threadAttrStatus != PTHREAD_INITIALIZED)
  155. return (EINVAL);
  156.     else if (!pAttr)
  157. pAttr = &defaultPthreadAttr;
  158.     /*
  159.      * Make sure that sched policy is supported, valid, and matches global
  160.      * policy. Only perform this test if the inheritsched attribute is set
  161.      * to PTHREAD_EXPLICIT_SCHED though; if we are inheriting then we'll get
  162.      * it right by definition (no need to worry about finding out the current
  163.      * policy since for VxWorks it is system-wide).
  164.      */
  165.     if (pAttr->threadAttrInheritsched == PTHREAD_EXPLICIT_SCHED)
  166. {
  167. if ((pAttr->threadAttrSchedpolicy == SCHED_OTHER) ||
  168.     ((roundRobinOn == TRUE) &&
  169.   (pAttr->threadAttrSchedpolicy != SCHED_RR)) ||
  170.     ((roundRobinOn == FALSE) &&
  171.   (pAttr->threadAttrSchedpolicy != SCHED_FIFO)))
  172.     {
  173.     errno = ENOTTY;
  174.     return (ENOTTY);
  175.     }
  176. }
  177.     if (!(pMyThread = malloc(sizeof (internalPthread))))
  178. return (EAGAIN);
  179.     bzero((char *)pMyThread, sizeof (internalPthread));
  180.     /*
  181.      * If zero is specified, use the default stack size, otherwise use the
  182.      * specified size, rounded up to PTHREAD_STACK_MIN if necessary.
  183.      */
  184.     if (pAttr->threadAttrStacksize == 0)
  185. {
  186. stacksize = DEF_STACK_SIZE;
  187. }
  188.     else
  189. {
  190. stacksize = max(pAttr->threadAttrStacksize, PTHREAD_STACK_MIN);
  191. }
  192.     if (pAttr->threadAttrStackaddr)
  193. {
  194. pMyThread->flags |= STACK_PASSED_IN;
  195. stackaddr = pAttr->threadAttrStackaddr;
  196. }
  197.     if (pAttr->threadAttrDetachstate == PTHREAD_CREATE_JOINABLE)
  198. {
  199. pMyThread->flags |= JOINABLE;
  200. if ((pMyThread->exitJoinSemId = semBCreate(SEM_Q_PRIORITY,
  201.    SEM_EMPTY)) == NULL)
  202.     {
  203.     free(pMyThread);
  204.     return (EAGAIN);
  205.     }
  206. }
  207.     if ((pMyThread->mutexSemId =
  208. semMCreate(SEM_Q_PRIORITY|SEM_INVERSION_SAFE)) == NULL)
  209. {
  210. semDelete(pMyThread->exitJoinSemId);
  211. free(pMyThread);
  212. return (EAGAIN);
  213. }
  214.     if ((pMyThread->cancelSemId =
  215. semMCreate(SEM_Q_PRIORITY|SEM_INVERSION_SAFE)) == NULL)
  216. {
  217. semDelete(pMyThread->mutexSemId);
  218. semDelete(pMyThread->exitJoinSemId);
  219. free(pMyThread);
  220. return (EAGAIN);
  221. }
  222.     /* create name for the task */
  223.     if (pAttr && pAttr->threadAttrName == NULL) 
  224.       {
  225.       strcpy (name, prefix);                  /* copy in prefix */
  226.       nBytes = strlen (name);                 /* calculate prefix length */
  227.       nPreBytes = nBytes;                     /* remember prefix strlen() */
  228.       value  = ++ namecntr;                   /* bump the nameless count */
  229.  
  230.       do                                      /* crank out digits backwards */
  231.   {
  232.   name [nBytes++] = digits [value % 10];
  233.   value /= 10;                              /* next digit */
  234.   }
  235.       while (value != 0);                           /* until no more digits */
  236.  
  237.       pBufStart = name + nPreBytes;        /* start reverse after prefix */
  238.       pBufEnd   = name + nBytes - 1;       /* end reverse at EOS */
  239.  
  240.       while (pBufStart < pBufEnd)          /* reverse the digits */
  241.   {
  242.   temp        = *pBufStart;
  243.   *pBufStart  = *pBufEnd;
  244.   *pBufEnd    = temp;
  245.   pBufEnd--;
  246.   pBufStart++;
  247.   }
  248.       name[nBytes] = EOS;                      /* EOS terminate string */
  249.       } 
  250.   
  251.   else 
  252.       {
  253.       strncpy(name, pAttr->threadAttrName, NAME_MAX - 1);
  254.       name[NAME_MAX - 1] = EOS;
  255.       }
  256.     /*
  257.      * Determine the priority. This is also based on the inheritsched
  258.      * attribute; we handled the scheduling policy inheritance above.
  259.      */
  260.     if (pAttr->threadAttrInheritsched == PTHREAD_INHERIT_SCHED)
  261. {
  262. taskPriorityGet(taskIdSelf(), &pMyThread->priority);
  263. /* Convert to POSIX format */
  264. pMyThread->priority = PX_VX_PRI_CONV (priNumMode, pMyThread->priority);
  265. }
  266.     else
  267. pMyThread->priority = pAttr->threadAttrSchedparam.sched_priority;
  268.     if (!(pMyThread->flags & STACK_PASSED_IN))
  269. {
  270. if (!(pTcb = (WIND_TCB *)taskCreat(name, 
  271.          PX_VX_PRI_CONV(priNumMode, pMyThread->priority),
  272.  VX_FP_TASK,
  273.  stacksize, 
  274.  (FUNCPTR) wrapperFunc, 
  275.  (int)start_routine, 
  276.  (int)arg,
  277.  0, 0, 0, 0, 0, 0, 0, 0)))
  278.     {
  279.     if (pMyThread->flags & JOINABLE)
  280. semDelete(pMyThread->exitJoinSemId);
  281.     semDelete(pMyThread->mutexSemId);
  282.     free(pMyThread);
  283.     return (EAGAIN);
  284.     }
  285. }
  286.     else
  287. {
  288. /*
  289.  * Since we have a passed in stack pointer, we need to do what
  290.  * taskCreat() does, and put the TCB on the stack.
  291.  */
  292. #if     (_STACK_DIR == _STACK_GROWS_DOWN)
  293. /*
  294.  * A portion of the very top of the stack is clobbered with a
  295.  * FREE_BLOCK in the objFree() associated with taskDestroy().
  296.  * There is no adverse consequence of this, and is thus not 
  297.  * accounted for.
  298.  *
  299.  * Given we set the stacksize above there is no need to check that
  300.  * there is enough room on the stack for the tcb.  There will be
  301.  */
  302. stackaddr = (char *) STACK_ROUND_DOWN (stackaddr +  stacksize - 
  303.        sizeof(WIND_TCB));
  304. pTcb = (WIND_TCB *) stackaddr;
  305. /* 
  306.  * We must adjust the stacksize as well.  However, because of the
  307.  * STACK_ROUND_DOWN the cleanest way to calculate this is to compare
  308.  * the original stack address to the new stack address.
  309.  */
  310. stacksize = ((UINT) stackaddr - (UINT) pAttr->threadAttrStackaddr);
  311. #else /* _STACK_GROWS_UP */
  312. #warning "Exception stack growing up not tested"
  313. /*
  314.  * To protect a portion of the WIND_TCB that is clobbered with a
  315.  * FREE_BLOCK in the objFree() associated with taskDestroy(),
  316.  * we goose the base of tcb by 16 bytes.
  317.  *
  318.  * Given we set the stacksize above there is no need to check that
  319.  * there is enough room on the stack for the tcb.  There will be
  320.  */
  321. pTcb = (WIND_TCB *) (stackaddr + 16);
  322. stackaddr = (char *) STACK_ROUND_UP (stackaddr + 16 + 
  323.       sizeof(WIND_TCB));
  324. /* 
  325.  * We must adjust the stacksize as well.  However, because of the
  326.  * STACK_ROUND_UP the cleanest way to calculate this is to compare
  327.  * the original stack address to the new stack address before 
  328.  * subtracting from the stacksize.
  329.  */
  330. stacksize = (stacksize - ((UINT) stackaddr - 
  331.   (UINT) pAttr->threadAttrStackaddr));
  332. #endif
  333. if (taskInit(pTcb, name,
  334.      PX_VX_PRI_CONV(priNumMode, pMyThread->priority),
  335.      (VX_FP_TASK | VX_NO_STACK_FILL), stackaddr, stacksize,
  336.      (FUNCPTR) wrapperFunc, (int)start_routine, (int)arg,
  337.      0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
  338.     {
  339.     if (pMyThread->flags & JOINABLE)
  340. semDelete(pMyThread->exitJoinSemId);
  341.     semDelete(pMyThread->mutexSemId);
  342.     free(pMyThread);
  343.     return (EAGAIN);
  344.     }
  345. }
  346.     pTcb->pPthread = pMyThread;
  347.     pMyThread->privateData = NULL;
  348.     pMyThread->handlerBase = NULL;
  349.     pMyThread->cancelstate = PTHREAD_CANCEL_ENABLE;
  350.     pMyThread->canceltype = PTHREAD_CANCEL_DEFERRED;
  351.     pMyThread->cancelrequest = 0;
  352.     pMyThread->taskId = (int)pTcb;
  353.     pMyThread->flags |= VALID;
  354.     taskActivate((int)pTcb);
  355.     *pThread = (pthread_t)pMyThread;
  356.     return (_RETURN_PTHREAD_SUCCESS);
  357.     }
  358. /*
  359.  * Section 18 - Thread Cancellation
  360.  */
  361. /*******************************************************************************
  362. *
  363. * _pthreadSetCancelType - set cancellation type for calling thread
  364. *
  365. * This is the kernel support routine for pthread_setcanceltype(). It is here
  366. * so that kernel libraries (such as the I/O system code) can make calls to it.
  367. *
  368. * The public API, pthread_setcanceltype(), is simply a call to this routine.
  369. *
  370. * RETURNS: On success zero; on failure a non-zero error code.
  371. *
  372. * ERRNOS: EINVAL
  373. *
  374. * SEE ALSO: pthread_setcanceltype(),
  375. */
  376. int _pthreadSetCancelType
  377.     (
  378.     int type,                   /* new type             */
  379.     int *oldtype                /* old type (out)       */
  380.     )
  381.     {
  382.     internalPthread *   pThread = MY_PTHREAD;
  383.     sigset_t            set;
  384.     sigset_t *          pset    = &set;
  385.     if (!pthreadLibInited || !pThread)
  386.         return (0);
  387. #if 0
  388.     self_become_pthread();
  389. #endif
  390.     if (type != PTHREAD_CANCEL_ASYNCHRONOUS && type != PTHREAD_CANCEL_DEFERRED)
  391.         {
  392.         return (EINVAL);
  393.         }
  394.     sigemptyset(pset);
  395.     sigaddset(pset, SIGCANCEL);
  396.     sigprocmask(SIG_BLOCK, pset, NULL);
  397.     CANCEL_LOCK(pThread);
  398.  
  399.     /* If the oldtype is required, save it now */
  400.  
  401.     if (oldtype != NULL)
  402.         *oldtype = pThread->canceltype;
  403.  
  404.     pThread->canceltype = type;
  405.  
  406.     CANCEL_UNLOCK(pThread);
  407.     sigprocmask(SIG_UNBLOCK, pset, NULL);
  408.     return (0);
  409.     }
  410. /*******************************************************************************
  411. *
  412. * deleteHook -
  413. *
  414. * Catch all for abnormally terminating pthreads, and those threads that
  415. * don't call pthread_exit to terminate.
  416. *
  417. * RETURNS:
  418. *
  419. * NOMANUAL
  420. */
  421. LOCAL void deleteHook
  422.     (
  423.     WIND_TCB *pTcb
  424.     )
  425.     {
  426.     if ((pthreadDeleteTaskEntry == NULL) || /* not initialised */
  427. (pTcb->pPthread == NULL)) /* task not a thread */
  428. return;
  429.     pthreadDeleteTaskEntry (pTcb->pPthread);
  430.     }
  431. /*******************************************************************************
  432. *
  433. * _pthreadSemOwnerGet - return the owner of a WIND semaphore
  434. *
  435. * Returns the owner task ID of a semaphore. This is only valid for mutex and
  436. * binary semaphores, but no attempt is made by the routine to check this. It is
  437. * the caller's responsibility to ensure that it is only called for correct
  438. * type of semaphore.
  439. *
  440. * RETURNS: task ID of owner, NULL if not owned, or ERROR if the semaphore ID
  441. * is invalid.
  442. *
  443. * SEE ALSO: _pthreadSemStateGet()
  444. *
  445. * NOMANUAL
  446. */
  447.  
  448. int _pthreadSemOwnerGet
  449.     (
  450.     SEM_ID      semId
  451.     )
  452.     {
  453.     int owner;
  454.     int level = intLock ();                     /* LOCK INTERRUPTS */
  455.  
  456.     if (OBJ_VERIFY (semId, semClassId) != OK)
  457.         {
  458.         intUnlock (level);                      /* UNLOCK INTERRUPTS */
  459.         return (ERROR);
  460.         }
  461.  
  462.     owner = (int) semId->semOwner;
  463.  
  464.     intUnlock (level);
  465.     return owner;
  466.     }
  467.  
  468. /*******************************************************************************
  469. *
  470. * _pthreadSemStateGet - return the state of a semaphore
  471. *
  472. * Returns the state of a semaphore. This will be zero or non-zero for mutex and
  473. * binary semaphores, meaning empty/not owned and full/owned respectively. For
  474. * counting semaphores the current count will be returned.
  475. *
  476. * RETURNS: current state of semaphore
  477. *
  478. * SEE ALSO: _pthreadSemOwnerGet()
  479. *
  480. * NOMANUAL
  481. */
  482.  
  483. int _pthreadSemStateGet
  484.     (
  485.     SEM_ID      semId
  486.     )
  487.     {
  488.     int state;
  489.     int level = intLock ();                     /* LOCK INTERRUPTS */
  490.  
  491.     if (OBJ_VERIFY (semId, semClassId) != OK)
  492.         {
  493.         intUnlock (level);                      /* UNLOCK INTERRUPTS */
  494.         return (ERROR);
  495.         }
  496.  
  497.     if ((semId->semType == (UINT8) SEM_TYPE_BINARY) ||
  498.         (semId->semType == (UINT8) SEM_TYPE_MUTEX))
  499.         {
  500.         state = (semId->semOwner == NULL) ? 0 : 1;
  501.         }
  502.     else if (semId->semType == (UINT8) SEM_TYPE_COUNTING)
  503.         {
  504.         state = semId->state.count;
  505.         }
  506.     else
  507.         {
  508.         /* "Old" semaphore, or just invalid */
  509.  
  510.         state = ERROR;
  511.         }
  512.  
  513.     intUnlock (level);
  514.     return state;
  515.     }