I've found myself writing the slightly clunky block of code below and was wondering whether the gap in the OSI library thus revealed is readily fixed and worth fixing, or whether I've missed a more direct way to do this.
I have a number of threads that need to block until iocInit has finished initialisation, so the natural solution is to use initHookRegister() and block until initHookAtEnd occurs. I can't safely call initHookRegister() for each waiting thread, because I might be too late, so it's simplest to call it once and signal everybody when the desired event occurs ... and there appears to be no straightforward way to do this, no mechanism equivalent to pthread_cond_broadcast().
I attach the code I've had to write. Have I missed a simpler way to do this? (Note, I've not run this code yet, so there may be some stupid bug in it.)
Assuming I've not missed anything in OSI this begs the question of whether OSI can readily be extended to support pthread condition variables or something equivalent, whether the associated implementations are feasible, and whether this is worth doing.
I found this page interesting: http://borkhuis.home.xs4all.nl/vxworks/vxw_pt5.html#5.5 Section 5.5 says "pthreads [have been ported] from Linux to VxWorks ... The only thing missing is condition variables. They turned out to be kind of hard." I'm sure this problem has been visited before, but thought I ought to comment.
---- epics_ready.h ----
/* Simple API for blocking until EPICS has finished initialisation. */
/* Must be called early, both before any call to wait_for_epics_ready() and
* before iocInit has been called. */
void initialise_epics_ready(void);
/* If EPICS hasn't finished startup this will block until done. */
void wait_for_epics_ready(void);
---- epics_ready.c ----
#include <stdbool.h>
#include <stdlib.h>
#include <epicsEvent.h>
#include <epicsMutex.h>
#include <initHooks.h>
#include "epics_ready.h"
/* Set once EPICS startup has completed. */
static bool epics_ready = false;
/* Used to guard access to the waiting list. */
static epicsMutexId epics_ready_mutex;
/* Alas the EPICS OSI does not appear to provide any mechanism (akin to the
* pthread condition variable) for waking more than one waiting thread at a
* time. So here we roll our own waiting list. Note that the waiters are woken
* in reverse order of waiting, but I don't care (easy to fix). */
static struct epics_ready_waiter {
struct epics_ready_waiter *next;
epicsEventId event;
} *epics_ready_list = NULL;
static void epics_init_hook(initHookState state)
{
if (state == initHookAtEnd)
{
struct epics_ready_waiter *waiter, *next;
epicsMutexMustLock(epics_ready_mutex);
epics_ready = true;
for (waiter = epics_ready_list; waiter != NULL; waiter = next)
{
/* Note that calling epicsEventSignal() may invalidate waiter, so
* have to pick up next pointer first. */
next = waiter->next;
epicsEventSignal(waiter->event);
}
epicsMutexUnlock(epics_ready_mutex);
}
}
void wait_for_epics_ready(void)
{
if (!epics_ready)
{
struct epics_ready_waiter *waiter = NULL;
epicsMutexMustLock(epics_ready_mutex);
if (!epics_ready)
{
waiter = malloc(sizeof(struct epics_ready_waiter));
waiter->event = epicsEventMustCreate(epicsEventEmpty);
waiter->next = epics_ready_list;
epics_ready_list = waiter;
}
epicsMutexUnlock(epics_ready_mutex);
if (waiter != NULL)
{
epicsEventMustWait(waiter->event);
epicsEventDestroy(waiter->event);
free(waiter);
}
}
}
void initialise_epics_ready(void)
{
epics_ready_mutex = epicsMutexMustCreate();
initHookRegister(epics_init_hook);
}
By contrast, here is exactly the same functionality implemented using pthread condition variables:
---- epics_ready_pthread.c ----
#include <stdbool.h>
#include <stdlib.h>
#include <pthread.h>
#include <initHooks.h>
#include "epics_ready.h"
/* Set once EPICS startup has completed. */
static bool epics_ready = false;
/* An pthread condition has to come with an associated mutex. */
static pthread_mutex_t epics_ready_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t epics_ready_cond = PTHREAD_COND_INITIALIZER;
static void epics_init_hook(initHookState state)
{
if (state == initHookAtEnd)
{
pthread_mutex_lock(&epics_ready_mutex);
epics_ready = true;
pthread_cond_broadcast(&epics_ready_cond);
pthread_mutex_unlock(&epics_ready_mutex);
}
}
void wait_for_epics_ready(void)
{
if (!epics_ready)
{
pthread_mutex_lock(&epics_ready_mutex);
while (!epics_ready)
pthread_cond_wait(&epics_ready_cond, &epics_ready_mutex);
pthread_mutex_unlock(&epics_ready_mutex);
}
}
void initialise_epics_ready(void)
{
initHookRegister(epics_init_hook);
}
--
This e-mail and any attachments may contain confidential, copyright and or privileged material, and are for the use of the intended addressee only. If you are not the intended addressee or an authorised recipient of the addressee please notify us of receipt by returning the e-mail and do not use, copy, retain, distribute or disclose the information in or attached to the e-mail.
Any opinions expressed within this e-mail are those of the individual and not necessarily of Diamond Light Source Ltd.
Diamond Light Source Ltd. cannot guarantee that this e-mail or any attachments are free from viruses and we cannot accept liability for any damage which you may sustain as a result of software viruses which may be transmitted in or with the message.
Diamond Light Source Limited (company no. 4375679). Registered in England and Wales with its registered office at Diamond House, Harwell Science and Innovation Campus, Didcot, Oxfordshire, OX11 0DE, United Kingdom
- Replies:
- RE: EPICS OSI and events Mark Rivers
- Navigate by Date:
- Prev:
Delay problem in ca_array_put() command Perrier Pierre
- Next:
RE: EPICS OSI and events Mark Rivers
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
<2011>
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
RE: Delay problem in ca_array_put() command Jeff Hill
- Next:
RE: EPICS OSI and events Mark Rivers
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
<2011>
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|