On Wed, Mar 27, 2013 at 9:48 PM, Irek Szczesniak <[email protected]> wrote:
> On Wed, Mar 27, 2013 at 6:10 PM, Roland Mainz <[email protected]> 
> wrote:
>> On Wed, Mar 27, 2013 at 11:31 AM, Irek Szczesniak <[email protected]> 
>> wrote:
>> [snip]
>>>>> BTW: The patch currently doesn't cover passing SIGCHLD siginfo data to
>>>>> the shell traps (this needs to be done in |job_waitsafe()| ... but
>>>>> that may be tricky).
>>>>
>>>> Could you add.sh.status (Exit value or signal) and .sh.pid for CHLD
>>>> traps, please?
>>>
>>> Appending to this RFE:
>>> We like to have .sh.code for CHLD traps too, with .sh.code being a
>>> STRING returning one of the CLD_* codes defined in
>>> http://pubs.opengroup.org/onlinepubs/7908799/xsh/signal.h.html (i.e.
>>> this is defined by X/OPEN and POSIX and therefore should be applicable
>>> as shell extension).
>>
>> Erm... do you mean that you want to be able to write a ksh93 version
>> of the following C code ?
>> -- snip --
>> #include <stdlib.h>
>> #include <stdio.h>
>> #include <signal.h>
>> #include <sys/types.h>
>> #include <unistd.h>
>> #include <errno.h>
>>
>> static
>> const char *sicode2str(int si_code)
>> {
>>         const char *str;
>>         switch(si_code)
>>         {
>> #define STRSYM(sym) \
>>         case (sym): str = #sym ; break;
>>                 STRSYM(CLD_EXITED)
>>                 STRSYM(CLD_KILLED)
>>                 STRSYM(CLD_DUMPED)
>>                 STRSYM(CLD_TRAPPED)
>>                 STRSYM(CLD_STOPPED)
>>                 STRSYM(CLD_CONTINUED)
>>                 default:
>>                         str="<unknown>";
>>                         break;
>>         }
>>         return str;
>> }
>>
>>
>> static
>> void chld_handler (int signum, siginfo_t *si,
>>         void *context)
>> {
>>         printf("#SIGCHLD, si_code=%d/%s handler\n",
>>                 si->si_code,
>>                 sicode2str(si->si_code));
>> }
>>
>>
>> static
>> void chsleep(void)
>> {
>>         int i;
>>         for (i=0 ; i < 120 ; i++)
>>                 usleep(10000);
>> }
>>
>>
>> int main(int ac, char *av[])
>> {
>>         struct sigaction new_action;
>>         pid_t pid;
>>
>>         /* Setting-up the sigchld handler */
>>         new_action.sa_sigaction = chld_handler;
>>         sigemptyset (&new_action.sa_mask);
>>         new_action.sa_flags = SA_SIGINFO;
>>         sigaction (SIGCHLD, &new_action, NULL);
>>
>>         pid = fork(); /*FIXME: Need error handling*/
>>
>>         if (pid == 0)
>>         {
>>                 /* Child process */
>>
>>                 puts("# child process "
>>                         "(stopping now...)");
>>                 raise(SIGSTOP);
>>
>>                 puts("# child continues...");
>>
>>                 _exit(0);
>>         }
>>         else
>>         {
>>                 /* Parent process */
>>
>>                 chsleep();
>>                 puts("# parent waking child...");
>>                 kill(pid, SIGCONT);
>>                 chsleep();
>>         }
>>
>>         return EXIT_SUCCESS;
>> }
>> -- snip --
>>
>> The output should look like this:
>> -- snip --
>> # child process (stopping now...)
>> #SIGCHLD, si_code=5/CLD_STOPPED handler
>> # parent waking child...
>> # child continues...
>> #SIGCHLD, si_code=6/CLD_CONTINUED handler
>> #SIGCHLD, si_code=1/CLD_EXITED handler
>> -- snip --
>>
>> This should be technically possible to implement in ksh93... but for
>> which purpose are you interested in the |CLD_STOPPED|&co. codes ?
>
> Until now there is no scalable way to monitor only a single process in
> a pool of many (20000+) worker processes. The usual way of listening
> to the CHLD trap and then take a sample of the job list using jobs -l
> works but scales very poorly. Using the information solely from the
> siginfo data passed to the CHLD handler would avoid that scalability
> bottleneck.
> Looking at si_code reveals whether the child process completed
> successfully, crashed or somehow else changed state and is thus IMO
> mandatory to replace jobs -l as information source.

Ok... thanks for the explanation.

Attached (as "astksh20130318_shsig_chld001.diff.txt") is a dumb 10min
hack which fills the .sh.sig data for CHLD traps.

