--- crash-4.0-3.6/defs.h 2006-10-05 21:43:10.000000000 +0200 +++ crash-4.0-3.6-patch/defs.h 2006-10-09 10:42:17.000000000 +0200 @@ -838,6 +838,12 @@ int args; }; +#define HASH_TGID 64 +struct tgid_node { + struct tgid_node *next; + ulong tgid; +}; + struct reference { char *str; ulong cmdflags; --- crash-4.0-3.6/task.c 2006-10-05 21:43:10.000000000 +0200 +++ crash-4.0-3.6-patch/task.c 2006-10-09 11:10:11.000000000 +0200 @@ -17,6 +17,10 @@ #include "defs.h" +#define TASK_LEVEL 1 +#define TASK_GROUP_LEVEL 2 +#define TASK_INDENT2 4 + static ulong get_panic_context(void); static int sort_by_pid(const void *, const void *); static void show_ps(ulong, struct psinfo *); @@ -35,6 +39,7 @@ static void show_task_times(struct task_context *, ulong); static void show_task_args(struct task_context *); static void show_tgid_list(ulong); +static void show_tgid_sig_list(ulong); static int compare_start_time(const void *, const void *); static int start_time_timespec(void); static ulonglong convert_start_time(ulonglong, ulonglong); @@ -51,7 +56,7 @@ static void dump_prio_array(int, ulong, char *); static void task_struct_member(struct task_context *,ulong,struct reference *); static void signal_reference(struct task_context *, ulong, struct reference *); -static void dump_signal_data(struct task_context *); +static void dump_signal_data(struct task_context *, int); static int sigrt_minmax(int *, int *); static void signame_list(void); static void sigqueue_list(ulong); @@ -60,6 +65,10 @@ static void translate_sigset(ulonglong); static ulonglong sigaction_mask(ulong); static int task_has_cpu(ulong, char *); +static struct tgid_node ** alloc_hash_tgid(void); +static struct tgid_node * put_tgid(struct tgid_node **, ulong); +static void free_hash_tgid(struct tgid_node **); +static void list_hash_tgid(struct tgid_node **); static int is_foreach_keyword(char *, int *); static char *task_pointer_string(struct task_context *, ulong, char *); static int panic_context_adjusted(struct task_context *tc); @@ -2954,7 +2963,6 @@ fprintf(fp, "\n"); } - /* * Return the first task found that belongs to a pid. */ @@ -4258,7 +4266,114 @@ foreach(fd); } +/* + * Allocate a table of HASH_TGID hash lists. +*/ +static struct tgid_node ** +alloc_hash_tgid(void) +{ + struct tgid_node **p; + /* + p= (struct tgid_node**)calloc(sizeof(struct tgid_node*) , HASH_TGID); + if (!p) + error(FATAL,"cannot malloc hash_tgid\n"); + */ + p= (struct tgid_node**)GETBUF(sizeof(struct tgid_node*) * HASH_TGID); + return p; +} +/* + * If the tgid is already in a hash list (it has been used), NULL is returned ; + * otherwise, the new node address is returned. + */ +static struct tgid_node * +put_tgid(struct tgid_node **hash_tgid, ulong tgid) +{ + struct tgid_node *prev_node, *curr_node, *new_node; + ulong cell = (tgid % HASH_TGID); + if (CRASHDEBUG(1)) + fprintf(fp, "cell %lu: ", cell); + for (prev_node=curr_node=*(hash_tgid + cell); + curr_node; prev_node=curr_node, curr_node=curr_node->next) { + if(curr_node) { + if (CRASHDEBUG(1)) + fprintf(fp,"%lu ", curr_node->tgid); + if (tgid > curr_node->tgid) + continue; + if (tgid == curr_node->tgid) { + fprintf(fp, "E\n"); + return NULL; + } + break; + } + if (curr_node==prev_node && !curr_node->next) /* Just one node. */ + break; + } + /* + new_node = (struct tgid_node*)malloc(sizeof(struct tgid_node)); + if (!new_node) + error(FATAL, "cannot malloc tgid_node\n"); + */ + new_node = (struct tgid_node*)GETBUF(sizeof(struct tgid_node)); + if (CRASHDEBUG(1)) { + fprintf(fp,"%lu ", tgid); + fprintf(fp,"N\n"); + } + new_node->tgid = tgid; + new_node->next = NULL; + if (!prev_node || curr_node==prev_node) { /* First node or before first node. */ + *(hash_tgid + cell)=new_node; + if(prev_node) + new_node->next = prev_node->next; + } else if (curr_node) { /* Midle node. */ + prev_node->next = new_node; + new_node->next = curr_node->next; + } else /* Last node. */ + prev_node->next = new_node; + return new_node; +} +static void +free_hash_tgid(struct tgid_node **hash_tgid) +{ + struct tgid_node **p, **p_end, *tn, *tn2; + p_end = hash_tgid+HASH_TGID; + for (p=hash_tgid; p < p_end; p++) { + if (CRASHDEBUG(1)) + fprintf(fp,"cell %p: ",p); + tn=*p; + while(tn){ + if (CRASHDEBUG(1)) + fprintf(fp,"%lu ",tn->tgid); + tn2=tn->next; + /* + free((void*)tn); + */ + FREEBUF((char*)tn); + tn=tn2; + } + if (CRASHDEBUG(1)) + fprintf(fp, "\n\n"); + } + /* + free((void *)hash_tgid); + */ + FREEBUF((char *)hash_tgid); +} +static void +list_hash_tgid(struct tgid_node **hash_tgid) +{ + struct tgid_node **p, **p_end, *tn; + p_end = hash_tgid+HASH_TGID; + for (p=hash_tgid; p < p_end; p++) { + tn=*p; + fprintf(fp,"cell %p: ",tn); + while(tn){ + fprintf(fp,"(%p %lu) ",tn->next,tn->tgid); + tn=tn->next; + } + fprintf(fp,"\n\n"); + } +} /* * Do the work for cmd_foreach(). */ @@ -4273,6 +4388,8 @@ ulong cmdflags; struct reference reference, *ref; struct bt_info bt_info, *bt; + struct tgid_node **hash_tgid=NULL; + ulong tgid; /* * Filter out any command/option issues. @@ -4453,7 +4570,7 @@ if (fd->reference) { BZERO(ref, sizeof(struct reference)); ref->str = fd->reference; - } else + } else if (hash_tgid==NULL) print_task_header(fp, tc, subsequent++); for (k = 0; k < fd->keys; k++) { @@ -4527,8 +4644,19 @@ case FOREACH_SIG: pc->curcmd = "sig"; + if (fd->flags & FOREACH_g_FLAG) { + static int first_pass=TRUE; + if (first_pass) { + hash_tgid=alloc_hash_tgid(); + first_pass = FALSE; + } + tgid = task_tgid(tc->task); + if (put_tgid(hash_tgid,tgid)) + show_tgid_sig_list(tc->task); + } else { do_sig(tc->task, FOREACH_SIG, fd->reference ? ref : NULL); + } break; case FOREACH_SET: @@ -4578,7 +4706,6 @@ pc->curcmd = "foreach"; } } - /* * Post-process any commands requiring it. */ @@ -4592,6 +4719,14 @@ nlm_files_dump(); } break; + case FOREACH_SIG: + if (CRASHDEBUG(1)) + list_hash_tgid(hash_tgid); + if (fd->flags & FOREACH_g_FLAG) { + pc->curcmd = "sig"; + free_hash_tgid(hash_tgid); + } + break; } } @@ -5936,13 +6071,14 @@ struct task_context *tc; ulong *tasklist; char *siglist; + int task_group=FALSE; tasklist = (ulong *)GETBUF((MAXARGS+NR_CPUS)*sizeof(ulong)); ref = (struct reference *)GETBUF(sizeof(struct reference)); siglist = GETBUF(BUFSIZE); ref->str = siglist; - while ((c = getopt(argcnt, args, "lR:s:")) != EOF) { + while ((c = getopt(argcnt, args, "lR:s:g")) != EOF) { switch(c) { case 's': @@ -5959,7 +6095,10 @@ case 'l': signame_list(); return; - + case 'g': + pc->curcmd_flags |= TASK_SPECIFIED; + task_group=TRUE; + break; default: argerrs++; break; @@ -6006,11 +6145,65 @@ tasklist[tcnt++] = CURRENT_TASK(); for (c = 0; c < tcnt; c++) { + if(task_group) + show_tgid_sig_list(tasklist[c]); + else { do_sig(tasklist[c], 0, strlen(ref->str) ? ref : NULL); fprintf(fp, "\n"); } + } } +static void +show_tgid_sig_list(ulong task) +{ + int i; + int cnt; + struct task_context *tc; + ulong tgid; + + tc = task_to_context(task); + tgid = task_tgid(task); + + if (tc->pid != tgid) { + if (pc->curcmd_flags & TASK_SPECIFIED) { + if (!(tc = tgid_to_context(tgid))) + return; + task = tc->task; + } else + return; + } + + if ((tc->pid == 0) && (pc->curcmd_flags & IDLE_TASK_SHOWN)) + return; + + print_task_header(fp, tc, 0); + dump_signal_data(tc,TASK_GROUP_LEVEL); + fprintf(fp, "\n"); + INDENT(2); + print_task_header(fp, tc, 0); + dump_signal_data(tc,TASK_LEVEL|TASK_INDENT2); + + tc = FIRST_CONTEXT(); + for (i = cnt = 0; i < RUNNING_TASKS(); i++, tc++) { + if (tc->task == task) + continue; + + if (task_tgid(tc->task) == tgid) { + fprintf(fp, "\n"); + INDENT(2); + print_task_header(fp, tc, 0); + dump_signal_data(tc,TASK_LEVEL|TASK_INDENT2); + cnt++; + if (tc->pid == 0) + pc->curcmd_flags |= IDLE_TASK_SHOWN; + } + } + + if (!cnt) + fprintf(fp, " (no threads)\n"); + fprintf(fp, "\n"); +} /* * Do the work for the sig command, coming from sig or foreach. @@ -6027,7 +6220,7 @@ else { if (!(flags & FOREACH_TASK)) print_task_header(fp, tc, 0); - dump_signal_data(tc); + dump_signal_data(tc,TASK_LEVEL|TASK_GROUP_LEVEL); } } @@ -6047,7 +6240,7 @@ * Dump all signal-handling data for a task. */ static void -dump_signal_data(struct task_context *tc) +dump_signal_data(struct task_context *tc, int task_flags) { int i, sigrtmax, others, use_sighand; int translate, sigpending; @@ -6074,16 +6267,6 @@ sigset = task_signal(tc->task, 0); if (!tt->last_task_read) return; - blocked = task_blocked(tc->task); - - if (VALID_MEMBER(task_struct_sigpending)) - sigpending = INT(tt->task_struct + - OFFSET(task_struct_sigpending)); - else if (VALID_MEMBER(thread_info_flags)) { - fill_thread_info(tc->thread_info); - ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags)); - sigpending = ti_flags & (1<task_struct + OFFSET(task_struct_signal)); - fprintf(fp, "SIGNAL_STRUCT: %lx ", signal_struct); - size = MAX(SIZE(signal_struct), VALID_SIZE(signal_queue) ? SIZE(signal_queue) : SIZE(sigqueue)); if (VALID_SIZE(sighand_struct)) @@ -6104,9 +6285,19 @@ readmem(signal_struct, KVADDR, signal_buf, SIZE(signal_struct), "signal_struct buffer", FAULT_ON_ERROR); + + /* + * Signal dispositions (task group level). + */ + if(task_flags & TASK_GROUP_LEVEL) { + if (task_flags & TASK_INDENT2) + INDENT(2); + fprintf(fp, "SIGNAL_STRUCT: %lx ", signal_struct); fprintf(fp, "COUNT: %d\n", INT(signal_buf + OFFSET(signal_struct_count))); + if (task_flags & TASK_INDENT2) + INDENT(2); fprintf(fp, " SIG %s %s %s %s\n", mkstring(buf1, VADDR_PRLEN == 8 ? 9 : VADDR_PRLEN, CENTER, "SIGACTION"), @@ -6127,6 +6318,8 @@ sigrtmax = sigrt_minmax(NULL, NULL); for (i = 1; i <= sigrtmax; i++) { + if (task_flags & TASK_INDENT2) + INDENT(2); fprintf(fp, "%s[%d] ", i < 10 ? " " : "", i); if (use_sighand) { @@ -6213,11 +6406,43 @@ fprintf(fp, "\n"); } + } + + if(task_flags & TASK_LEVEL) { + /* + * Pending signals (task level). + */ + if (VALID_MEMBER(task_struct_sigpending)) + sigpending = INT(tt->task_struct + + OFFSET(task_struct_sigpending)); + else if (VALID_MEMBER(thread_info_flags)) { + fill_thread_info(tc->thread_info); + ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags)); + sigpending = ti_flags & (1<task); + if (task_flags & TASK_INDENT2) + INDENT(2); fprintf(fp, " BLOCKED: %016llx\n", blocked); + /* + * Pending queue (task level). + */ + + if (task_flags & TASK_INDENT2) + INDENT(2); if (VALID_MEMBER(signal_struct_shared_pending) ) fprintf(fp, "PRIVATE_PENDING\n"); + if (task_flags & TASK_INDENT2) + INDENT(2); fprintf(fp, " SIGNAL: %016llx\n", sigset); if (VALID_MEMBER(task_struct_sigqueue)) @@ -6232,13 +6457,20 @@ if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue)) sigqueue = 0; + if (task_flags & TASK_INDENT2) + INDENT(2); if (sigqueue) { fprintf(fp, " SIGQUEUE: SIG %s\n", mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO")); sigqueue_list(sigqueue); } else fprintf(fp, " SIGQUEUE: (empty)\n"); + } + /* + * Pending queue (task group level). + */ + if (task_flags & TASK_GROUP_LEVEL) { if (VALID_MEMBER(signal_struct_shared_pending) ) { ulong shared_pending, signal; fprintf(fp, "SHARED_PENDING\n"); @@ -6247,6 +6479,8 @@ readmem(signal, KVADDR, signal_buf,SIZE(sigpending_signal), "signal", FAULT_ON_ERROR); sigset = task_signal(0, (ulong*)signal_buf); + if (task_flags & TASK_INDENT2) + INDENT(2); fprintf(fp, " SIGNAL: %016llx\n", sigset); sigqueue = (shared_pending + OFFSET_OPTION(sigpending_head, sigpending_list) + @@ -6257,6 +6491,8 @@ if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue)) sigqueue = 0; + if (task_flags & TASK_INDENT2) + INDENT(2); if (sigqueue) { fprintf(fp, " SIGQUEUE: SIG %s\n", mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO")); @@ -6264,6 +6500,7 @@ } else fprintf(fp, " SIGQUEUE: (empty)\n"); } + } FREEBUF(signal_buf); } --- crash-4.0-3.6/help.c 2006-10-05 21:43:10.000000000 +0200 +++ crash-4.0-3.6-patch/help.c 2006-10-08 20:21:49.000000000 +0200 @@ -521,7 +521,7 @@ " files run the \"files\" command (optional flag: -R)", " net run the \"net\" command (optional flags: -s -S -R)", " set run the \"set\" command", -" sig run the \"sig\" command", +" sig run the \"sig\" command (optional flag: -g)", " vtop run the \"vtop\" command (optional flags: -c -u -k)\n", " flag Pass this optional flag to the command selected.", " argument Pass this argument to the command selected.", @@ -2845,7 +2845,7 @@ char *help_sig[] = { "sig", "task signal handling", -"[[-l] | [-s sigset]] | [pid | taskp] ...", +"[[-l] | [-s sigset]] | [-g] [pid | taskp] ...", " This command displays signal-handling data of one or more tasks. Multiple", " task or PID numbers may be entered; if no arguments are entered, the signal", " handling data of the current context will be displayed. The default display", @@ -2868,6 +2868,7 @@ " ", " pid a process PID.", " taskp a hexadecimal task_struct pointer.", +" -g displays signal informations for all tasks of task's task group", " -l displays the defined signal numbers and names.", " -s sigset translates a 64-bit hexadecimal value representing a sigset_t", " into a list of signal names associated with the bits set.", @@ -2915,6 +2916,50 @@ " 64 f51b9d18", " 64 f51b9500", " ", +" Dump the signal-handling data for all tasks of task's task group PID 2578:\n", +" %s> sig -g 2578", +" PID: 2387 TASK: f617d020 CPU: 0 COMMAND: \"slapd\"", +" SIGNAL_STRUCT: f7dede00 COUNT: 6", +" SIG SIGACTION HANDLER MASK FLAGS", +" [1] c1f60c04 a258a7 0000000000000000 10000000 (SA_RESTART)", +" [2] c1f60c18 a258a7 0000000000000000 10000000 (SA_RESTART)", +" [3] c1f60c2c SIG_DFL 0000000000000000 0", +" [4] c1f60c40 SIG_DFL 0000000000000000 0", +" [5] c1f60c54 a258a7 0000000000000000 10000000 (SA_RESTART)", +" [6] c1f60c68 SIG_DFL 0000000000000000 0", +" [7] c1f60c7c SIG_DFL 0000000000000000 0", +" [8] c1f60c90 SIG_DFL 0000000000000000 0", +" [9] c1f60ca4 SIG_DFL 0000000000000000 0", +" [10] c1f60cb8 a25911 0000000000000000 10000000 (SA_RESTART)", +" ...", +" [64] c1f610f0 SIG_DFL 0000000000000000 0", +" SHARED_PENDING", +" SIGNAL: 0000000000000000", +" SIGQUEUE: (empty)", +" ", +" PID: 2387 TASK: f617d020 CPU: 0 COMMAND: \"slapd\"", +" SIGPENDING: no", +" BLOCKED: 0000000000000000", +" PRIVATE_PENDING", +" SIGNAL: 0000000000000000", +" SIGQUEUE: (empty)", +" ", +" PID: 2392 TASK: f6175aa0 CPU: 0 COMMAND: \"slapd\"", +" SIGPENDING: no", +" BLOCKED: 0000000000000000", +" PRIVATE_PENDING", +" SIGNAL: 0000000000000000", +" SIGQUEUE: (empty)", +" ", +" PID: 2523 TASK: f7cd4aa0 CPU: 1 COMMAND: \"slapd\"", +" SIGPENDING: no", +" BLOCKED: 0000000000000000", +" PRIVATE_PENDING", +" SIGNAL: 0000000000000000", +" SIGQUEUE: (empty)", +" ", +" ...", +" ", " Translate the sigset_t mask value, cut-and-pasted from the signal handling", " data from signals 1 and 10 above:", " ",