From d3c0f075cf5e496aa5d4e747a3fb3f97a16764c2 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Wed, 20 Dec 2000 21:02:04 +0000 Subject: [PATCH] replacements for osdSem --- src/libCom/Makefile | 18 +- src/libCom/osi/os/RTEMS/osdEvent.c | 197 +++++++++++ src/libCom/osi/os/RTEMS/osdEvent.h | 9 + src/libCom/osi/os/RTEMS/osdMutex.c | 232 +++++++++++++ src/libCom/osi/os/RTEMS/osdMutex.h | 9 + src/libCom/osi/os/WIN32/osdEvent.c | 176 ++++++++++ src/libCom/osi/os/WIN32/osdEvent.h | 32 ++ src/libCom/osi/os/WIN32/osdMutex.c | 448 +++++++++++++++++++++++++ src/libCom/osi/os/WIN32/osdMutex.h | 36 ++ src/libCom/osi/os/posix/osdEvent.c | 164 +++++++++ src/libCom/osi/os/posix/osdEvent.h | 1 + src/libCom/osi/os/posix/osdMutex.c | 219 ++++++++++++ src/libCom/osi/os/posix/osdMutex.h | 1 + src/libCom/osi/os/vxWorks/osdEvent.c | 64 ++++ src/libCom/osi/os/vxWorks/osdEvent.h | 22 ++ src/libCom/osi/os/vxWorks/osdMutex.c | 65 ++++ src/libCom/osi/os/vxWorks/osdMutex.h | 22 ++ src/libCom/test/Makefile | 10 + src/libCom/test/epicsEventTest.cpp | 168 ++++++++++ src/libCom/test/epicsEventTestMain.cpp | 46 +++ src/libCom/test/epicsMutexTest.cpp | 116 +++++++ src/libCom/test/epicsMutexTestMain.cpp | 46 +++ 22 files changed, 2099 insertions(+), 2 deletions(-) create mode 100644 src/libCom/osi/os/RTEMS/osdEvent.c create mode 100644 src/libCom/osi/os/RTEMS/osdEvent.h create mode 100644 src/libCom/osi/os/RTEMS/osdMutex.c create mode 100644 src/libCom/osi/os/RTEMS/osdMutex.h create mode 100644 src/libCom/osi/os/WIN32/osdEvent.c create mode 100644 src/libCom/osi/os/WIN32/osdEvent.h create mode 100644 src/libCom/osi/os/WIN32/osdMutex.c create mode 100644 src/libCom/osi/os/WIN32/osdMutex.h create mode 100644 src/libCom/osi/os/posix/osdEvent.c create mode 100644 src/libCom/osi/os/posix/osdEvent.h create mode 100644 src/libCom/osi/os/posix/osdMutex.c create mode 100644 src/libCom/osi/os/posix/osdMutex.h create mode 100644 src/libCom/osi/os/vxWorks/osdEvent.c create mode 100644 src/libCom/osi/os/vxWorks/osdEvent.h create mode 100644 src/libCom/osi/os/vxWorks/osdMutex.c create mode 100644 src/libCom/osi/os/vxWorks/osdMutex.h create mode 100644 src/libCom/test/epicsEventTest.cpp create mode 100644 src/libCom/test/epicsEventTestMain.cpp create mode 100644 src/libCom/test/epicsMutexTest.cpp create mode 100644 src/libCom/test/epicsMutexTestMain.cpp diff --git a/src/libCom/Makefile b/src/libCom/Makefile index 476c2d560..c66601200 100644 --- a/src/libCom/Makefile +++ b/src/libCom/Makefile @@ -118,8 +118,19 @@ INC += osiSock.h INC += osdSock.h INC += osiInterrupt.h INC += osdInterrupt.h + +#Marty remove the following INC += osiSem.h INC += osdSem.h +INC += osiMutex.h +INC += osiEvent.h + + +INC += epicsMutex.h +INC += osdMutex.h +INC += epicsEvent.h +INC += osdEvent.h + INC += epicsAssert.h INC += epicsFindSymbol.h INC += osiPoolStatus.h @@ -131,8 +142,6 @@ INC += osdTime.h INC += osiSigPipeIgnore.h INC += osdSigPipeIgnore.h INC += tsStamp.h -INC += osiMutex.h -INC += osiEvent.h INC += osiProcess.h INC += osiUnistd.h INC += osiWireFormat.h @@ -143,7 +152,12 @@ SRCS += osdAssert.c SRCS += osdFindSymbol.c SRCS += osdInterrupt.c SRCS += osdPoolStatus.c + +#Marty remove the following SRCS += osdSem.c + +SRCS += osdMutex.c +SRCS += osdEvent.c SRCS += osdThread.c SRCS += osiThread.cpp SRCS += osdTime.cpp diff --git a/src/libCom/osi/os/RTEMS/osdEvent.c b/src/libCom/osi/os/RTEMS/osdEvent.c new file mode 100644 index 000000000..93a94f2ee --- /dev/null +++ b/src/libCom/osi/os/RTEMS/osdEvent.c @@ -0,0 +1,197 @@ +/* + * RTEMS osdEvent.c + * $Id$ + * Author: W. Eric Norum + * eric@cls.usask.ca + * (306) 966-6055 + */ + +/* + * We want to print out some information which is + * normally hidden from application programs. + */ +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1 + +#include +#include +#include +#include + +#include "epicsEvent.h" +#include "osiThread.h" +#include "errlog.h" + +/* + * Some performance tuning instrumentation + */ +#ifdef EPICS_RTEMS_SEMAPHORE_STATS +unsigned long semStat[6]; +#define SEMSTAT(i) semStat[i]++; +#else +#define SEMSTAT(i) +#endif + +/* + * Create a simple binary semaphore + */ +epicsEventId +epicsEventCreate(epicsEventInitialState initialState) +{ + rtems_status_code sc; + rtems_id sid; + rtems_interrupt_level level; + static char c1 = 'a'; + static char c2 = 'a'; + static char c3 = 'a'; + + sc = rtems_semaphore_create (rtems_build_name ('B', c3, c2, c1), + initialState, + RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | + RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, + 0, + &sid); + if (sc != RTEMS_SUCCESSFUL) { + errlogPrintf ("Can't create binary semaphore: %s\n", rtems_status_text (sc)); + return NULL; + } + rtems_interrupt_disable (level); + if (c1 == 'z') { + if (c2 == 'z') { + if (c3 == 'z') { + c3 = 'a'; + } + else { + c3++; + } + c2 = 'a'; + } + else { + c2++; + } + c1 = 'a'; + } + else { + c1++; + } + rtems_interrupt_enable (level); + return (epicsEventId)sid; +} + +epicsEventId epicsEventMustCreate(epicsEventInitialState initialState) +{ + epicsEventId id = epicsEventCreate (initialState); + assert (id); + return id; +} + +void +epicsEventDestroy(epicsEventId id) +{ + rtems_id sid = (rtems_id)id; + rtems_status_code sc; + + sc = rtems_semaphore_delete (sid); + if (sc != RTEMS_SUCCESSFUL) + errlogPrintf ("Can't destroy semaphore: %s\n", rtems_status_text (sc)); +} + +void +epicsEventSignal(epicsEventId id) +{ + rtems_id sid = (rtems_id)id; + rtems_status_code sc; + + sc = rtems_semaphore_release (sid); + if (sc != RTEMS_SUCCESSFUL) + errlogPrintf ("Can't release semaphore: %s\n", rtems_status_text (sc)); +} + +epicsEventWaitStatus +epicsEventWait(epicsEventId id) +{ + rtems_id sid = (rtems_id)id; + rtems_status_code sc; + + SEMSTAT(0) + sc = rtems_semaphore_obtain (sid, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + return epicsEventWaitError; + return epicsEventWaitOK; +} + +epicsEventWaitStatus +epicsEventWaitWithTimeout(epicsEventId id, double timeOut) +{ + rtems_id sid = (rtems_id)id; + rtems_status_code sc; + rtems_interval delay; + extern double rtemsTicksPerSecond_double; + + SEMSTAT(1) + delay = timeOut * rtemsTicksPerSecond_double; + if (delay == 0) + delay = 1; + sc = rtems_semaphore_obtain (sid, RTEMS_WAIT, delay); + if (sc == RTEMS_SUCCESSFUL) + return epicsEventWaitOK; + else if (sc == RTEMS_TIMEOUT) + return epicsEventWaitTimeout; + else + return epicsEventWaitError; +} + +epicsEventWaitStatus +epicsEventTryWait(epicsEventId id) +{ + rtems_id sid = (rtems_id)id; + rtems_status_code sc; + + SEMSTAT(2) + sc = rtems_semaphore_obtain (sid, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); + if (sc == RTEMS_SUCCESSFUL) + return epicsEventWaitOK; + else if (sc == RTEMS_UNSATISFIED) + return epicsEventWaitTimeout; + else + return epicsEventWaitError; +} + +void +epicsEventShow(epicsEventId id, unsigned int level) +{ +#if __RTEMS_VIOLATE_KERNEL_VISIBILITY__ + rtems_id sid = (rtems_id)id; + Semaphore_Control *the_semaphore; + Semaphore_Control semaphore; + Objects_Locations location; + + the_semaphore = _Semaphore_Get (sid, &location); + if (location != OBJECTS_LOCAL) + return; + /* + * Yes, there's a race condition here since an interrupt might + * change things while the copy is in progress, but the information + * is only for display, so it's not that critical. + */ + semaphore = *the_semaphore; + _Thread_Enable_dispatch(); + printf (" %8.8x ", sid); + if (_Attributes_Is_counting_semaphore (semaphore.attribute_set)) { + printf ("Count: %d", semaphore.Core_control.semaphore.count); + } + else { + if (_CORE_mutex_Is_locked(&semaphore.Core_control.mutex)) { + char name[20]; + threadGetName ((threadId)semaphore.Core_control.mutex.holder_id, name, sizeof name); + printf ("Held by:%8.8x (%s) Nest count:%d", + semaphore.Core_control.mutex.holder_id, + name, + semaphore.Core_control.mutex.nest_count); + } + else { + printf ("Not Held"); + } + } + printf ("\n"); +#endif +} diff --git a/src/libCom/osi/os/RTEMS/osdEvent.h b/src/libCom/osi/os/RTEMS/osdEvent.h new file mode 100644 index 000000000..8d9791d28 --- /dev/null +++ b/src/libCom/osi/os/RTEMS/osdEvent.h @@ -0,0 +1,9 @@ +/* + * RTEMS osdEvent.h + * $Id$ + * Author: W. Eric Norum + * eric@cls.usask.ca + * (306) 966-6055 + */ + +/* osdEvent.h not needed */ diff --git a/src/libCom/osi/os/RTEMS/osdMutex.c b/src/libCom/osi/os/RTEMS/osdMutex.c new file mode 100644 index 000000000..78255e111 --- /dev/null +++ b/src/libCom/osi/os/RTEMS/osdMutex.c @@ -0,0 +1,232 @@ +/* + * RTEMS osdMutex.c + * $Id$ + * Author: W. Eric Norum + * eric@cls.usask.ca + * (306) 966-6055 + */ + +/* + * We want to print out some information which is + * normally hidden from application programs. + */ +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1 + +#include +#include +#include +#include + +#include "epicsMutex.h" +#include "epicsEvent.h" +#include "osiThread.h" +#include "errlog.h" + +#define RTEMS_FAST_MUTEX +/* #define EPICS_RTEMS_SEMAPHORE_STATS */ +/* + * Some performance tuning instrumentation + */ +#ifdef EPICS_RTEMS_SEMAPHORE_STATS +unsigned long semStat[6]; +#define SEMSTAT(i) semStat[i]++; +#else +#define SEMSTAT(i) +#endif + +epicsMutexId +epicsMutexCreate(void) +{ + rtems_status_code sc; + rtems_id sid; + rtems_interrupt_level level; + static char c1 = 'a'; + static char c2 = 'a'; + static char c3 = 'a'; + + sc = rtems_semaphore_create (rtems_build_name ('M', c3, c2, c1), + 1, + RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE|RTEMS_INHERIT_PRIORITY|RTEMS_NO_PRIORITY_CEILING|RTEMS_LOCAL, + 0, + &sid); + if (sc != RTEMS_SUCCESSFUL) { + errlogPrintf ("Can't create mutex semaphore: %s\n", rtems_status_text (sc)); + return NULL; + } + rtems_interrupt_disable (level); + if (c1 == 'z') { + if (c2 == 'z') { + if (c3 == 'z') { + c3 = 'a'; + } + else { + c3++; + } + c2 = 'a'; + } + else { + c2++; + } + c1 = 'a'; + } + else { + c1++; + } + rtems_interrupt_enable (level); +#ifdef RTEMS_FAST_MUTEX + { + Semaphore_Control *the_semaphore; + Objects_Locations location; + + the_semaphore = _Semaphore_Get( sid, &location ); + _Thread_Enable_dispatch(); + + return the_semaphore; + } +#endif + return (epicsMutexId)sid; +} + +epicsMutexId epicsMutexMustCreate(void) +{ + epicsMutexId id = epicsMutexCreate (); + assert (id); + return id; +} + +void epicsMutexDestroy(epicsMutexId id) +{ + rtems_status_code sc; + rtems_id sid; +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + sid = the_semaphore->Object.id; +#else + sid = (rtems_id)id; +#endif + sc = rtems_semaphore_delete (sid); + if (sc == RTEMS_RESOURCE_IN_USE) { + rtems_semaphore_release (sid); + sc = rtems_semaphore_delete (sid); + } + if (sc != RTEMS_SUCCESSFUL) + errlogPrintf ("Can't destroy semaphore: %s\n", rtems_status_text (sc)); +} + +void epicsMutexUnlock(epicsMutexId id) +{ +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + _Thread_Disable_dispatch(); + _CORE_mutex_Surrender ( + &the_semaphore->Core_control.mutex, + the_semaphore->Object.id, + NULL + ); + _Thread_Enable_dispatch(); +#else + epicsEventSignal (id); +#endif + +} + +epicsMutexLockStatus epicsMutexLock(epicsMutexId id) +{ +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + ISR_Level level; + SEMSTAT(3) + _ISR_Disable( level ); + _CORE_mutex_Seize( + &the_semaphore->Core_control.mutex, + the_semaphore->Object.id, + 1, /* TRUE or FALSE */ + 0, /* same as passed to obtain -- ticks */ + level + ); + if (_Thread_Executing->Wait.return_code == 0) + return epicsMutexLockOK; + else + return epicsMutexLockError; +#else + SEMSTAT(3) + return((epicsEventWait (id) == epicsEventWaitOK) + ?epicsMutexLockOK : epicsMutexLockError); +#endif +} + +epicsMutexLockStatus epicsMutexLockWithTimeout( + epicsMutexId id, double timeOut) +{ +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + ISR_Level level; + rtems_interval delay; + extern double rtemsTicksPerSecond_double; + + SEMSTAT(4) + delay = timeOut * rtemsTicksPerSecond_double; + if (delay == 0) + delay = 1; + _ISR_Disable( level ); + _CORE_mutex_Seize( + &the_semaphore->Core_control.mutex, + the_semaphore->Object.id, + 1, /* TRUE or FALSE */ + delay, /* same as passed to obtain -- ticks */ + level + ); + if (_Thread_Executing->Wait.return_code == 0) + return epicsMutexLockOK; + else + return epicsMutexLockError; +#else + epicsEventWaitStatus status; + SEMSTAT(4) + status = epicsEventWaitWithTimeout(id,timeOut); + return((status==epicsEventWaitOK + ? epicsMutexLockOK + : (status==epicsEventWaitTimeout) + ? epicsMutexLockTimeout + : epicsMutexLockError)); +#endif +} + +epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id) +{ +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + ISR_Level level; + SEMSTAT(5) + _ISR_Disable( level ); + _CORE_mutex_Seize( + &the_semaphore->Core_control.mutex, + the_semaphore->Object.id, + 0, /* TRUE or FALSE */ + 0, /* same as passed to obtain -- ticks */ + level + ); + if (_Thread_Executing->Wait.return_code == 0) + return epicsMutexLockOK; + else + return epicsMutexLockError; +#else + epicsEventWaitStatus status; + SEMSTAT(5) + status = epicsEventTryWait(id); + return((status==epicsEventWaitOK + ? epicsMutexLockOK + : (status==epicsEventWaitTimeout) + ? epicsMutexLockTimeout + : epicsMutexLockError)); +#endif +} + +epicsShareFunc void epicsMutexShow(epicsMutexId id,unsigned int level) +{ +#ifdef RTEMS_FAST_MUTEX + Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + id = (epicsMutexId)the_semaphore->Object.id; +#endif + epicsEventShow (id,level); +} diff --git a/src/libCom/osi/os/RTEMS/osdMutex.h b/src/libCom/osi/os/RTEMS/osdMutex.h new file mode 100644 index 000000000..1627a416c --- /dev/null +++ b/src/libCom/osi/os/RTEMS/osdMutex.h @@ -0,0 +1,9 @@ +/* + * RTEMS osdMutex.h + * $Id$ + * Author: W. Eric Norum + * eric@cls.usask.ca + * (306) 966-6055 + */ + +/* osdSem.h not needed */ diff --git a/src/libCom/osi/os/WIN32/osdEvent.c b/src/libCom/osi/os/WIN32/osdEvent.c new file mode 100644 index 000000000..20edbe788 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdEvent.c @@ -0,0 +1,176 @@ +/* osdEvent.c */ +/* + * $Id$ + * WIN32 version + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + */ + +#include + +#ifndef VC_EXTRALEAN +# define VC_EXTRALEAN +#endif +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +/* including less than this causes conflicts with winsock2.h :-( */ +#define _WIN32_WINNT 0x400 +#include + +#define epicsExportSharedSymbols +#include "shareLib.h" +#include "epicsEvent.h" +#include "epicsAssert.h" +#include "cantProceed.h" + +static const unsigned mSecPerSecOsdSem = 1000u; + +typedef struct eventSem { + HANDLE handle; +}eventSem; + + +/* + * epicsEventCreate () + */ +epicsShareFunc epicsEventId epicsShareAPI epicsEventCreate ( + epicsEventInitialState initialState ) +{ + eventSem *pSem; + + pSem = malloc ( sizeof ( *pSem ) ); + if ( pSem ) { + pSem->handle = CreateEvent ( NULL, FALSE, initialState?TRUE:FALSE, NULL ); + if ( pSem->handle == 0 ) { + free ( pSem ); + pSem = 0; + } + } + + return ( epicsEventId ) pSem; +} + +/* + * epicsEventMustCreate () + */ +epicsShareFunc epicsEventId epicsShareAPI epicsEventMustCreate ( + epicsEventInitialState initialState ) +{ + epicsEventId id = epicsEventCreate ( initialState ); + assert ( id ); + return id; +} + +/* + * epicsEventDestroy () + */ +epicsShareFunc void epicsShareAPI epicsEventDestroy (epicsEventId id) +{ + eventSem *pSem = (eventSem *) id; + + CloseHandle (pSem->handle); + free (pSem); +} + +/* + * epicsEventSignal () + */ +epicsShareFunc void epicsShareAPI epicsEventSignal (epicsEventId id) +{ + eventSem *pSem = (eventSem *) id; + BOOL status; + + status = SetEvent (pSem->handle); + assert (status); +} + +/* + * epicsEventLock () + */ +epicsShareFunc epicsEventWaitStatus epicsShareAPI epicsEventLock (epicsEventId id) +{ + eventSem *pSem = (eventSem *) id; + DWORD status; + + status = WaitForSingleObject (pSem->handle, INFINITE); + if ( status == WAIT_OBJECT_0 ) { + return epicsEventWaitOK; + } + else { + return epicsEventWaitError; + } +} + +/* + * epicsEventWaitWithTimeout () + */ +epicsShareFunc epicsEventWaitStatus epicsShareAPI epicsEventWaitWithTimeout ( + epicsEventId id, double timeOut) +{ + eventSem *pSem = (eventSem *) id; + DWORD status; + DWORD tmo; + + tmo = (DWORD) (timeOut * mSecPerSecOsdSem); + status = WaitForSingleObject (pSem->handle, tmo); + if ( status == WAIT_OBJECT_0 ) { + return epicsEventWaitOK; + } + else if (status == WAIT_TIMEOUT) { + return epicsEventWaitTimeout; + } + else { + return epicsEventWaitError; + } +} + +/* + * epicsEventTryWait () + */ +epicsShareFunc epicsEventWaitStatus epicsShareAPI epicsEventTryWait (epicsEventId id) +{ + eventSem *pSem = (eventSem *) id; + DWORD status; + + status = WaitForSingleObject (pSem->handle, 0); + if ( status == WAIT_OBJECT_0 ) { + return epicsEventWaitOK; + } + else if (status == WAIT_TIMEOUT) { + return epicsEventWaitTimeout; + } + else { + return epicsEventWaitError; + } +} + +/* + * epicsEventShow () + */ +epicsShareFunc void epicsShareAPI epicsEventShow (epicsEventId id, unsigned level) +{ +} diff --git a/src/libCom/osi/os/WIN32/osdEvent.h b/src/libCom/osi/os/WIN32/osdEvent.h new file mode 100644 index 000000000..874fb05a7 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdEvent.h @@ -0,0 +1,32 @@ +/* osdEvent.c */ +/* + * $Id$ + * WIN32 version + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + */ + +/* osdEvent.h not needed */ diff --git a/src/libCom/osi/os/WIN32/osdMutex.c b/src/libCom/osi/os/WIN32/osdMutex.c new file mode 100644 index 000000000..598a2e7b1 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdMutex.c @@ -0,0 +1,448 @@ +/* osdMutex.c */ +/* + * $Id$ + * WIN32 version + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + */ + +#include + +#ifndef VC_EXTRALEAN +# define VC_EXTRALEAN +#endif +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +/* including less than this causes conflicts with winsock2.h :-( */ +#define _WIN32_WINNT 0x400 +#include + +#define epicsExportSharedSymbols +#include "shareLib.h" +#include "epicsMutex.h" +#include "epicsAssert.h" +#include "cantProceed.h" + +static const unsigned mSecPerSecOsdSem = 1000u; + +#if 0 + +typedef struct mutexSem { + HANDLE handle; +}mutexSem; + + +/* + * epicsMutexCreate () + */ +epicsShareFunc epicsMutexId epicsShareAPI epicsMutexCreate (void) +{ + mutexSem *pSem; + + pSem = malloc ( sizeof (*pSem) ); + if (pSem) { + pSem->handle = CreateMutex (NULL, FALSE, NULL); + if (pSem->handle==0) { + free (pSem); + pSem = 0; + } + } + + return (epicsMutexId) pSem; +} + +/* + * epicsMutexMustCreate () + */ +epicsShareFunc epicsMutexId epicsShareAPI epicsMutexMustCreate () +{ + epicsMutexId id = epicsMutexCreate (); + assert (id); + return id; +} + +/* + * epicsMutexDestroy () + */ +epicsShareFunc void epicsShareAPI epicsMutexDestroy (epicsMutexId id) +{ + mutexSem *pSem = (mutexSem *) id; + + CloseHandle (pSem->handle); + free (pSem); +} + +/* + * epicsMutexUnlock () + */ +epicsShareFunc void epicsShareAPI epicsMutexUnlock (epicsMutexId id) +{ + mutexSem *pSem = (mutexSem *) id; + BOOL success; + + success = ReleaseMutex (pSem->handle); + assert (success); +} + +/* + * epicsMutexLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLock (epicsMutexId id) +{ + mutexSem *pSem = (mutexSem *) id; + DWORD status; + + status = WaitForSingleObject (pSem->handle, INFINITE); + if ( status == WAIT_OBJECT_0 ) { + return epicsMutexLockOK; + } + else { + return epicsMutexLockError; + } +} + +/* + * epicsMutexLockWithTimeout () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLockWithTimeout (epicsMutexId id, double timeOut) +{ + mutexSem *pSem = (mutexSem *) id; + DWORD status; + DWORD tmo; + + tmo = (DWORD) (timeOut * mSecPerSecOsdSem); + status = WaitForSingleObject (pSem->handle, tmo); + if ( status == WAIT_OBJECT_0 ) { + return epicsMutexLockOK; + } + else if (status == WAIT_TIMEOUT) { + return epicsMutexLockTimeout; + } + else { + return epicsMutexLockError; + } +} + +/* + * epicsMutexTryLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexTryLock (epicsMutexId id) +{ + mutexSem *pSem = (mutexSem *) id; + DWORD status; + + status = WaitForSingleObject (pSem->handle, 0); + if ( status == WAIT_OBJECT_0 ) { + return epicsMutexLockOK; + } + else if (status == WAIT_TIMEOUT) { + return epicsMutexLockTimeout; + } + else { + return epicsMutexLockError; + } +} + +/* + * epicsMutexShow () + */ +epicsShareFunc void epicsShareAPI epicsMutexShow (epicsMutexId id, unsigned level) +{ +} + +#elif 0 + +typedef struct mutexSem { + CRITICAL_SECTION cs; +} mutexSem; + +/* + * epicsMutexCreate () + */ +epicsShareFunc epicsMutexId epicsShareAPI epicsMutexCreate ( void ) +{ + mutexSem *pSem; + + pSem = malloc ( sizeof (*pSem) ); + if ( pSem ) { + InitializeCriticalSection ( &pSem->cs ); + } + + return (epicsMutexId) pSem; +} + +/* + * epicsMutexMustCreate () + */ +epicsShareFunc semBinaryId epicsShareAPI epicsMutexMustCreate () +{ + epicsMutexId id = epicsMutexCreate (); + assert ( id ); + return id; +} + +/* + * epicsMutexDestroy () + */ +epicsShareFunc void epicsShareAPI epicsMutexDestroy ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + + DeleteCriticalSection ( &pSem->cs ); + free ( pSem ); +} + +/* + * epicsMutexUnlock () + */ +epicsShareFunc void epicsShareAPI epicsMutexUnlock ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + LeaveCriticalSection ( &pSem->cs ); +} + +/* + * epicsMutexLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLock ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + EnterCriticalSection ( &pSem->cs ); + return epicsMutexLockOK; +} + +/* + * epicsMutexLockWithTimeout () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLockWithTimeout ( epicsMutexId id, double timeOut ) +{ + mutexSem *pSem = ( mutexSem * ) id; + EnterCriticalSection ( &pSem->cs ); + return epicsMutexLockOK; +} + +/* + * epicsMutexTryLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexTryLock ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + if ( TryEnterCriticalSection ( &pSem->cs ) ) { + return epicsMutexLockOK; + } + else { + return epicsMutexLockTimeout; + } +} + +/* + * epicsMutexShow () + */ +epicsShareFunc void epicsShareAPI epicsMutexShow ( epicsMutexId id, unsigned level ) +{ +} + +#else + +typedef struct mutexSem { + CRITICAL_SECTION cs; + DWORD threadId; + HANDLE unlockSignal; + unsigned count; +} mutexSem; + +/* + * epicsMutexCreate () + */ +epicsShareFunc epicsMutexId epicsShareAPI epicsMutexCreate ( void ) +{ + mutexSem *pSem; + + pSem = malloc ( sizeof (*pSem) ); + if ( pSem ) { + pSem->unlockSignal = CreateEvent ( NULL, FALSE, FALSE, NULL ); + if ( pSem->unlockSignal == 0 ) { + free ( pSem ); + pSem = 0; + } + else { + InitializeCriticalSection ( &pSem->cs ); + pSem->threadId = 0; + pSem->count = 0u; + } + } + return (epicsMutexId) pSem; +} + +/* + * epicsMutexMustCreate () + */ +epicsShareFunc semBinaryId epicsShareAPI epicsMutexMustCreate () +{ + epicsMutexId id = epicsMutexCreate (); + assert ( id ); + return id; +} + +/* + * epicsMutexDestroy () + */ +epicsShareFunc void epicsShareAPI epicsMutexDestroy ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + + DeleteCriticalSection ( &pSem->cs ); + CloseHandle ( pSem->unlockSignal ); + free ( pSem ); +} + +/* + * epicsMutexUnlock () + */ +epicsShareFunc void epicsShareAPI epicsMutexUnlock ( epicsMutexId id ) +{ + mutexSem *pSem = ( mutexSem * ) id; + unsigned signalNeeded; + DWORD status; + + EnterCriticalSection ( &pSem->cs ); + //assert ( pSem->threadId == GetCurrentThreadId () ); + assert ( pSem->count > 0u ); + pSem->count--; + if ( pSem->count == 0 ) { + pSem->threadId = 0; + signalNeeded = 1; + } + else { + signalNeeded = 0; + } + LeaveCriticalSection ( &pSem->cs ); + + if ( signalNeeded ) { + status = SetEvent ( pSem->unlockSignal ); + assert ( status ); + } +} + +/* + * epicsMutexLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLock ( epicsMutexId id ) +{ + DWORD thisThread = GetCurrentThreadId (); + mutexSem *pSem = ( mutexSem * ) id; + + EnterCriticalSection ( &pSem->cs ); + + while ( pSem->count && pSem->threadId != thisThread ) { + DWORD status; + + LeaveCriticalSection ( &pSem->cs ); + status = WaitForSingleObject ( pSem->unlockSignal, INFINITE ); + if ( status == WAIT_TIMEOUT ) { + return epicsMutexLockTimeout; + } + EnterCriticalSection ( &pSem->cs ); + } + + pSem->threadId = thisThread; + assert ( pSem->count != UINT_MAX ); + pSem->count++; + + LeaveCriticalSection ( &pSem->cs ); + + return epicsMutexLockOK; +} + +/* + * epicsMutexLockWithTimeout () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexLockWithTimeout ( epicsMutexId id, double timeOut ) +{ + DWORD thisThread = GetCurrentThreadId (); + + mutexSem *pSem = ( mutexSem * ) id; + + EnterCriticalSection ( &pSem->cs ); + + while ( pSem->count && pSem->threadId != thisThread ) { + DWORD tmo; + DWORD status; + + LeaveCriticalSection ( &pSem->cs ); + tmo = ( DWORD ) ( timeOut * mSecPerSecOsdSem ); + status = WaitForSingleObject ( pSem->unlockSignal, tmo ); + if ( status == WAIT_TIMEOUT ) { + return epicsMutexLockTimeout; + } + EnterCriticalSection ( &pSem->cs ); + } + + pSem->threadId = thisThread; + assert ( pSem->count != UINT_MAX ); + pSem->count++; + + LeaveCriticalSection ( &pSem->cs ); + + return epicsMutexLockOK; +} + +/* + * epicsMutexTryLock () + */ +epicsShareFunc epicsMutexLockStatus epicsShareAPI epicsMutexTryLock ( epicsMutexId id ) +{ + DWORD thisThread = GetCurrentThreadId (); + + mutexSem *pSem = ( mutexSem * ) id; + + EnterCriticalSection ( &pSem->cs ); + + if ( pSem->count && pSem->threadId != thisThread ) { + LeaveCriticalSection ( &pSem->cs ); + return epicsMutexLockTimeout; + } + + pSem->threadId = thisThread; + assert ( pSem->count != UINT_MAX ); + pSem->count++; + + LeaveCriticalSection ( &pSem->cs ); + + return epicsMutexLockOK; +} + +/* + * epicsMutexShow () + */ +epicsShareFunc void epicsShareAPI epicsMutexShow ( epicsMutexId id, unsigned level ) +{ +} + + +#endif + diff --git a/src/libCom/osi/os/WIN32/osdMutex.h b/src/libCom/osi/os/WIN32/osdMutex.h new file mode 100644 index 000000000..57fdd3cf8 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdMutex.h @@ -0,0 +1,36 @@ + +/* osdMutex.h */ +/* + * $Id$ + * WIN32 version + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + */ + +#ifndef osdMutexh +#define osdMutexh + +#endif /* osdMutexh */ diff --git a/src/libCom/osi/os/posix/osdEvent.c b/src/libCom/osi/os/posix/osdEvent.c new file mode 100644 index 000000000..d53fbb494 --- /dev/null +++ b/src/libCom/osi/os/posix/osdEvent.c @@ -0,0 +1,164 @@ +/* osi/os/posix/osdEvent.c */ + +/* Author: Marty Kraimer Date: 13AUG1999 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "epicsEvent.h" +#include "osiThread.h" +#include "cantProceed.h" +#include "tsStamp.h" +#include "errlog.h" +#include "epicsAssert.h" + +/* Until these can be demonstrated to work leave them undefined*/ +#undef _POSIX_THREAD_PROCESS_SHARED +#undef _POSIX_THREAD_PRIO_INHERIT + +typedef struct event { + pthread_mutex_t mutex; + pthread_cond_t cond; + int isFull; +}event; + +#define checkStatus(status,message) \ +if((status)) { \ + errlogPrintf("%s failed: error %s\n",(message),strerror((status)));} + +#define checkStatusQuit(status,message,method) \ +if(status) { \ + errlogPrintf("%s failed: error %s\n",(message),strerror((status))); \ + cantProceed((method)); \ +} + +static void convertDoubleToWakeTime(double timeout,struct timespec *wakeTime) +{ + struct timespec wait; + TS_STAMP stamp; + + if(timeout<0.0) timeout = 0.0; + else if(timeout>3600.0) timeout = 3600.0; + tsStampGetCurrent(&stamp); + tsStampToTimespec(wakeTime, &stamp); + wait.tv_sec = timeout; + wait.tv_nsec = (long)((timeout - (double)wait.tv_sec) * 1e9); + wakeTime->tv_sec += wait.tv_sec; + wakeTime->tv_nsec += wait.tv_nsec; + if(wakeTime->tv_nsec>1000000000L) { + wakeTime->tv_nsec -= 1000000000L; + ++wakeTime->tv_sec; + } +} + +epicsEventId epicsEventCreate(epicsEventInitialState initialState) +{ + event *pevent; + int status; + + pevent = callocMustSucceed(1,sizeof(event),"epicsEventCreate"); + status = pthread_mutex_init(&pevent->mutex,0); + checkStatusQuit(status,"pthread_mutex_init","epicsEventCreate"); + status = pthread_cond_init(&pevent->cond,0); + checkStatusQuit(status,"pthread_cond_init","epicsEventCreate"); + if(initialState==epicsEventFull) pevent->isFull = 1; + return((epicsEventId)pevent); +} + +epicsEventId epicsEventMustCreate(epicsEventInitialState initialState) +{ + epicsEventId id = epicsEventCreate (initialState); + assert (id); + return id; +} + +void epicsEventDestroy(epicsEventId id) +{ + event *pevent = (event *)id; + int status; + + status = pthread_mutex_destroy(&pevent->mutex); + checkStatus(status,"pthread_mutex_destroy"); + status = pthread_cond_destroy(&pevent->cond); + checkStatus(status,"pthread_cond_destroy"); + free(pevent); +} + +void epicsEventSignal(epicsEventId id) +{ + event *pevent = (event *)id; + int status; + + status = pthread_mutex_lock(&pevent->mutex); + checkStatusQuit(status,"pthread_mutex_lock","epicsEventSignal"); + if(!pevent->isFull) { + pevent->isFull = 1; + status = pthread_cond_signal(&pevent->cond); + checkStatus(status,"pthread_cond_signal"); + } + status = pthread_mutex_unlock(&pevent->mutex); + checkStatusQuit(status,"pthread_mutex_unlock","epicsEventSignal"); +} + +epicsEventWaitStatus epicsEventWait(epicsEventId id) +{ + event *pevent = (event *)id; + int status; + + if(!pevent) return(epicsEventWaitError); + status = pthread_mutex_lock(&pevent->mutex); + checkStatusQuit(status,"pthread_mutex_lock","epicsEventWait"); + /*no need for while since caller must be prepared for no work*/ + if(!pevent->isFull) { + status = pthread_cond_wait(&pevent->cond,&pevent->mutex); + checkStatusQuit(status,"pthread_cond_wait","epicsEventWait"); + } + pevent->isFull = 0; + status = pthread_mutex_unlock(&pevent->mutex); + checkStatusQuit(status,"pthread_mutex_unlock","epicsEventWait"); + return(epicsEventWaitOK); +} + +epicsEventWaitStatus epicsEventWaitWithTimeout(epicsEventId id, double timeout) +{ + event *pevent = (event *)id; + struct timespec wakeTime; + int status = 0; + int unlockStatus; + + status = pthread_mutex_lock(&pevent->mutex); + checkStatusQuit(status,"pthread_mutex_lock","epicsEventWaitWithTimeout"); + if(!pevent->isFull) { + convertDoubleToWakeTime(timeout,&wakeTime); + status = pthread_cond_timedwait( + &pevent->cond,&pevent->mutex,&wakeTime); + } + if(status==0) pevent->isFull = 0; + unlockStatus = pthread_mutex_unlock(&pevent->mutex); + checkStatusQuit(unlockStatus,"pthread_mutex_unlock","epicsEventWaitWithTimeout"); + if(status==0) return(epicsEventWaitOK); + if(status==ETIMEDOUT) return(epicsEventWaitTimeout); + checkStatus(status,"pthread_cond_timedwait"); + return(epicsEventWaitError); +} + +epicsEventWaitStatus epicsEventTryWait(epicsEventId id) +{ + return(epicsEventWaitWithTimeout(id,0.0)); +} + +void epicsEventShow(epicsEventId id,unsigned int level) +{ +} diff --git a/src/libCom/osi/os/posix/osdEvent.h b/src/libCom/osi/os/posix/osdEvent.h new file mode 100644 index 000000000..f58a54c0f --- /dev/null +++ b/src/libCom/osi/os/posix/osdEvent.h @@ -0,0 +1 @@ +/* for a pure posix implementation no osdEvent.h definitions are needed*/ diff --git a/src/libCom/osi/os/posix/osdMutex.c b/src/libCom/osi/os/posix/osdMutex.c new file mode 100644 index 000000000..fbc074d39 --- /dev/null +++ b/src/libCom/osi/os/posix/osdMutex.c @@ -0,0 +1,219 @@ +/* osi/os/posix/osdMutex.c */ + +/* Author: Marty Kraimer Date: 13AUG1999 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "epicsMutex.h" +#include "osiThread.h" +#include "cantProceed.h" +#include "tsStamp.h" +#include "errlog.h" +#include "epicsAssert.h" + +/* Until these can be demonstrated to work leave them undefined*/ +#undef _POSIX_THREAD_PROCESS_SHARED +#undef _POSIX_THREAD_PRIO_INHERIT + +typedef struct mutex { + pthread_mutexattr_t mutexAttr; + pthread_mutex_t lock; + pthread_cond_t waitToBeOwner; +#if defined _POSIX_THREAD_PROCESS_SHARED + pthread_condattr_t condAttr; +#endif /*_POSIX_THREAD_PROCESS_SHARED*/ + int count; + int owned; /* TRUE | FALSE */ + pthread_t ownerTid; +}mutex; + +#define checkStatus(status,message) \ +if((status)) { \ + errlogPrintf("%s failed: error %s\n",(message),strerror((status)));} + +#define checkStatusQuit(status,message,method) \ +if(status) { \ + errlogPrintf("%s failed: error %s\n",(message),strerror((status))); \ + cantProceed((method)); \ +} + +static void convertDoubleToWakeTime(double timeout,struct timespec *wakeTime) +{ + struct timespec wait; + TS_STAMP stamp; + + if(timeout<0.0) timeout = 0.0; + else if(timeout>3600.0) timeout = 3600.0; + tsStampGetCurrent(&stamp); + tsStampToTimespec(wakeTime, &stamp); + wait.tv_sec = timeout; + wait.tv_nsec = (long)((timeout - (double)wait.tv_sec) * 1e9); + wakeTime->tv_sec += wait.tv_sec; + wakeTime->tv_nsec += wait.tv_nsec; + if(wakeTime->tv_nsec>1000000000L) { + wakeTime->tv_nsec -= 1000000000L; + ++wakeTime->tv_sec; + } +} + +epicsMutexId epicsMutexCreate(void) { + mutex *pmutex; + int status; + + pmutex = callocMustSucceed(1,sizeof(mutex),"epicsMutexCreate"); + status = pthread_mutexattr_init(&pmutex->mutexAttr); + checkStatusQuit(status,"pthread_mutexattr_init","epicsMutexCreate"); +#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","epicsMutexCreate"); +#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","epicsMutexCreate"); + return((epicsMutexId)pmutex); +} + +epicsMutexId epicsMutexMustCreate(void) +{ + epicsMutexId id = epicsMutexCreate (); + assert (id); + return id; +} + +void epicsMutexDestroy(epicsMutexId id) +{ + mutex *pmutex = (mutex *)id; + int status; + + status = pthread_cond_destroy(&pmutex->waitToBeOwner); + checkStatus(status,"pthread_cond_destroy"); +#if defined _POSIX_THREAD_PROCESS_SHARED + status = pthread_condattr_destroy(&pmutex->condAttr); +#endif /*_POSIX_THREAD_PROCESS_SHARED*/ + status = pthread_mutex_destroy(&pmutex->lock); + checkStatus(status,"pthread_mutex_destroy"); + status = pthread_mutexattr_destroy(&pmutex->mutexAttr); + checkStatus(status,"pthread_mutexattr_destroy"); + free(pmutex); +} + +void epicsMutexUnlock(epicsMutexId id) +{ + mutex *pmutex = (mutex *)id; + int status; + + status = pthread_mutex_lock(&pmutex->lock); + checkStatusQuit(status,"pthread_mutex_lock","epicsMutexUnlock"); + if((pmutex->count<=0) || (pmutex->ownerTid != pthread_self())) { + errlogPrintf("epicsMutexUnlock but caller is not owner\n"); + status = pthread_mutex_unlock(&pmutex->lock); + checkStatusQuit(status,"pthread_mutex_unlock","epicsMutexUnlock"); + 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","epicsMutexUnlock"); +} + +epicsMutexLockStatus epicsMutexLock(epicsMutexId id) +{ + mutex *pmutex = (mutex *)id; + pthread_t tid = pthread_self(); + int status; + + if(!pmutex || !tid) return(epicsMutexLockError); + status = pthread_mutex_lock(&pmutex->lock); + checkStatusQuit(status,"pthread_mutex_lock","epicsMutexLock"); + while(pmutex->owned && !pthread_equal(pmutex->ownerTid,tid)) + pthread_cond_wait(&pmutex->waitToBeOwner,&pmutex->lock); + pmutex->ownerTid = tid; + pmutex->owned = 1; + pmutex->count++; + status = pthread_mutex_unlock(&pmutex->lock); + checkStatusQuit(status,"pthread_mutex_unlock","epicsMutexLock"); + return(epicsMutexLockOK); +} + +epicsMutexLockStatus epicsMutexLockWithTimeout(epicsMutexId id, double timeout) +{ + mutex *pmutex = (mutex *)id; + pthread_t tid = pthread_self(); + struct timespec wakeTime; + int status,unlockStatus; + + convertDoubleToWakeTime(timeout,&wakeTime); + status = pthread_mutex_lock(&pmutex->lock); + checkStatusQuit(status,"pthread_mutex_lock","epicsMutexLockWithTimeout"); + while(pmutex->owned && !pthread_equal(pmutex->ownerTid,tid)) { + status = pthread_cond_timedwait( + &pmutex->waitToBeOwner,&pmutex->lock,&wakeTime); + if(!status) break; + } + if(status==0) { + pmutex->ownerTid = tid; + pmutex->owned = 1; + pmutex->count++; + } + unlockStatus = pthread_mutex_unlock(&pmutex->lock); + checkStatusQuit(unlockStatus,"pthread_mutex_lock","epicsMutexLockWithTimeout"); + if(status==0) return(epicsMutexLockOK); + if(status==ETIMEDOUT) return(epicsMutexLockTimeout); + checkStatusQuit(status,"pthread_cond_timedwait","epicsMutexLockWithTimeout"); + return(epicsMutexLockError); +} + +epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id) +{ + mutex *pmutex = (mutex *)id; + pthread_t tid = pthread_self(); + epicsMutexLockStatus status = epicsMutexLockError; + int pthreadStatus; + + pthreadStatus = pthread_mutex_lock(&pmutex->lock); + checkStatusQuit(pthreadStatus,"pthread_mutex_lock","epicsMutexTryLock"); + if(!pmutex->owned || pthread_equal(pmutex->ownerTid,tid)) { + pmutex->ownerTid = tid; + pmutex->owned = 1; + pmutex->count++; + status = 0; + } + pthreadStatus = pthread_mutex_unlock(&pmutex->lock); + checkStatusQuit(pthreadStatus,"pthread_mutex_unlock","epicsMutexTryLock"); + return(status); +} + +void epicsMutexShow(epicsMutexId id,unsigned int level) +{ + mutex *pmutex = (mutex *)id; + printf("ownerTid %p count %d owned %d\n", + pmutex->ownerTid,pmutex->count,pmutex->owned); +} diff --git a/src/libCom/osi/os/posix/osdMutex.h b/src/libCom/osi/os/posix/osdMutex.h new file mode 100644 index 000000000..078ad7200 --- /dev/null +++ b/src/libCom/osi/os/posix/osdMutex.h @@ -0,0 +1 @@ +/* for a pure posix implementation no osdMutex.h definitions are needed*/ diff --git a/src/libCom/osi/os/vxWorks/osdEvent.c b/src/libCom/osi/os/vxWorks/osdEvent.c new file mode 100644 index 000000000..00002842e --- /dev/null +++ b/src/libCom/osi/os/vxWorks/osdEvent.c @@ -0,0 +1,64 @@ +/* os/vxWorks/osdEvent.c */ + +/* Author: Marty Kraimer Date: 25AUG99 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +/* The following not defined in an vxWorks header */ +int sysClkRateGet(void); + +#include "epicsEvent.h" + +epicsEventId epicsEventCreate(epicsEventInitialState initialState) +{ + return((epicsEventId)semBCreate( + SEM_Q_FIFO,((initialState==epicsEventEmpty) ? SEM_EMPTY : SEM_FULL))); +} + +epicsEventId epicsEventMustCreate(epicsEventInitialState initialState) +{ + epicsEventId id = epicsEventCreate (initialState); + assert (id); + return id; +} + +void epicsEventDestroy(epicsEventId id) +{ + semDelete((SEM_ID)id); +} + +epicsEventWaitStatus epicsEventTakeWithTimeout( + epicsEventId id, double timeOut) +{ + int status; + int ticks; + ticks = (int)(timeOut * (double)sysClkRateGet()); + if(ticks<=0) ticks = 1; + status = semTake((SEM_ID)id,ticks); + if(status==OK) return(epicsEventWaitOK); + if(errno==S_objLib_OBJ_TIMEOUT) return(epicsEventWaitTimeout); + return(epicsEventWaitError); +} + +epicsEventWaitStatus epicsEventTryWait(epicsEventId id) +{ + int status; + status = semTake((SEM_ID)id,NO_WAIT); + if(status==OK) return(epicsEventWaitOK); + if(errno==S_objLib_OBJ_UNAVAILABLE) return(epicsEventWaitTimeout); + return(epicsEventWaitError); +} + +void epicsEventShow(epicsEventId id,unsigned int level) +{ + semShow((SEM_ID)id,level); +} diff --git a/src/libCom/osi/os/vxWorks/osdEvent.h b/src/libCom/osi/os/vxWorks/osdEvent.h new file mode 100644 index 000000000..0a4f75f6d --- /dev/null +++ b/src/libCom/osi/os/vxWorks/osdEvent.h @@ -0,0 +1,22 @@ +/* os/vxWorks/osdEvent.h */ + +/* Author: Marty Kraimer Date: 25AUG99 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include + +/* If the macro is replaced by inline it is necessary to say + static __inline__ + but then a warning message appears everywhere osdEvent.h is included +*/ + +#define epicsEventSignal(ID) semGive((SEM_ID)(ID)) + +#define epicsEventWait(ID) \ +(semTake((SEM_ID)(ID),WAIT_FOREVER)==OK ? epicsEventWaitOK : epicsEventWaitError) diff --git a/src/libCom/osi/os/vxWorks/osdMutex.c b/src/libCom/osi/os/vxWorks/osdMutex.c new file mode 100644 index 000000000..16749b7c5 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/osdMutex.c @@ -0,0 +1,65 @@ +/* os/vxWorks/osdMutex.c */ + +/* Author: Marty Kraimer Date: 25AUG99 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +/* The following not defined in an vxWorks header */ +int sysClkRateGet(void); + + +#include "epicsMutex.h" + +epicsMutexId epicsMutexCreate(void) +{ + return((epicsMutexId) + semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY)); +} + +epicsMutexId epicsMutexMustCreate(void) +{ + epicsMutexId id = epicsMutexCreate (); + assert (id); + return id; +} + +void epicsMutexDestroy(epicsMutexId id) +{ + semDelete((SEM_ID)id); +} + +epicsMutexLockStatus epicsMutexTakeWithTimeout( + epicsMutexId id, double timeOut) +{ + int status; + int ticks; + ticks = (int)(timeOut * (double)sysClkRateGet()); + if(ticks<=0) ticks = 1; + status = semTake((SEM_ID)id,ticks); + if(status==OK) return(epicsMutexLockOK); + if(errno==S_objLib_OBJ_TIMEOUT) return(epicsMutexLockTimeout); + return(epicsMutexLockError); +} + +epicsMutexLockStatus epicsMutexTryLock(epicsMutexId id) +{ + int status; + status = semTake((SEM_ID)id,NO_WAIT); + if(status==OK) return(epicsMutexLockOK); + if(errno==S_objLib_OBJ_UNAVAILABLE) return(epicsMutexLockTimeout); + return(epicsMutexLockError); +} + +void epicsMutexShow(epicsMutexId id,unsigned int level) +{ + semShow((SEM_ID)id,level); +} diff --git a/src/libCom/osi/os/vxWorks/osdMutex.h b/src/libCom/osi/os/vxWorks/osdMutex.h new file mode 100644 index 000000000..118f1626d --- /dev/null +++ b/src/libCom/osi/os/vxWorks/osdMutex.h @@ -0,0 +1,22 @@ +/* os/vxWorks/osdMutex.h */ + +/* Author: Marty Kraimer Date: 25AUG99 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include + +/* If the macro is replaced by inline it is necessary to say + static __inline__ + but then a warning message appears everywhere osdMutex.h is included +*/ + +#define epicsMutexUnlock(ID) semGive((SEM_ID)(ID)) + +#define epicsMutexLock(ID) \ +(semTake((SEM_ID)(ID),WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError) diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index a2e15aa7f..d8fc9bb90 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -14,14 +14,24 @@ ringPointerTestHost_SRCS += ringPointerTestMain.c ringPointerTest.c PROD += ringPointerTestHost OBJS_IOC += ringPointerTest +# Marty remover the following semBinaryTestHost_SRCS += semBinaryTestMain.c semBinaryTest.c PROD += semBinaryTestHost OBJS_IOC += semBinaryTest +# Marty remover the following semMutexTestHost_SRCS += semMutexTestMain.c semMutexTest.c PROD += semMutexTestHost OBJS_IOC += semMutexTest +epicsEventTestHost_SRCS += epicsEventTestMain.cpp epicsEventTest.cpp +PROD += epicsEventTestHost +OBJS_IOC += epicsEventTest + +epicsMutexTestHost_SRCS += epicsMutexTestMain.cpp epicsMutexTest.cpp +PROD += epicsMutexTestHost +OBJS_IOC += epicsMutexTest + threadTestHost_SRCS += threadTestMain.c threadTest.c PROD += threadTestHost OBJS_IOC += threadTest diff --git a/src/libCom/test/epicsEventTest.cpp b/src/libCom/test/epicsEventTest.cpp new file mode 100644 index 000000000..b8dd94770 --- /dev/null +++ b/src/libCom/test/epicsEventTest.cpp @@ -0,0 +1,168 @@ +/* epicsEventTest.cpp */ + +/* Author: Marty Kraimer Date: 26JAN2000 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "osiThread.h" +#include "epicsEvent.h" +#include "epicsMutex.h" +#include "epicsRingPointer.h" +#include "errlog.h" + + +typedef struct info { + epicsEventId event; + epicsMutexId lockRing; + int quit; + epicsRingPointerId ring; +}info; + +static void consumer(void *arg) +{ + info *pinfo = (info *)arg; + time_t tp; + threadId idSelf = threadGetIdSelf(); + + printf("consumer %p starting time %ld\n",idSelf,time(&tp)); + while(1) { + epicsEventWaitStatus status; + if(pinfo->quit) { + printf("consumer %p returning time %ld\n", + idSelf,time(&tp)); + return; + } + status = epicsEventWait(pinfo->event); + if(status!=epicsEventWaitOK) { + printf("task %p epicsEventWait returned %d time %ld\n", + idSelf,(int)status,time(&tp)); + } + while(epicsRingPointerGetUsed(pinfo->ring)>=2) { + threadId message[2]; + int i; + + for(i=0; i<2; i++) { + if(!(message[i]=epicsRingPointerPop(pinfo->ring))) + printf("consumer error\n"); + } + if(message[0]!=message[1]) { + printf("consumer error message %p %p\n",message[0],message[1]); + } else { + printf("consumer message from %p\n",message[0]); + } + } + } +} + +static void producer(void *arg) +{ + info *pinfo = (info *)arg; + time_t tp; + threadId idSelf = threadGetIdSelf(); + int ntimes=0; + + printf("producer %p starting time %ld\n",idSelf,time(&tp)); + while(1) { + epicsMutexLockStatus status; + + ++ntimes; + if(pinfo->quit) { + printf("producer %p returning time %ld\n", + idSelf,time(&tp)); + return; + } + status = epicsMutexLock(pinfo->lockRing); + if(status!=epicsMutexLockOK) { + printf("producer %p epicsMutexLock returned %d time %ld\n", + idSelf,(int)status,time(&tp)); + } + if(epicsRingPointerGetFree(pinfo->ring)>=2) { + int i; + + for(i=0; i<2; i++) { + if(!epicsRingPointerPush(pinfo->ring,idSelf)) + printf("producer %p error\n",idSelf); + if(i==0 && (ntimes%4==0)) threadSleep(.1); + } + printf("producer %p sending\n",idSelf); + } else { + printf("producer %p ring buffer is full\n",idSelf); + } + epicsMutexUnlock(pinfo->lockRing); + threadSleep(1.0); + epicsEventSignal(pinfo->event); + } +} + +extern "C" void epicsEventTest(int nthreads,int verbose) +{ + unsigned int stackSize; + threadId *id; + char **name; + int i; + info *pinfo; + epicsEventId event; + int status; + time_t tp; + int errVerboseSave = errVerbose; + + threadInit (); + errVerbose = verbose; + event = epicsEventMustCreate(epicsEventEmpty); + printf("calling epicsEventWaitWithTimeout(event,2.0) time %ld\n",time(&tp)); + status = epicsEventWaitWithTimeout(event,2.0); + if(status!=epicsEventWaitTimeout) printf("status %d\n",status); + printf("calling epicsEventTryWait(event) time %ld\n",time(&tp)); + status = epicsEventTryWait(event); + if(status!=epicsEventWaitTimeout) printf("status %d\n",status); + printf("calling epicsEventSignal() time %ld\n",time(&tp)); + epicsEventSignal(event); + printf("calling epicsEventWaitWithTimeout(event,2.0) time %ld\n",time(&tp)); + status = epicsEventWaitWithTimeout(event,2.0); + if(status) printf("status %d\n",status); + printf("calling epicsEventSignal() time %ld\n",time(&tp)); + epicsEventSignal(event); + printf("calling epicsEventTryWait(event) time %ld\n",time(&tp)); + status = epicsEventTryWait(event); + if(status) printf("status %d\n",status); + + if(nthreads<=0) { + errVerbose = errVerboseSave; + return; + } + pinfo = (info *)calloc(1,sizeof(info)); + pinfo->event = event; + pinfo->lockRing = epicsMutexCreate(); + pinfo->ring = epicsRingPointerCreate(1024*2); + stackSize = threadGetStackSize(threadStackSmall); + threadCreate("consumer",50,stackSize,consumer,pinfo); + id = (threadId *)calloc(nthreads,sizeof(threadId)); + name = (char **)calloc(nthreads,sizeof(char *)); + for(i=0; iquit = 1; + threadSleep(2.0); + epicsEventSignal(pinfo->event); + threadSleep(1.0); + printf("semTest returning time %ld\n",time(&tp)); + errVerbose = errVerboseSave; +} diff --git a/src/libCom/test/epicsEventTestMain.cpp b/src/libCom/test/epicsEventTestMain.cpp new file mode 100644 index 000000000..cbedf2d71 --- /dev/null +++ b/src/libCom/test/epicsEventTestMain.cpp @@ -0,0 +1,46 @@ +/* epicsEventTestMain.cpp */ + +/* Author: Marty Kraimer Date: 26JAN2000 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "osiThread.h" +extern "C" void epicsEventTest(int nthreads,int errVerbose); + + +int main(int argc,char *argv[]) +{ + int nthreads = 2; + int errVerbose = 0; + + if(argc>1) { + if(isdigit(*argv[1])) { + sscanf(argv[1],"%d",&nthreads); + printf("nthreads %d\n",nthreads); + } else { + printf("Illegal argument %s\n",argv[1]); + } + } + if(argc>2) { + if(isdigit(*argv[2])) { + sscanf(argv[2],"%d",&errVerbose); + printf("errVerbose %d\n",errVerbose); + } else { + printf("Illegal argument %s\n",argv[1]); + } + } + epicsEventTest(nthreads,errVerbose); + printf("main terminating\n"); + return(0); +} diff --git a/src/libCom/test/epicsMutexTest.cpp b/src/libCom/test/epicsMutexTest.cpp new file mode 100644 index 000000000..f1919d598 --- /dev/null +++ b/src/libCom/test/epicsMutexTest.cpp @@ -0,0 +1,116 @@ +/* epicsMutexTest.c */ + +/* Author: Marty Kraimer Date: 26JAN2000 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "osiThread.h" +#include "epicsMutex.h" +#include "errlog.h" + + +typedef struct info { + int threadnum; + epicsMutexId mutex; + int quit; +}info; + +static void mutexThread(void *arg) +{ + info *pinfo = (info *)arg; + time_t tp; + printf("mutexThread %d starting time %ld\n",pinfo->threadnum,time(&tp)); + while(1) { + epicsMutexLockStatus status; + if(pinfo->quit) { + printf("mutexThread %d returning time %ld\n", + pinfo->threadnum,time(&tp)); + return; + } + status = epicsMutexLock(pinfo->mutex); + if(status!=epicsMutexLockOK) { + printf("task %d epicsMutexLock returned %d time %ld\n", + pinfo->threadnum,(int)status,time(&tp)); + } + printf("mutexThread %d epicsMutexLock time %ld\n", + pinfo->threadnum,time(&tp)); + threadSleep(.1); + epicsMutexUnlock(pinfo->mutex); + threadSleep(.9); + } +} + +extern "C" void epicsMutexTest(int nthreads,int verbose) +{ + unsigned int stackSize; + threadId *id; + int i; + char **name; + void **arg; + info **pinfo; + epicsMutexId mutex; + int status; + time_t tp; + int errVerboseSave = errVerbose; + + threadInit (); + errVerbose = verbose; + mutex = epicsMutexMustCreate(); + printf("calling epicsMutexLock(mutex) time %ld\n",time(&tp)); + status = epicsMutexLock(mutex); + if(status) printf("status %d\n",status); + printf("calling epicsMutexLockWithTimeout(mutex,2.0) time %ld\n",time(&tp)); + status = epicsMutexLockWithTimeout(mutex,2.0); + if(status) printf("status %d\n",status); + printf("calling epicsMutexTryLock(mutex) time %ld\n",time(&tp)); + status = epicsMutexTryLock(mutex); + if(status) printf("status %d\n",status); + epicsMutexShow(mutex,1); + printf("calling epicsMutexUnlock() time %ld\n",time(&tp)); + epicsMutexUnlock(mutex); + printf("calling epicsMutexUnlock() time %ld\n",time(&tp)); + epicsMutexUnlock(mutex); + printf("calling epicsMutexUnlock() time %ld\n",time(&tp)); + epicsMutexUnlock(mutex); + epicsMutexShow(mutex,1); + + if(nthreads<=0) { + errVerbose = errVerboseSave; + return; + } + id = (void **)calloc(nthreads,sizeof(threadId)); + name = (char **)calloc(nthreads,sizeof(char *)); + arg = (void **)calloc(nthreads,sizeof(void *)); + pinfo = (info **)calloc(nthreads,sizeof(info *)); + stackSize = threadGetStackSize(threadStackSmall); + for(i=0; ithreadnum = i; + pinfo[i]->mutex = mutex; + arg[i] = pinfo[i]; + id[i] = threadCreate(name[i],40,stackSize,(THREADFUNC)mutexThread,arg[i]); + printf("semTest created mutexThread %d id %p time %ld\n", + i, id[i],time(&tp)); + } + threadSleep(5.0); + printf("semTest setting quit time %ld\n",time(&tp)); + for(i=0; iquit = 1; + } + threadSleep(2.0); + errVerbose = errVerboseSave; +} diff --git a/src/libCom/test/epicsMutexTestMain.cpp b/src/libCom/test/epicsMutexTestMain.cpp new file mode 100644 index 000000000..ff862ef01 --- /dev/null +++ b/src/libCom/test/epicsMutexTestMain.cpp @@ -0,0 +1,46 @@ +/* epicsMutexTestMain.c */ + +/* Author: Marty Kraimer Date: 26JAN2000 */ + +/********************COPYRIGHT NOTIFICATION********************************** +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "osiThread.h" +extern "C" void epicsMutexTest(int nthreads,int errVerbose); + + +int main(int argc,char *argv[]) +{ + int nthreads = 2; + int errVerbose = 0; + + if(argc>1) { + if(isdigit(*argv[1])) { + sscanf(argv[1],"%d",&nthreads); + printf("nthreads %d\n",nthreads); + } else { + printf("Illegal argument %s\n",argv[1]); + } + } + if(argc>2) { + if(isdigit(*argv[2])) { + sscanf(argv[2],"%d",&errVerbose); + printf("errVerbose %d\n",errVerbose); + } else { + printf("Illegal argument %s\n",argv[1]); + } + } + epicsMutexTest(nthreads,errVerbose); + printf("main terminating\n"); + return(0); +}