epicsMutexOSD * epicsMutexOsdCreate(void) { epicsMutexOSD *pmutex; int status; pmutex = callocMustSucceed(1, sizeof(*pmutex), "epicsMutexOsdCreate"); status = pthread_mutexattr_init(&pmutex->mutexAttr); checkStatusQuit(status, "pthread_mutexattr_init", "epicsMutexOsdCreate"); #if defined _POSIX_THREAD_PRIO_INHERIT status = pthread_mutexattr_setprotocol( &pmutex->mutexAttr,PTHREAD_PRIO_INHERIT); if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal"); #endif /*_POSIX_THREAD_PRIO_INHERIT*/ status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr); checkStatusQuit(status, "pthread_mutex_init", "epicsMutexOsdCreate"); #if defined _POSIX_THREAD_PROCESS_SHARED status = pthread_condattr_init(&pmutex->condAttr); checkStatus(status, "pthread_condattr_init"); status = pthread_condattr_setpshared(&pmutex->condAttr, PTHREAD_PROCESS_PRIVATE); checkStatus(status, "pthread_condattr_setpshared"); status = pthread_cond_init(&pmutex->waitToBeOwner, &pmutex->condAttr); #else status = pthread_cond_init(&pmutex->waitToBeOwner, 0); #endif /*_POSIX_THREAD_PROCESS_SHARED*/ checkStatusQuit(status, "pthread_cond_init", "epicsMutexOsdCreate"); return pmutex; }
epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsigned int level) { epicsThreadOSD *pthreadInfo; int status; int found = 0; epicsThreadInit(); if(!showThread) { showThreadInfo(0,level); return; } status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll"); pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList); while(pthreadInfo) { if (((epicsThreadId)pthreadInfo == showThread) || ((epicsThreadId)pthreadInfo->tid == showThread)) { found = 1; showThreadInfo(pthreadInfo,level); } pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node); } status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll"); if (!found) printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread); }
static void * start_routine(void *arg) { epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg; int status; int oldtype; sigset_t blockAllSig; sigfillset(&blockAllSig); pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL); status = pthread_setspecific(getpthreadInfo,arg); checkStatusQuit(status,"pthread_setspecific","start_routine"); status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&oldtype); checkStatusQuit(status,"pthread_setcanceltype","start_routine"); status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","start_routine"); ellAdd(&pthreadList,&pthreadInfo->node); pthreadInfo->isOnThreadList = 1; status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","start_routine"); (*pthreadInfo->createFunc)(pthreadInfo->createArg); epicsExitCallAtThreadExits (); free_threadInfo(pthreadInfo); return(0); }
static void free_threadInfo(epicsThreadOSD *pthreadInfo) { int status; status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo"); if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node); status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","free_threadInfo"); epicsEventDestroy(pthreadInfo->suspendEvent); status = pthread_attr_destroy(&pthreadInfo->attr); checkStatusQuit(status,"pthread_attr_destroy","free_threadInfo"); free(pthreadInfo->name); free(pthreadInfo); }
void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex) { int status; status = pthread_mutex_unlock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_unlock", "epicsMutexOsdUnlock"); }
/* * Create dummy context for threads not created by epicsThreadCreate(). */ static epicsThreadOSD *createImplicit(void) { epicsThreadOSD *pthreadInfo; char name[64]; pthread_t tid; int status; tid = pthread_self(); sprintf(name, "non-EPICS_%ld", (long)tid); pthreadInfo = create_threadInfo(name); pthreadInfo->tid = tid; pthreadInfo->osiPriority = 0; #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) { struct sched_param param; int policy; if(pthread_getschedparam(tid,&policy,¶m) == 0) pthreadInfo->osiPriority = (param.sched_priority - pcommonAttr->minPriority) * 100.0 / (pcommonAttr->maxPriority - pcommonAttr->minPriority + 1); } #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo); checkStatusQuit(status,"pthread_setspecific","createImplicit"); /* pthread_cleanup_push(nonEPICSthreadCleanup, pthreadInfo); */ return pthreadInfo; }
epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level) { epicsThreadOSD *pthreadInfo; int status; epicsThreadInit(); epicsThreadShow(0,level); status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll"); pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList); while(pthreadInfo) { showThreadInfo(pthreadInfo,level); pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node); } status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll"); }
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name) { epicsThreadOSD *pthreadInfo; int status; assert(epicsThreadOnceCalled); status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","epicsThreadGetId"); pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList); while(pthreadInfo) { if(strcmp(name,pthreadInfo->name) == 0) break; pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node); } status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadGetId"); return(pthreadInfo); }
epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id) { pthread_key_t *key = (pthread_key_t *)id; int status; assert(epicsThreadOnceCalled); status = pthread_key_delete(*key); checkStatusQuit(status,"pthread_key_delete","epicsThreadPrivateDelete"); free((void *)key); }
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * pmutex) { int status; if (!pmutex) return epicsMutexLockError; status = mutexLock(&pmutex->lock); if (status == EINVAL) return epicsMutexLockError; checkStatusQuit(status, "pthread_mutex_lock", "epicsMutexOsdLock"); return epicsMutexLockOK; }
epicsShareFunc void epicsShareAPI epicsThreadPrivateSet (epicsThreadPrivateId id, void *value) { pthread_key_t *key = (pthread_key_t *)id; int status; assert(epicsThreadOnceCalled); if(errVerbose && !value) errlogPrintf("epicsThreadPrivateSet: setting value of 0\n"); status = pthread_setspecific(*key,value); checkStatusQuit(status,"pthread_setspecific","epicsThreadPrivateSet"); }
epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void) { pthread_key_t *key; int status; epicsThreadInit(); key = callocMustSucceed(1,sizeof(pthread_key_t),"epicsThreadPrivateCreate"); status = pthread_key_create(key,0); checkStatusQuit(status,"pthread_key_create","epicsThreadPrivateCreate"); return((epicsThreadPrivateId)key); }
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex) { int status; if (!pmutex) return epicsMutexLockError; status = pthread_mutex_trylock(&pmutex->lock); if (status == EINVAL) return epicsMutexLockError; if (status == EBUSY) return epicsMutexLockTimeout; checkStatusQuit(status, "pthread_mutex_lock", "epicsMutexOsdTryLock"); return epicsMutexLockOK; }
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * pmutex) { pthread_t tid = pthread_self(); int status; if (!pmutex || !tid) return epicsMutexLockError; status = mutexLock(&pmutex->lock); if (status == EINVAL) return epicsMutexLockError; checkStatusQuit(status, "pthread_mutex_lock", "epicsMutexOsdLock"); while (pmutex->owned && !pthread_equal(pmutex->ownerTid, tid)) condWait(&pmutex->waitToBeOwner, &pmutex->lock); pmutex->ownerTid = tid; pmutex->owned = 1; pmutex->count++; status = pthread_mutex_unlock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_unlock", "epicsMutexOsdLock"); return epicsMutexLockOK; }
epicsMutexOSD * epicsMutexOsdCreate(void) { epicsMutexOSD *pmutex; int status; pmutex = callocMustSucceed(1, sizeof(*pmutex), "epicsMutexOsdCreate"); status = pthread_mutexattr_init(&pmutex->mutexAttr); checkStatusQuit(status,"pthread_mutexattr_init", "epicsMutexOsdCreate"); #if defined _POSIX_THREAD_PRIO_INHERIT status = pthread_mutexattr_setprotocol(&pmutex->mutexAttr, PTHREAD_PRIO_INHERIT); if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal"); #endif /*_POSIX_THREAD_PRIO_INHERIT*/ status = pthread_mutexattr_settype(&pmutex->mutexAttr, PTHREAD_MUTEX_RECURSIVE); if (errVerbose) checkStatus(status, "pthread_mutexattr_settype"); status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr); checkStatusQuit(status, "pthread_mutex_init", "epicsMutexOsdCreate"); return pmutex; }
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex) { pthread_t tid = pthread_self(); epicsMutexLockStatus result; int status; status = mutexLock(&pmutex->lock); if (status == EINVAL) return epicsMutexLockError; checkStatusQuit(status, "pthread_mutex_lock", "epicsMutexOsdTryLock"); if (!pmutex->owned || pthread_equal(pmutex->ownerTid, tid)) { pmutex->ownerTid = tid; pmutex->owned = 1; pmutex->count++; result = epicsMutexLockOK; } else { result = epicsMutexLockTimeout; } status = pthread_mutex_unlock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_unlock", "epicsMutexOsdTryLock"); return result; }
void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex) { int status; status = mutexLock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_lock", "epicsMutexOsdUnlock"); if ((pmutex->count <= 0) || (pmutex->ownerTid != pthread_self())) { errlogPrintf("epicsMutexOsdUnlock but caller is not owner\n"); status = pthread_mutex_unlock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_unlock", "epicsMutexOsdUnlock"); return; } pmutex->count--; if (pmutex->count == 0) { pmutex->owned = 0; pmutex->ownerTid = 0; pthread_cond_signal(&pmutex->waitToBeOwner); } status = pthread_mutex_unlock(&pmutex->lock); checkStatusQuit(status, "pthread_mutex_unlock", "epicsMutexOsdUnlock"); }
epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) { static struct epicsThreadOSD threadOnceComplete; #define EPICS_THREAD_ONCE_DONE &threadOnceComplete int status; epicsThreadInit(); status = mutexLock(&onceLock); if(status) { fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n", strerror(status)); exit(-1); } if (*id != EPICS_THREAD_ONCE_DONE) { if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */ *id = epicsThreadGetIdSelf(); /* mark active */ status = pthread_mutex_unlock(&onceLock); checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce"); func(arg); status = mutexLock(&onceLock); checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce"); *id = EPICS_THREAD_ONCE_DONE; /* mark done */ } else if (*id == epicsThreadGetIdSelf()) { status = pthread_mutex_unlock(&onceLock); checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce"); cantProceed("Recursive epicsThreadOnce() initialization\n"); } else while (*id != EPICS_THREAD_ONCE_DONE) { /* Another thread is in the above func(arg) call. */ status = pthread_mutex_unlock(&onceLock); checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce"); epicsThreadSleep(epicsThreadSleepQuantum()); status = mutexLock(&onceLock); checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce"); } } status = pthread_mutex_unlock(&onceLock); checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce"); }
static void epicsThreadInit(void) { static pthread_once_t once_control = PTHREAD_ONCE_INIT; int status = pthread_once(&once_control,once); checkStatusQuit(status,"pthread_once","epicsThreadInit"); }
static void* find_pri_range(void *arg) { priAvailable *prm = arg; int min = sched_get_priority_min(prm->policy); int max = sched_get_priority_max(prm->policy); int low, try; if ( -1 == min || -1 == max ) { /* something is very wrong; maintain old behavior * (warning message if sched_get_priority_xxx() fails * and use default policy's sched_priority [even if * that is likely to cause epicsThreadCreate to fail * because that priority is not suitable for SCHED_FIFO]). */ prm->min_pri = prm->max_pri = -1; return 0; } if ( try_pri(min, prm->policy) ) { /* cannot create thread at minimum priority; * probably no permission to use SCHED_FIFO * at all. However, we still must return * a priority range accepted by the SCHED_FIFO * policy. Otherwise, epicsThreadCreate() cannot * detect the unsufficient permission (EPERM) * and fall back to a non-RT thread (because * pthread_attr_setschedparam would fail with * EINVAL due to the bad priority). */ prm->min_pri = prm->max_pri = min; return 0; } /* Binary search through available priorities. * The actually available range may be restricted * by resource limitations (but that is ignored * by sched_get_priority_max() [linux]). */ low = min; while ( low < max ) { try = (max+low)/2; if ( try_pri(try, prm->policy) ) { max = try; } else { low = try + 1; } } prm->min_pri = min; prm->max_pri = try_pri(max, prm->policy) ? max-1 : max; return 0; } static void findPriorityRange(commonAttr *a_p) { priAvailable arg; pthread_t id; void *dummy; int status; arg.policy = a_p->schedPolicy; status = pthread_create(&id, 0, find_pri_range, &arg); checkStatusQuit(status, "pthread_create","epicsThreadInit"); status = pthread_join(id, &dummy); checkStatusQuit(status, "pthread_join","epicsThreadInit"); a_p->minPriority = arg.min_pri; a_p->maxPriority = arg.max_pri; } #endif static void once(void) { epicsThreadOSD *pthreadInfo; int status; pthread_key_create(&getpthreadInfo,0); status = pthread_mutex_init(&onceLock,0); checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit"); status = pthread_mutex_init(&listLock,0); checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit"); pcommonAttr = calloc(1,sizeof(commonAttr)); if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit"); status = pthread_attr_init(&pcommonAttr->attr); checkStatusOnceQuit(status,"pthread_attr_init","epicsThreadInit"); status = pthread_attr_setdetachstate( &pcommonAttr->attr, PTHREAD_CREATE_DETACHED); checkStatusOnce(status,"pthread_attr_setdetachstate"); status = pthread_attr_setscope(&pcommonAttr->attr,PTHREAD_SCOPE_PROCESS); if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope"); #if defined (_POSIX_THREAD_PRIORITY_SCHEDULING) status = pthread_attr_setschedpolicy( &pcommonAttr->attr,SCHED_FIFO); checkStatusOnce(status,"pthread_attr_setschedpolicy"); status = pthread_attr_getschedpolicy( &pcommonAttr->attr,&pcommonAttr->schedPolicy); checkStatusOnce(status,"pthread_attr_getschedpolicy"); status = pthread_attr_getschedparam( &pcommonAttr->attr,&pcommonAttr->schedParam); checkStatusOnce(status,"pthread_attr_getschedparam"); findPriorityRange(pcommonAttr); if(pcommonAttr->maxPriority == -1) { pcommonAttr->maxPriority = pcommonAttr->schedParam.sched_priority; fprintf(stderr,"sched_get_priority_max failed set to %d\n", pcommonAttr->maxPriority); } if(pcommonAttr->minPriority == -1) { pcommonAttr->minPriority = pcommonAttr->schedParam.sched_priority; fprintf(stderr,"sched_get_priority_min failed set to %d\n", pcommonAttr->maxPriority); } #else if(errVerbose) fprintf(stderr,"task priorities are not implemented\n"); #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0); status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo); checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit"); status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","epicsThreadInit"); ellAdd(&pthreadList,&pthreadInfo->node); pthreadInfo->isOnThreadList = 1; status = pthread_mutex_unlock(&listLock); checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit"); status = atexit(epicsExitCallAtExits); checkStatusOnce(status,"atexit"); epicsThreadOnceCalled = 1; }