Recall from our earlier discussions in the first chapter that Linux supports multi-threaded applications through lightweight processes. All LWPs of a threaded application are part of a process group and share signal handlers; each LWP (thread) maintains its own pending, and blocked signal queues.
The signal pointer of the task structure refers to the instance of type signal_struct, which is the signal descriptor. This structure is shared by all LWPs of a thread group and maintains elements such as a shared pending signal queue (for signals queued to a thread group), which is common to all threads in a process group.
The following figure represents the data structures involved in maintaining shared pending signals:
Following are a few important fields of signal_struct:
struct signal_struct {
atomic_t sigcnt;
atomic_t live;
int nr_threads;
struct list_head thread_head;
wait_queue_head_t wait_chldexit; /* for wait4() */
/* current thread group signal load-balancing target: */
struct task_struct *curr_target;
/* shared signal handling: */
struct sigpending shared_pending;
/* thread group exit support */
int group_exit_code;
/* overloaded:
* - notify group_exit_task when ->count is equal to notify_count
* - everyone except group_exit_task is stopped during signal delivery
* of fatal signals, group_exit_task processes the signal.
*/
int notify_count;
struct task_struct *group_exit_task;
/* thread group stop support, overloads group_exit_code too */
int group_stop_count;
unsigned int flags; /* see SIGNAL_* flags below */