@@ -240,31 +240,52 @@ struct sighook {
240240 sighook_fn * fn ;
241241 /** An argument to pass to the function. */
242242 void * arg ;
243+
244+ /** The RCU pointer to this hook. */
245+ struct rcu * self ;
243246 /** The next hook in the list. */
244247 struct rcu next ;
245248};
246249
247- /** Add a hook to a linked list. */
248- static void sigpush (struct rcu * rcu , struct sighook * hook ) {
249- struct sighook * next = rcu_peek (rcu );
250- rcu_init (& hook -> next , next );
251- rcu_update (rcu , hook );
250+ /**
251+ * An RCU-protected linked list of signal hooks.
252+ */
253+ struct siglist {
254+ /** The first hook in the list. */
255+ struct rcu head ;
256+ /** &last->next */
257+ struct rcu * tail ;
258+ };
259+
260+ /** Initialize a siglist. */
261+ static void siglist_init (struct siglist * list ) {
262+ rcu_init (& list -> head , NULL );
263+ list -> tail = & list -> head ;
264+ }
265+
266+ /** Append a hook to a linked list. */
267+ static void sigpush (struct siglist * list , struct sighook * hook ) {
268+ hook -> self = list -> tail ;
269+ list -> tail = & hook -> next ;
270+ rcu_init (& hook -> next , NULL );
271+ rcu_update (hook -> self , hook );
252272}
253273
254274/** Remove a hook from the linked list. */
255- static void sigpop (struct rcu * rcu , struct sighook * hook ) {
275+ static void sigpop (struct siglist * list , struct sighook * hook ) {
256276 struct sighook * next = rcu_peek (& hook -> next );
257- rcu_update (rcu , next );
277+ rcu_update (hook -> self , next );
278+ if (next ) {
279+ next -> self = hook -> self ;
280+ }
258281}
259282
260283/** The lists of signal hooks. */
261- static struct rcu rcu_sighooks [64 ];
262- /** The list of atsigexit() hooks. */
263- static struct rcu rcu_exithooks ;
284+ static struct siglist sighooks [64 ];
264285
265286/** Get the hook list for a particular signal. */
266- static struct rcu * siglist (int sig ) {
267- return & rcu_sighooks [sig % countof (rcu_sighooks )];
287+ static struct siglist * siglist (int sig ) {
288+ return & sighooks [sig % countof (sighooks )];
268289}
269290
270291/** Mutex for initialization and RCU writer exclusion. */
@@ -365,11 +386,11 @@ static noreturn void reraise(int sig) {
365386}
366387
367388/** Find any matching hooks and run them. */
368- static enum sigflags run_hooks (struct rcu * rcu , int sig , siginfo_t * info ) {
389+ static enum sigflags run_hooks (struct siglist * list , int sig , siginfo_t * info ) {
369390 enum sigflags ret = 0 ;
370391
371392 struct arc * slot = NULL ;
372- struct sighook * hook = rcu_read (rcu , & slot );
393+ struct sighook * hook = rcu_read (& list -> head , & slot );
373394 while (hook ) {
374395 if (hook -> sig == sig || hook -> sig == 0 ) {
375396 hook -> fn (sig , info , hook -> arg );
@@ -407,12 +428,13 @@ static void sigdispatch(int sig, siginfo_t *info, void *context) {
407428 int error = errno ;
408429
409430 // Run the normal hooks
410- struct rcu * rcu = siglist (sig );
411- enum sigflags flags = run_hooks (rcu , sig , info );
431+ struct siglist * list = siglist (sig );
432+ enum sigflags flags = run_hooks (list , sig , info );
412433
413434 // Run the atsigexit() hooks, if we're exiting
414435 if (!(flags & SH_CONTINUE ) && is_fatal (sig )) {
415- run_hooks (& rcu_exithooks , sig , info );
436+ list = siglist (0 );
437+ run_hooks (list , sig , info );
416438 reraise (sig );
417439 }
418440
@@ -435,10 +457,9 @@ static int siginit(int sig) {
435457 return -1 ;
436458 }
437459
438- for (size_t i = 0 ; i < countof (rcu_sighooks ); ++ i ) {
439- rcu_init ( & rcu_sighooks [i ], NULL );
460+ for (size_t i = 0 ; i < countof (sighooks ); ++ i ) {
461+ siglist_init ( & sighooks [i ]);
440462 }
441- rcu_init (& rcu_exithooks , NULL );
442463
443464 initialized = true;
444465 }
@@ -462,7 +483,7 @@ static int siginit(int sig) {
462483}
463484
464485/** Shared sighook()/atsigexit() implementation. */
465- static struct sighook * sighook_impl (struct rcu * rcu , int sig , sighook_fn * fn , void * arg , enum sigflags flags ) {
486+ static struct sighook * sighook_impl (int sig , sighook_fn * fn , void * arg , enum sigflags flags ) {
466487 struct sighook * hook = ALLOC (struct sighook );
467488 if (!hook ) {
468489 return NULL ;
@@ -473,21 +494,21 @@ static struct sighook *sighook_impl(struct rcu *rcu, int sig, sighook_fn *fn, vo
473494 hook -> fn = fn ;
474495 hook -> arg = arg ;
475496
476- sigpush (rcu , hook );
497+ struct siglist * list = siglist (sig );
498+ sigpush (list , hook );
477499 return hook ;
478500}
479501
480502struct sighook * sighook (int sig , sighook_fn * fn , void * arg , enum sigflags flags ) {
503+ bfs_assert (sig > 0 );
504+
481505 mutex_lock (& sigmutex );
482506
483507 struct sighook * ret = NULL ;
484- if (siginit (sig ) ! = 0 ) {
485- goto done ;
508+ if (siginit (sig ) = = 0 ) {
509+ ret = sighook_impl ( sig , fn , arg , flags ) ;
486510 }
487511
488- struct rcu * rcu = siglist (sig );
489- ret = sighook_impl (rcu , sig , fn , arg , flags );
490- done :
491512 mutex_unlock (& sigmutex );
492513 return ret ;
493514}
@@ -508,7 +529,7 @@ struct sighook *atsigexit(sighook_fn *fn, void *arg) {
508529 }
509530#endif
510531
511- struct sighook * ret = sighook_impl (& rcu_exithooks , 0 , fn , arg , 0 );
532+ struct sighook * ret = sighook_impl (0 , fn , arg , 0 );
512533 mutex_unlock (& sigmutex );
513534 return ret ;
514535}
@@ -520,19 +541,8 @@ void sigunhook(struct sighook *hook) {
520541
521542 mutex_lock (& sigmutex );
522543
523- struct rcu * rcu ;
524- if (hook -> sig ) {
525- rcu = siglist (hook -> sig );
526- } else {
527- rcu = & rcu_exithooks ;
528- }
529-
530- struct sighook * node = rcu_peek (rcu );
531- while (node != hook ) {
532- rcu = & node -> next ;
533- node = rcu_peek (rcu );
534- }
535- sigpop (rcu , hook );
544+ struct siglist * list = siglist (hook -> sig );
545+ sigpop (list , hook );
536546
537547 mutex_unlock (& sigmutex );
538548
0 commit comments