@@ -56,6 +56,10 @@ USAGE... This file contains driver functions that are common
5656#include < callback.h>
5757#include < epicsThread.h>
5858#include < epicsExport.h>
59+ #include < epicsAtomic.h>
60+ #include < epicsExit.h>
61+ #include < epicsMutex.h>
62+ #include < ellLib.h>
5963#include < stdarg.h>
6064
6165#include " motor.h"
@@ -85,6 +89,48 @@ static void process_messages(struct driver_table *, epicsTime, double);
8589static struct mess_node *get_head_node (struct driver_table *);
8690static struct mess_node *motor_malloc (struct circ_queue *, epicsEvent *);
8791
92+ static epicsInt32 motorShutdown = 0 ;
93+ static epicsThreadOnceId motorShutdownOnce = EPICS_THREAD_ONCE_INIT;
94+ static epicsMutexId motorShutdownLock = 0 ;
95+ static ELLLIST motorShutdownWakeList;
96+
97+ typedef struct motorWakeNode {
98+ ELLNODE node;
99+ epicsEvent *ev;
100+ } motorWakeNode;
101+
102+ static void motorAtExit (void *arg)
103+ {
104+ epicsAtomicSetIntT (&motorShutdown, 1u );
105+
106+ /* Wake all motor_task() instances so they can see motorShutdown and exit. */
107+ if (!motorShutdownLock)
108+ {
109+ return ;
110+ }
111+ epicsMutexLock (motorShutdownLock);
112+ for (ELLNODE *n = ellFirst (&motorShutdownWakeList); n; n = ellNext (n))
113+ {
114+ motorWakeNode *wn = (motorWakeNode*)n;
115+ if (wn->ev )
116+ {
117+ wn->ev ->signal ();
118+ }
119+ }
120+ epicsMutexUnlock (motorShutdownLock);
121+ }
122+
123+ static void motorShutdownInitOnce (void *arg)
124+ {
125+ ellInit (&motorShutdownWakeList);
126+ motorShutdownLock = epicsMutexCreate ();
127+ epicsAtExit (motorAtExit, NULL );
128+ }
129+
130+ static void motorShutdownEnsureInit (void )
131+ {
132+ epicsThreadOnce (&motorShutdownOnce, motorShutdownInitOnce, NULL );
133+ }
88134
89135/*
90136 * FUNCION... motor_task()
@@ -141,7 +187,23 @@ epicsShareFunc int motor_task(struct thread_args *args)
141187 tabptr = args->table ;
142188 previous_time = epicsTime::getCurrent ();
143189 scan_sec = 1 / (double ) args->motor_scan_rate ; /* Convert HZ to seconds. */
144-
190+
191+ /* One-time registration of IOC shutdown hook + list init (reentrant-safe). */
192+ motorShutdownEnsureInit ();
193+
194+ /* Register this task's wake event so IOC shutdown can wake the wait(). */
195+ if (motorShutdownLock && tabptr && tabptr->semptr )
196+ {
197+ motorWakeNode *wn = (motorWakeNode*)calloc (1 , sizeof (*wn));
198+ if (wn)
199+ {
200+ wn->ev = tabptr->semptr ;
201+ epicsMutexLock (motorShutdownLock);
202+ ellAdd (&motorShutdownWakeList, &wn->node );
203+ epicsMutexUnlock (motorShutdownLock);
204+ }
205+ }
206+
145207 if (args->update_delay == 0.0 )
146208 stale_data_max_delay = 0.0 ;
147209 else if (args->update_delay < quantum * 2.0 )
@@ -180,6 +242,12 @@ epicsShareFunc int motor_task(struct thread_args *args)
180242 sem_ret = tabptr->semptr ->wait (wait_time);
181243 previous_time = epicsTime::getCurrent ();
182244
245+ /* IOC shutdown: motorAtExit() will signal semptr to wake us. */
246+ if (epicsAtomicGetIntT (&motorShutdown))
247+ {
248+ break ;
249+ }
250+
183251 if (*tabptr->any_inmotion_ptr )
184252 {
185253 if (tabptr->strtstat != NULL )
0 commit comments