📄 sempxlib.c
字号:
/* semPxLib.c - semaphore synchronization library (POSIX) *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01l,17jul00,jgn merge DOT-4 pthreads changes01k,03feb95,rhp strengthen warning re semaphore deletion01j,25jan95,rhp restructure library man page, other doc tweaks. 19jan95,jdi doc cleanup.01i,08apr94,dvs changed semClass to semPxClass (SCD #3119).01h,08apr94,dvs fixed error in args when calling symFindByName (SCD #3091).01g,01feb94,dvs documentation cleanup.01f,12jan94,kdl changed semaphoreInit() to semPxLibInit().01e,05jan94,kdl changed param names to match POSIX spec; changed sem_t "close" field to "refCnt"; general cleanup.01d,21dec93,kdl made sem_destroy() return error if sem has tasks blocked.01c,13dec93,dvs added initialization of posix name tbl in semaphoreInit(). +rrr fixed sem_open bug01b,15nov93,dvs initial cleanup01a,06apr93,smb created*//*DESCRIPTION:This library implements the POSIX 1003.1b semaphore interface. Foralternative semaphore routines designed expressly for VxWorks, seethe manual page for semLib and other semaphore librariesmentioned there. POSIX semaphores are counting semaphores; assuch they are most similar to the semCLib VxWorks-specific semaphores.The main advantage of POSIX semaphores is portability (to the extentthat alternative operating systems also provide these POSIXinterfaces). However, VxWorks-specific semaphores providethe following features absent from the semaphores implemented in thislibrary: priority inheritance, task-deletion safety, the ability for asingle task to take a semaphore multiple times, ownership ofmutual-exclusion semaphores, semaphore timeout, and the choice ofqueuing mechanism.POSIX defines both named and unnamed semaphores; semPxLib includesseparate routines for creating and deleting each kind. For otheroperations, applications use the same routines for both kinds ofsemaphore.TERMINOLOGYThe POSIX standard uses the terms \f2wait\f1 or \f2lock\f1 where\f2take\f1 is normally used in VxWorks, and the terms \f2post\f1 or\f2unlock\f1 where \f2give\f1 is normally used in VxWorks. VxWorksdocumentation that is specific to the POSIX interfaces (such as theremainder of this manual entry, and the manual entries for subroutinesin this library) uses the POSIX terminology, in order to make iteasier to read in conjunction with other references on POSIX.SEMAPHORE DELETIONThe sem_destroy() call terminates an unnamed semaphore and deallocatesany associated memory; the combination of sem_close() and sem_unlink()has the same effect for named semaphores. Take care when deletingsemaphores, particularly those used for mutual exclusion, to avoiddeleting a semaphore out from under a task that has already lockedthat semaphore. Applications should adopt the protocol of onlydeleting semaphores that the deleting task has successfully locked.(Similarly, for named semaphores, applications should take care toonly close semaphores that the closing task has opened.)If there are tasks blocked waiting for the semaphore, sem_destroy()fails and sets `errno' to EBUSY.INTERNAL:POSIX indicates that semaphores may be implemented using a filedescriptor. I have chosen not to include this functionality in thisimplementation of semaphores. POSIX specs do not insist on a file descriptor implementation.There is an attempt to deal with the issues of a task connecting to a semaphore and the persistence of that semaphore. Persistence implies thata semaphore and its associated state remains valid until the reference isreleased. Ref. sem_close() and sem_unlink().Detection of deadlock is not considered in this implementation. POSIXconsiders the issue but does not require it to be addressed for POSIX.The routines in this library are compliant to POSIX 1003.4 draft 14.INCLUDE FILES: semaphore.hSEE ALSO: POSIX 1003.1b document, semLib, .pG "Basic OS"*/#include "vxWorks.h"#include "errno.h"#include "semaphore.h"#include "semLib.h"#include "symLib.h"#include "posixName.h"#include "fcntl.h"#include "taskLib.h"#include "stdarg.h"#include "symSync.h"#include "string.h"#include "objLib.h"#include "qLib.h"#define __PTHREAD_SRC#include "pthread.h" /* defines */#define MAX_TASKS 100/* locals */LOCAL OBJ_CLASS semPxClass; /* sem object class */LOCAL BOOL semInitialized;CLASS_ID semPxClassId = &semPxClass; /* sem class id *//********************************************************************************* semPxLibInit - initialize POSIX semaphore support** This routine must be called before using POSIX semaphores.** RETURNS: OK, or ERROR if there is an error installing the semaphore library.*/STATUS semPxLibInit (void) { if ((!semInitialized) && (classInit (semPxClassId, sizeof (struct sem_des), OFFSET (struct sem_des, objCore), (FUNCPTR) NULL, (FUNCPTR) NULL, (FUNCPTR) NULL) == OK)) { /* initialize the posix name table */ posixNameTblInit (0); /* use default hashing */ /* init counting semaphore library */ if (semCLibInit () == ERROR) { return (ERROR); } semInitialized = TRUE; /* we've finished the initialization */ } return (OK); }/********************************************************************************* sem_init - initialize an unnamed semaphore (POSIX)** This routine is used to initialize the unnamed semaphore <sem>.* The value of the initialized semaphore is <value>. Following a successful* call to sem_init() the semaphore may be used in subsequent calls to* sem_wait(), sem_trywait(), and sem_post(). This semaphore remains usable* until the semaphore is destroyed.** The <pshared> parameter currently has no effect.** Only <sem> itself may be used for synchronization.** RETURNS: 0 (OK), or -1 (ERROR) if unsuccessful.** ERRNO:* EINVAL* - <value> exceeds SEM_VALUE_MAX.* ENOSPC * - unable to initialize semaphore due to resource constraints.* * SEE ALSO: sem_wait(), sem_trywait(), sem_post()**/int sem_init ( sem_t * sem, /* semaphore to be initialized */ int pshared, /* process sharing */ unsigned int value /* semaphore initialization value */ ) { /* validate value */ if (value > SEM_VALUE_MAX) { errno = EINVAL; return (ERROR); } /* initialize the semaphore library */ if (semPxLibInit () == OK) { /* create semaphore */ if ((sem->semId = semCCreate (SEM_Q_PRIORITY, value)) == NULL) { errno = ENOSPC; return (ERROR); } sem->sem_name = NULL; /* init the structure */ objCoreInit (&sem->objCore, semPxClassId); /* validate object */ } else { errno = ENOSPC; return (ERROR); } return (OK); }/********************************************************************************* sem_destroy - destroy an unnamed semaphore (POSIX)** This routine is used to destroy the unnamed semaphore indicated by <sem>.** The sem_destroy() call can only destroy a semaphore created by sem_init().* Calling sem_destroy() with a named semaphore will cause a EINVAL error.* Subsequent use of the <sem> semaphore will cause an EINVAL error in the* calling function.** If one or more tasks is blocked on the semaphore, the semaphore is not* destroyed.* * WARNING* Take care when deleting semaphores, particularly those used for* mutual exclusion, to avoid deleting a semaphore out from under a* task that has already locked that semaphore. Applications should* adopt the protocol of only deleting semaphores that the deleting* task has successfully locked.* * RETURNS: 0 (OK), or -1 (ERROR) if unsuccessful.** ERRNO:* EINVAL * - invalid semaphore descriptor.* EBUSY* - one or more tasks is blocked on the semaphore.* * SEE ALSO: sem_init()**/int sem_destroy ( sem_t * sem /* semaphore descriptor */ ) { taskLock (); /* TASK LOCK */ if (OBJ_VERIFY (sem, semPxClassId) != OK) { taskUnlock (); /* TASK UNLOCK */ errno = EINVAL; return (ERROR); /* invalid object */ } if (sem->sem_name != NULL) /* close via sem_close/unlink */ { taskUnlock (); /* TASK UNLOCK */ errno = EINVAL; return (ERROR); } if (qFirst (&(sem->semId->qHead)) != NULL) { taskUnlock (); /* TASK UNLOCK */ errno = EBUSY; return (ERROR); /* someone waiting on sem */ } objCoreTerminate (&sem->objCore); /* terminate object */ semDelete (sem->semId); taskUnlock (); /* TASK UNLOCK */ return (OK); }/********************************************************************************* sem_open - initialize/open a named semaphore (POSIX)** This routine establishes a connection between a named semaphore and* a task. Following a call to sem_open() with a semaphore name <name>,* the task may reference the semaphore associated with <name> using* the address returned by this call. This semaphore may be used in * subsequent calls to sem_wait(), sem_trywait(), and sem_post(). The * semaphore remains usable until the semaphore is closed by a successful* call to sem_close(). ** The <oflag> argument controls whether the semaphore is created or merely* accessed by the call to sem_open(). The following flag bits may be set* in <oflag>:** .iP O_CREAT* Use this flag to create a semaphore if it does not already exist. If* O_CREAT is set and the semaphore already exists, O_CREAT has no effect* except as noted below under O_EXCL. Otherwise, sem_open() creats a* semaphore. O_CREAT requires a third and fourth argument: <mode>, which is* of type mode_t, and <value>, which is of type unsigned int. <mode> has no* effect in this implementation. The semaphore is created with an initial* value of <value>. Valid initial values for semaphores must be less than* or equal to SEM_VALUE_MAX.** .iP O_EXCL* If O_EXCL and O_CREAT are set, sem_open() will fail if the semaphore name* exists. If O_EXCL is set and O_CREAT is not set, the named semaphore * is not created.* .LP* * To determine whether a named semaphore already exists in the system,* call sem_open() with the flags `O_CREAT | O_EXCL'. If the* sem_open() call fails, the semaphore exists.* * If a task makes multiple calls to sem_open() with the same value* for <name>, then the same semaphore address is returned for each such* call, provided that there have been no calls to sem_unlink()* for this semaphore.** References to copies of the semaphore will produce undefined results.** NOTE* The current implementation has the following limitations:** - A semaphore cannot be closed with calls to _exit() or exec().* - A semaphore cannot be implemented as a file.* - Semaphore names will not appear in the file system. ** RETURNS: A pointer to sem_t, or -1 (ERROR) if unsuccessful. ** ERRNO:* EEXIST* - O_CREAT | O_EXCL are set and the semaphore already exists.* EINVAL* - <value> exceeds SEM_VALUE_MAX or the semaphore name is invalid.* ENAMETOOLONG* - the semaphore name is too long.* ENOENT* - the named semaphore does not exist and O_CREAT is not set.* ENOSPC* - the semaphore could not be initialized due to resource constraints.** SEE ALSO: sem_unlink()** INTERNAL:* Note that if the sem already exists and O_CREAT is not set then this call* has no effect. If the sem does not exist and only the O_EXCL flag* is set then ENOENT is set and an -1 returned. These are not clear from the * POSIX specifications.**/sem_t * sem_open ( const char * name, /* semaphore name */ int oflag, /* semaphore creation flags */ ... /* extra optional parameters */ ) { va_list vaList; /* traverses argument list */ mode_t mode; /* mode of semaphore */ unsigned int value; /* initial value of semaphore */ sem_t * pSemDesc; /* semaphore descriptor */ BOOL found = FALSE; /* find named object */ void * pPool = NULL; /* area for name */ SYM_TYPE dummy; /* dummy var for calling symFindByName */ #if _POSIX_NO_TRUNC /* check name length */ if (strlen (name) > NAME_MAX) { errno = ENAMETOOLONG; return ((sem_t *) ERROR); }#endif /* Initialize semaphore library */ if (semPxLibInit () == ERROR) { errno = ENOSPC; return ((sem_t *) ERROR); } /* The following symTblLock is used to insure that no other task * can create a semaphore of the same name as this one. This * could have occurred if another task tried to access the name table * between symFindByName returning not found and the name being * added to the name table via symAdd. */ symTblLock (posixNameTbl); /* LOCK NAME TABLE */ if (symFindByName (posixNameTbl, (char *) name, (char **) &pSemDesc, &dummy) == OK) { found = TRUE; } if (found) /* found */ { if (O_EXCL & oflag) { symTblUnlock (posixNameTbl); /* UNLOCK NAME TABLE */ errno = EEXIST; return ((sem_t *) ERROR); } else { symTblUnlock (posixNameTbl); /* UNLOCK NAME TABLE */ /* validate semaphore descriptor */ if (OBJ_VERIFY (pSemDesc, semPxClassId) != 0) { errno = EINVAL; return ((sem_t *) ERROR); } pSemDesc->refCnt++; /* attach */ return (pSemDesc); } } else /* not found */ if (!(O_CREAT & oflag)) /* if not creating */ { symTblUnlock (posixNameTbl); /* UNLOCK NAME TABLE */ errno = ENOENT; return ((sem_t *) ERROR); } /* retrieve optional parameters */ va_start (vaList, oflag); mode = va_arg (vaList, mode_t); value = va_arg (vaList, uint_t); va_end (vaList); /* validate parameter */ if (value > SEM_VALUE_MAX) { symTblUnlock (posixNameTbl); /* UNLOCK NAME TABLE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -