linguini1 opened a new pull request, #20197:
URL: https://github.com/apache/nuttx/pull/20197

   ## Summary
   
   Implements the `pthread_sigqueue` function. **NOTE:** I am unsure if I have 
to add this function to the syscall lookup and CSV like `pthread_sigmask`?
   
   ### docs/pthread: Document pthread_sigqueue
       
   Documents the new implementation of pthread_sigqueue.
   
   ### sched/pthread: Implement pthread_sigqueue
       
   Implements the pthread_sigqueue Linux extension to pthreads. Follows a 
similar implementation to sigqueue, except targeting a specific thread through 
nxsig_dispatch.
   
   ## Impact
   
   Closes #20163.
   
   Users can now queue signals to pthreads using this Linux extension interface.
   
   ## Testing
   
   Tested using a custom application which uses a pthread to handle POSIX timer 
events. When it is time to clean up the thread, `pthread_sigqueue` is used to 
send `SIGABRT` which kills the thread.
   
   Main program cancelling thread:
   
   ```c
         cancelval.sival_ptr = NULL;
         err = pthread_sigqueue(g_thread, THREAD_CANCEL_SIG, cancelval);
         if (err)
           {
             syslog(LOG_ERR | LOG_USER,
                    "Couldn't send timer thread cancel signal: %d\n", err);
   
             /* No point joining if we couldn't cancel. */
   
             goto clean_topics;
           }
   
         err = pthread_join(g_thread, &threadret);
         if (err)
           {
             syslog(LOG_ERR | LOG_USER, "Couldn't join to timer thread: %d\n",
                    err);
             goto clean_topics;
           }
   
         syslog(LOG_INFO | LOG_USER, "Timer thread exited with status %d\n",
                (int)threadret);
   ```
   
   Thread logic:
   
   ```c
   static void *timer_thread(void *arg)
   {
     int err;
     int dep_fd = (int)arg;
     sigset_t set;
     siginfo_t info;
     struct pyrochan_s *chan;
   
     syslog(LOG_INFO | LOG_USER, "Timer thread started.\n");
   
     /* Configure the set of signals we're waiting for (just timer signals) */
   
     err = sigemptyset(&set);
     if (err < 0)
       {
         syslog(LOG_ERR | LOG_USER, "Couldn't configure signal set: %d\n",
                errno);
         return (void *)(uintptr_t)errno;
       }
   
     err = sigaddset(&set, TIMER_SIG); /* We wait for timer signal */
     if (err < 0)
       {
         syslog(LOG_ERR | LOG_USER, "Couldn't configure signal set: %d\n",
                errno);
         return (void *)(uintptr_t)errno;
       }
   
     /* We also allow a cancellation signal */
   
     err = sigaddset(&set, THREAD_CANCEL_SIG);
     if (err < 0)
       {
         syslog(LOG_ERR | LOG_USER, "Couldn't configure signal set: %d\n",
                errno);
         return (void *)(uintptr_t)errno;
       }
   
     /* We specifically unblock the timer signal from this thread's set of
      * blocked signals.
      */
   
     err = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
     if (err)
       {
         syslog(LOG_ERR | LOG_USER, "Couldn't unblock timer signal: %d\n", err);
         return (void *)(uintptr_t)err;
       }
   
     /* We are waiting for the timer signal. */
   
     for (;;)
       {
         /* Block until we receive a signal, with continue to re-block on
          * spurious wake-ups.
          */
   
         err = sigwaitinfo(&set, &info);
         if (err < 0)
           {
             syslog(LOG_ERR | LOG_USER,
                    "Error while waiting for timer signal: %d", errno);
             continue;
           }
   
         /* If this was a cancellation signal, stop execution and return */
   
         if (info.si_signo == THREAD_CANCEL_SIG)
           {
             syslog(LOG_INFO | LOG_USER, "Timer thread cancelled.\n");
             return 0;
           }
   
         /* Handle the timer expiration by deploying the channel and indicating
          * the deployment event.
          */
   
         chan = (struct pyrochan_s *)info.si_value.sival_ptr;
   
         err = channel_fire(chan);
         if (err == 0)
           {
             err = publish_deployment(dep_fd, chan->id);
   
             /* Not really much to do if this fails; we continue so we can fire
              * any other timer-based channels.
              */
           }
   
         /* Clean up the expired timer */
   
         err = timer_delete(chan->timerid);
         if (err < 0)
           {
             syslog(LOG_ERR | LOG_USER, "Couldn't clean up expired timer: %d\n",
                    errno);
           }
       }
   
     return 0;
   }
   ```
   
   Log output:
   
   ```
   pthread_sigqueue: tid=19 sig=10 value=0                     
   nxsig_tcbdispatch: TCB=0x3fcb1cf8 pid=19 signo=10 code=1 value=0
   Timer thread cancelled.
   nx_pthread_exit: exit_value=0
   pthread_completejoin: pid=19 exit_value=0
   nxtask_exit: deployment pid=19,TCB=0x3fcb1cf8
   pthread_join: Returning 0, exit_value 0
   Timer thread exited with status 0
   nxsig_tcbdispatch: TCB=0x3fca79b0 pid=7 signo=17 code=5 value=0 masked=NO
   nxsig_tcbdispatch: Group 0x3fca7a90
   nxtask_exit: deployment pid=16,TCB=0x3fcad620
   Service 'deployment' pid 16 exited status 1
   Removing service 'deployment' ...
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to