* Changes:
- .sh.sig data are now filled for CHLD traps
- ".sh.sig.name" was renamed to ".sh.sig.signame" to avoid naming
collisions on platforms which pass names around as part of |siginfo_t|
- ".sh.sig.code" is now a _string_ since |siginfo_t|'s |si_code|
numbers are not portable... nor are they self-explaining (the strings
returned should be...)
- .sh.sig.status now works and returns even exit codes like 97 or 121 ...


* Open issues:
 - ".sh.sig.code" code should be more robust (SIGRT* signals come in mind)
 - .sh.sig.* should only have variables available which match the
siginfo_t data returned
- Only |CLD_EXITED| is currently supported since the code is mostly a
10min hack... the real code should save the |siginfo_t| data in a list
and replay it when the CHLD shell traps are called.


* Example usage looks like this:
-- snip --
$ cat test1.sh

function chld_trap
{
        printf "child done, code=%q, exit code=%d\n" \
                "${.sh.sig.code}" \
                ${.sh.sig.status}
}

trap 'chld_trap' CHLD

exit 120 &

wait

print '#done.'
$ ksh ./test1.sh
child done, code=CLD_EXITED, exit code=120
#done.
-- snip --

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) [email protected]
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)
diff -r -u build_i386_64bit_debug_unpatched/src/cmd/ksh93/data/variables.c 
build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/data/variables.c
--- build_i386_64bit_debug_unpatched/src/cmd/ksh93/data/variables.c     
2012-10-01 18:58:22.000000000 +0200
+++ build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/data/variables.c 
2013-03-29 15:15:02.717053517 +0100
@@ -118,11 +118,11 @@
 const Shtable_t        shtab_siginfo[] =
 {
        "signo",        NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
-       "name",         NV_RDONLY|NV_MINIMAL|NV_NOFREE,
+       "signame",      NV_RDONLY|NV_MINIMAL|NV_NOFREE,
        "pid",          NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
        "uid",          NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
        "value",        NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER|NV_LONG,
-       "code",         NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
+       "code",         NV_RDONLY|NV_MINIMAL|NV_NOFREE,
        "status",       NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
        "errno",        NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER,
        "addr",         NV_RDONLY|NV_MINIMAL|NV_NOFREE|NV_INTEGER|NV_LONG,
diff -r -u build_i386_64bit_debug_unpatched/src/cmd/ksh93/sh/init.c 
build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/sh/init.c
--- build_i386_64bit_debug_unpatched/src/cmd/ksh93/sh/init.c    2013-03-11 
21:45:45.000000000 +0100
+++ build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/sh/init.c        
2013-03-29 15:31:44.253142901 +0100
@@ -2040,6 +2040,117 @@
        svar_init(shp,SH_SIG,shtab_siginfo);
     }
 
