Skip to content

Commit ac00e16

Browse files
committed
upump-ev: use ev_async to notify remote event loop
Use ev_async to notify remote event loop when an event is started from another loop. From man ev: ev_set_loop_release_cb [...] While event loop modifications are allowed between invocations of "release" and "acquire" (that's their only purpose after all), no modifications done will affect the event loop, i.e. adding watchers will have no effect on the set of file descriptors being watched, or the time waited. Use an "ev_async" watcher to wake up "ev_run" when you want it to take note of any changes you made. [...]
1 parent c50602d commit ac00e16

1 file changed

Lines changed: 46 additions & 5 deletions

File tree

lib/upump-ev/upump_ev.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2012-2018 OpenHeadend S.A.R.L.
3+
* Copyright (C) 2026 EasyTools
34
*
45
* Authors: Christophe Massiot
56
*
@@ -30,9 +31,16 @@ struct upump_ev_mgr {
3031

3132
/** ev private structure */
3233
struct ev_loop *ev_loop;
34+
/** watcher to wake up the event loop from a remote event loop */
35+
struct ev_async ev_async;
3336
/** true if the loop has to be destroyed at the end */
3437
bool destroy;
3538

39+
/** current mutex used if any */
40+
struct umutex *umutex;
41+
/** current ev_async configured if any */
42+
struct ev_async *async;
43+
3644
/** common structure */
3745
struct upump_common_mgr common_mgr;
3846

@@ -215,6 +223,10 @@ static void upump_ev_real_start(struct upump *upump, bool status)
215223
}
216224
if (!status)
217225
ev_unref(ev_mgr->ev_loop);
226+
227+
if (ev_mgr->async)
228+
/* wake up remote event loop to take account for this event */
229+
ev_async_send(ev_mgr->ev_loop, ev_mgr->async);
218230
}
219231

220232
/** @This stops a pump.
@@ -373,8 +385,9 @@ static int upump_ev_control(struct upump *upump, int command, va_list args)
373385
**/
374386
static void upump_ev_mgr_lock(struct ev_loop *loop)
375387
{
376-
struct umutex *mutex = ev_userdata(loop);
377-
umutex_lock(mutex);
388+
struct upump_ev_mgr *ev_mgr = ev_userdata(loop);
389+
umutex_lock(ev_mgr->umutex);
390+
ev_mgr->async = NULL;
378391
}
379392

380393
/** @internal @This is called when the event loop goes to sleep.
@@ -383,8 +396,24 @@ static void upump_ev_mgr_lock(struct ev_loop *loop)
383396
**/
384397
static void upump_ev_mgr_unlock(struct ev_loop *loop)
385398
{
386-
struct umutex *mutex = ev_userdata(loop);
387-
umutex_unlock(mutex);
399+
struct upump_ev_mgr *ev_mgr = ev_userdata(loop);
400+
/* configure async event so remote event loops can wake us up if they start
401+
* events in this event loop.
402+
*
403+
* From man ev:
404+
*
405+
* ev_set_loop_release_cb
406+
* [...]
407+
* While event loop modifications are allowed between invocations of
408+
* "release" and "acquire" (that's their only purpose after all), no
409+
* modifications done will affect the event loop, i.e. adding watchers
410+
* will have no effect on the set of file descriptors being watched, or
411+
* the time waited. Use an "ev_async" watcher to wake up "ev_run" when you
412+
* want it to take note of any changes you made.
413+
* [...]
414+
*/
415+
ev_mgr->async = &ev_mgr->ev_async;
416+
umutex_unlock(ev_mgr->umutex);
388417
}
389418

390419
/** @internal @This runs an event loop.
@@ -397,9 +426,10 @@ static void upump_ev_mgr_unlock(struct ev_loop *loop)
397426
static int upump_ev_mgr_run(struct upump_mgr *mgr, struct umutex *mutex)
398427
{
399428
struct upump_ev_mgr *ev_mgr = upump_ev_mgr_from_upump_mgr(mgr);
429+
ev_mgr->umutex = mutex;
400430

401431
if (mutex != NULL) {
402-
ev_set_userdata(ev_mgr->ev_loop, mutex);
432+
ev_set_userdata(ev_mgr->ev_loop, ev_mgr);
403433
ev_set_loop_release_cb(ev_mgr->ev_loop,
404434
upump_ev_mgr_unlock, upump_ev_mgr_lock);
405435

@@ -456,6 +486,13 @@ static void upump_ev_mgr_free(struct urefcount *urefcount)
456486
free(ev_mgr);
457487
}
458488

489+
/** @internal @This is called when an async ev is raised. */
490+
static void upump_ev_mgr_async_cb(struct ev_loop *loop, struct ev_async *w,
491+
int revents)
492+
{
493+
/* nothing to do */
494+
}
495+
459496
/** @This allocates and initializes a upump_ev_mgr structure.
460497
*
461498
* @param ev_loop pointer to an ev loop
@@ -490,6 +527,10 @@ struct upump_mgr *upump_ev_mgr_alloc(struct ev_loop *ev_loop,
490527

491528
ev_mgr->ev_loop = ev_loop;
492529
ev_mgr->destroy = false;
530+
ev_mgr->async = NULL;
531+
ev_async_init(&ev_mgr->ev_async, upump_ev_mgr_async_cb);
532+
ev_async_start(ev_loop, &ev_mgr->ev_async);
533+
ev_unref(ev_loop);
493534
return mgr;
494535
}
495536

0 commit comments

Comments
 (0)