Roland Mainz
2014-01-23 21:45:32 UTC
Hi!
----
While trying to figure out why Solaris still have problems with
(realtime) signal handling I found another issue related to |errno|:
It seems that if syscalls are waiting and are then interrupted by a
signal the value of |errno| returned by the syscall looks different
than the errno value returned by the kernel for that syscall...
... after some digging I figured out that some platforms do not save
|errno| before calling the signal handler function and then restore it
when that function returns.
Attached (as "astksh20131010_sighandler_saverestore_errno001.diff") is
a simple patch which fixes that issue (and therefore fixes some
sporadic failures in ksh93 related to signal handling) ...
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -r -u build_i386_64bit_debug/src/cmd/ksh93/sh/fault.c build_sigerrno/src/cmd/ksh93/sh/fault.c
--- src/cmd/ksh93/sh/fault.c 2013-08-14 23:31:23.000000000 +0200
+++ src/cmd/ksh93/sh/fault.c 2014-01-23 21:22:08.081397145 +0100
@@ -112,6 +112,7 @@
void sh_fault(register int sig)
#endif
{
+ int saved_errno = errno; /* many platforms do not save/restore errno for signal handlers */
register Shell_t *shp = sh_getinterp();
register int flag=0;
register char *trap;
@@ -135,21 +136,21 @@
/* critical region, save and process later */
if(!(shp->sigflag[sig]&SH_SIGIGNORE))
shp->savesig = sig;
- return;
+ goto done;
}
/* handle ignored signals */
if(trap && *trap==0)
- return;
+ goto done;
flag = shp->sigflag[sig]&~SH_SIGOFF;
if(!trap)
{
if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
- return;
+ goto done;
if(flag&SH_SIGIGNORE)
{
if(shp->subshell)
shp->ignsig = sig;
- return;
+ goto done;
}
if(flag&SH_SIGDONE)
{
@@ -161,7 +162,7 @@
/* check for TERM signal between fork/exec */
if(sig==SIGTERM && job.in_critical)
shp->trapnote |= SH_SIGTERM;
- return;
+ goto done;
}
shp->lastsig = sig;
sigrelease(sig);
@@ -194,7 +195,7 @@
dp->exceptf = malloc_done;
}
#endif
- return;
+ goto done;
}
}
errno = 0;
@@ -224,7 +225,7 @@
{
sigrelease(sig);
sh_exit(shp,SH_EXITSIG);
- return;
+ goto done;
}
}
#endif /* SIGTSTP */
@@ -232,7 +233,7 @@
if(shp->bltinfun)
action = notify_builtin(shp,sig);
if(action>0)
- return;
+ goto done;
shp->trapnote |= flag;
#ifdef AST_SERIAL_RESTART
if(flag&(SH_SIGSET|SH_SIGTRAP))
@@ -243,10 +244,12 @@
if(pp->mode==SH_JMPCMD && sh_isstate(shp,SH_STOPOK))
{
if(action<0)
- return;
+ goto done;
sigrelease(sig);
sh_exit(shp,SH_EXITSIG);
}
+done:
+ errno = saved_errno;
}
/*
diff -r -u build_i386_64bit_debug/src/cmd/ksh93/sh/jobs.c build_sigerrno/src/cmd/ksh93/sh/jobs.c
--- src/cmd/ksh93/sh/jobs.c 2013-10-04 17:25:25.000000000 +0200
+++ src/cmd/ksh93/sh/jobs.c 2014-01-23 22:05:24.830307582 +0100
@@ -367,6 +367,8 @@
static void job_waitsafe(int sig)
#endif
{
+ int saved_errno = errno; /* many platforms do not save/restore errno for signal handlers */
+
if(job.in_critical || vmbusy())
{
job.savesig = sig;
@@ -374,6 +376,8 @@
}
else
job_reap(sig);
+
+ errno = saved_errno;
}
/*
----
While trying to figure out why Solaris still have problems with
(realtime) signal handling I found another issue related to |errno|:
It seems that if syscalls are waiting and are then interrupted by a
signal the value of |errno| returned by the syscall looks different
than the errno value returned by the kernel for that syscall...
... after some digging I figured out that some platforms do not save
|errno| before calling the signal handler function and then restore it
when that function returns.
Attached (as "astksh20131010_sighandler_saverestore_errno001.diff") is
a simple patch which fixes that issue (and therefore fixes some
sporadic failures in ksh93 related to signal handling) ...
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -r -u build_i386_64bit_debug/src/cmd/ksh93/sh/fault.c build_sigerrno/src/cmd/ksh93/sh/fault.c
--- src/cmd/ksh93/sh/fault.c 2013-08-14 23:31:23.000000000 +0200
+++ src/cmd/ksh93/sh/fault.c 2014-01-23 21:22:08.081397145 +0100
@@ -112,6 +112,7 @@
void sh_fault(register int sig)
#endif
{
+ int saved_errno = errno; /* many platforms do not save/restore errno for signal handlers */
register Shell_t *shp = sh_getinterp();
register int flag=0;
register char *trap;
@@ -135,21 +136,21 @@
/* critical region, save and process later */
if(!(shp->sigflag[sig]&SH_SIGIGNORE))
shp->savesig = sig;
- return;
+ goto done;
}
/* handle ignored signals */
if(trap && *trap==0)
- return;
+ goto done;
flag = shp->sigflag[sig]&~SH_SIGOFF;
if(!trap)
{
if(sig==SIGINT && (shp->trapnote&SH_SIGIGNORE))
- return;
+ goto done;
if(flag&SH_SIGIGNORE)
{
if(shp->subshell)
shp->ignsig = sig;
- return;
+ goto done;
}
if(flag&SH_SIGDONE)
{
@@ -161,7 +162,7 @@
/* check for TERM signal between fork/exec */
if(sig==SIGTERM && job.in_critical)
shp->trapnote |= SH_SIGTERM;
- return;
+ goto done;
}
shp->lastsig = sig;
sigrelease(sig);
@@ -194,7 +195,7 @@
dp->exceptf = malloc_done;
}
#endif
- return;
+ goto done;
}
}
errno = 0;
@@ -224,7 +225,7 @@
{
sigrelease(sig);
sh_exit(shp,SH_EXITSIG);
- return;
+ goto done;
}
}
#endif /* SIGTSTP */
@@ -232,7 +233,7 @@
if(shp->bltinfun)
action = notify_builtin(shp,sig);
if(action>0)
- return;
+ goto done;
shp->trapnote |= flag;
#ifdef AST_SERIAL_RESTART
if(flag&(SH_SIGSET|SH_SIGTRAP))
@@ -243,10 +244,12 @@
if(pp->mode==SH_JMPCMD && sh_isstate(shp,SH_STOPOK))
{
if(action<0)
- return;
+ goto done;
sigrelease(sig);
sh_exit(shp,SH_EXITSIG);
}
+done:
+ errno = saved_errno;
}
/*
diff -r -u build_i386_64bit_debug/src/cmd/ksh93/sh/jobs.c build_sigerrno/src/cmd/ksh93/sh/jobs.c
--- src/cmd/ksh93/sh/jobs.c 2013-10-04 17:25:25.000000000 +0200
+++ src/cmd/ksh93/sh/jobs.c 2014-01-23 22:05:24.830307582 +0100
@@ -367,6 +367,8 @@
static void job_waitsafe(int sig)
#endif
{
+ int saved_errno = errno; /* many platforms do not save/restore errno for signal handlers */
+
if(job.in_critical || vmbusy())
{
job.savesig = sig;
@@ -374,6 +376,8 @@
}
else
job_reap(sig);
+
+ errno = saved_errno;
}
/*