+const char *siginfocode2name(Shell_t *shp, int signo, int sicode)
+{
+       const char *str = NULL;
+#define SYM2STR(sym) case sym: str = #sym ; break ; 
+       switch(signo)
+       {
+               case SIGILL:
+                       switch(sicode)
+                       {
+                       SYM2STR(ILL_ILLOPC)
+                       SYM2STR(ILL_ILLOPN)
+                       SYM2STR(ILL_ILLADR)
+                       SYM2STR(ILL_ILLTRP)
+                       SYM2STR(ILL_PRVOPC)
+                       SYM2STR(ILL_PRVREG)
+                       SYM2STR(ILL_COPROC)
+                       SYM2STR(ILL_BADSTK)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGILL-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGFPE:
+                       switch(sicode)
+                       {
+                       SYM2STR(FPE_INTDIV)
+                       SYM2STR(FPE_INTOVF)
+                       SYM2STR(FPE_FLTDIV)
+                       SYM2STR(FPE_FLTOVF)
+                       SYM2STR(FPE_FLTUND)
+                       SYM2STR(FPE_FLTRES)
+                       SYM2STR(FPE_FLTINV)
+                       SYM2STR(FPE_FLTSUB)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGFPE-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGSEGV:
+                       switch(sicode)
+                       {
+                       SYM2STR(SEGV_MAPERR)
+                       SYM2STR(SEGV_ACCERR)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGSEGV-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGBUS:
+                       switch(sicode)
+                       {
+                       SYM2STR(BUS_ADRALN)
+                       SYM2STR(BUS_ADRERR)
+                       SYM2STR(BUS_OBJERR)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGBUS-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGTRAP:
+                       switch(sicode)
+                       {
+                       SYM2STR(TRAP_BRKPT)
+                       SYM2STR(TRAP_TRACE)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGTRAP-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGCHLD:
+                       switch(sicode)
+                       {
+                       SYM2STR(CLD_EXITED)
+                       SYM2STR(CLD_KILLED)
+                       SYM2STR(CLD_DUMPED)
+                       SYM2STR(CLD_TRAPPED)
+                       SYM2STR(CLD_STOPPED)
+                       SYM2STR(CLD_CONTINUED)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGCHLD-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               case SIGPOLL:
+                       switch(sicode)
+                       {
+                       SYM2STR(POLL_IN)
+                       SYM2STR(POLL_OUT)
+                       SYM2STR(POLL_MSG)
+                       SYM2STR(POLL_ERR)
+                       SYM2STR(POLL_PRI)
+                       SYM2STR(POLL_HUP)
+                       default:
+                               sfprintf(shp->strbuf, "<SIGPOLL-code%x>", 
sicode);
+                               break;
+                       }
+                       break;
+               default:
+                       sfprintf(shp->strbuf, "<SIG%x-code%x>", signo, sicode);
+                       break;
+       }
+
+       if (str)
+       {
+               /* FIXME: What's the |stkcopy()| equivalent for str buffers 
again ? */
+               sfprintf(shp->strbuf, "%s", str);
+       }
+
+       return sfstruse(shp->strbuf);
+}
+
     void sh_setsiginfo(siginfo_t *sip)
     {
        Namval_t        *np;
@@ -2052,22 +2163,20 @@
        sp = (struct Svars*)fp;
        np = create_svar(SH_SIG,"signo",0, fp);
        np->nvalue.ip = &sip->si_signo;
-       np = create_svar(SH_SIG,"name",0, fp);
+       np = create_svar(SH_SIG,"signame",0, fp);
        sh_siglist(sp->sh,sp->sh->strbuf,sip->si_signo+1);
        nv_putval(np,sfstruse(sp->sh->strbuf),NV_RDONLY);
        np = create_svar(SH_SIG,"pid",0, fp);
        np->nvalue.idp = &sip->si_pid;
        np = create_svar(SH_SIG,"uid",0, fp);
        np->nvalue.idp = &sip->si_uid;
+
        np = create_svar(SH_SIG,"code",0, fp);
-       np->nvalue.ip = &sip->si_code;
+       nv_putval(np, siginfocode2name(sp->sh, sip->si_signo, 
sip->si_code),NV_RDONLY);
+
        np = create_svar(SH_SIG,"status",0, fp);
-#ifdef CLD_EXITED
-       if(sip->si_code==CLD_EXITED)
-               sip->si_status &= 0xf;
-#endif
        np->nvalue.ip = &sip->si_status;
-       np->nvalue.ip = &sip->si_code;
+
        np = create_svar(SH_SIG,"addr",0, fp);
        np->nvsize = 16;
        np->nvalue.llp = (Sflong_t*)&sip->si_addr;
diff -r -u build_i386_64bit_debug_unpatched/src/cmd/ksh93/sh/jobs.c 
build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/sh/jobs.c
--- build_i386_64bit_debug_unpatched/src/cmd/ksh93/sh/jobs.c    2013-02-22 
17:10:52.000000000 +0100
+++ build_i386_64bit_debug_sigchld_shsig/src/cmd/ksh93/sh/jobs.c        
2013-03-28 00:48:58.355797312 +0100
@@ -196,6 +196,7 @@
        register struct process *pw,*pwnext;
        pid_t bckpid;
        int oldexit,trapnote;
+       siginfo_t si;
        job_lock();
        shp->sigflag[SIGCHLD] &= ~SH_SIGTRAP;
        trapnote = shp->trapnote;
@@ -212,6 +213,21 @@
                shp->savexit = pw->p_exit;
                if(pw->p_flag&P_SIGNALLED)
                        shp->savexit |= SH_EXITSIG;
+
+#ifdef _lib_sigaction
+               /*
+                * We craft our own siginfo_t data here. This
+                * should be replaced later with code which
+                * just saves the siginfo_t data in the signal
+                * handler and replays it for the matching trap
+                */
+               memset(&si, 0, sizeof(si));
+               si.si_signo=SIGCHLD;
+               si.si_pid=pw->p_pid;
+               si.si_code=CLD_EXITED;
+               si.si_status=pw->p_exit;
+               sh_setsiginfo(&si);
+#endif
                sh_trap(shp,trap,0);
                if(pw->p_pid==bckpid && unpost)
                        job_unpost(shp,pw,0);
_______________________________________________
ast-developers mailing list
[email protected]
http://lists.research.att.com/mailman/listinfo/ast-developers

Reply via email to