Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
<== Date ==> <== Thread ==>

Subject: EPICS OSI and events
From: <michael.abbott@diamond.ac.uk>
To: <tech-talk@aps.anl.gov>
Date: Mon, 18 Jul 2011 13:05:32 +0000
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  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
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  <20112012  2013  2014  2015  2016  2017  2018  2019  2020 
ANJ, 18 Nov 2013 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·