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 **/
374386static 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 **/
384397static 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)
397426static 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