1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/cmd/ksh93/sh/timers.c
Johnothan King c4f980eb29
Introduce usage of __builtin_unreachable() and noreturn (#248)
This commit adds an UNREACHABLE() macro that expands to either the
__builtin_unreachable() compiler builtin (for release builds) or
abort(3) (for development builds). This is used to mark code paths
that are never to be reached.

It also adds the 'noreturn' attribute to functions that never
return: path_exec(), sh_done() and sh_syntax(). The UNREACHABLE()
macro is not added after calling these.

The purpose of these is:
* to slightly improve GCC/Clang compiler optimizations;
* to fix a few compiler warnings;
* to add code clarity.

Changes of note:

src/cmd/ksh93/sh/io.c: outexcept():
- Avoid using __builtin_unreachable() here since errormsg can
  return despite using ERROR_system(1), as shp->jmplist->mode is
  temporarily set to 0. See: https://github.com/att/ast/issues/1336

src/cmd/ksh93/tests/io.sh:
- Add a regression test for the ksh2020 bug referenced above.

src/lib/libast/features/common:
- Detect the existence of either the C11 stdnoreturn.h header or
  the GCC noreturn attribute, preferring the former when available.
- Test for the existence of __builtin_unreachable(). Use it for
  release builds. On development builds, use abort() instead, which
  crahses reliably for debugging when unreachable code is reached.

Co-authored-by: Martijn Dekker <martijn@inlv.org>
2021-04-05 00:28:24 +01:00

247 lines
5.8 KiB
C

/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.eclipse.org/org/documents/epl-v10.html *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
#include <ast.h>
#include <sig.h>
#include <error.h>
#include "fault.h"
#include "defs.h"
#include "FEATURE/sigfeatures"
#include "FEATURE/time"
typedef struct _timer
{
double wakeup;
double incr;
struct _timer *next;
void (*action)(void*);
void *handle;
} Timer_t;
#define IN_ADDTIMEOUT 1
#define IN_SIGALRM 2
#define DEFER_SIGALRM 4
#define SIGALRM_CALL 8
static Timer_t *tptop, *tpmin, *tpfree;
static char time_state;
static double getnow(void)
{
register double now;
#ifdef timeofday
struct timeval tp;
timeofday(&tp);
now = tp.tv_sec + 1.e-6*tp.tv_usec;
#else
now = (double)time((time_t*)0);
#endif /* timeofday */
return(now+.001);
}
/*
* set an alarm for <t> seconds
*/
static double setalarm(register double t)
{
#if defined(_lib_setitimer) && defined(ITIMER_REAL)
struct itimerval tnew, told;
tnew.it_value.tv_sec = t;
tnew.it_value.tv_usec = 1.e6*(t- (double)tnew.it_value.tv_sec);
if(t && tnew.it_value.tv_sec==0 && tnew.it_value.tv_usec<1000)
tnew.it_value.tv_usec = 1000;
tnew.it_interval.tv_sec = 0;
tnew.it_interval.tv_usec = 0;
if(setitimer(ITIMER_REAL,&tnew,&told) < 0)
{
errormsg(SH_DICT,ERROR_system(1),e_alarm);
UNREACHABLE();
}
t = told.it_value.tv_sec + 1.e-6*told.it_value.tv_usec;
#else
unsigned seconds = (unsigned)t;
if(t && seconds<1)
seconds=1;
t = (double)alarm(seconds);
#endif
return(t);
}
/* signal handler for alarm call */
static void sigalrm(int sig)
{
register Timer_t *tp, *tplast, *tpold, *tpnext;
double now;
static double left;
NOT_USED(sig);
left = 0;
if(time_state&SIGALRM_CALL)
time_state &= ~SIGALRM_CALL;
else if(alarm(0))
kill(shgd->current_pid,SIGALRM|SH_TRAP);
if(time_state)
{
if(time_state&IN_ADDTIMEOUT)
time_state |= DEFER_SIGALRM;
errno = EINTR;
return;
}
time_state |= IN_SIGALRM;
sigrelease(SIGALRM);
while(1)
{
now = getnow();
tpold = tpmin = 0;
for(tplast=0,tp=tptop; tp; tp=tpnext)
{
tpnext = tp->next;
if(tp->action)
{
if(tp->wakeup <=now)
{
if(!tpold || tpold->wakeup>tp->wakeup)
tpold = tp;
}
else
{
if(!tpmin || tpmin->wakeup>tp->wakeup)
tpmin=tp;
}
tplast = tp;
}
else
{
if(tplast)
tplast->next = tp->next;
else
tptop = tp->next;
tp->next = tpfree;
tpfree = tp;
}
}
if((tp=tpold) && tp->incr)
{
while((tp->wakeup += tp->incr) <= now);
if(!tpmin || tpmin->wakeup>tp->wakeup)
tpmin=tp;
}
if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left))))
{
if(left==0)
signal(SIGALRM,sigalrm);
left = setalarm(tpmin->wakeup-now);
if(left && (now+left) < tpmin->wakeup)
setalarm(left);
else
left=tpmin->wakeup-now;
}
if(tp)
{
void (*action)(void*);
action = tp->action;
if(!tp->incr)
tp->action = 0;
errno = EINTR;
time_state &= ~IN_SIGALRM;
(*action)(tp->handle);
time_state |= IN_SIGALRM;
}
else
break;
}
if(!tpmin)
signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
time_state &= ~IN_SIGALRM;
errno = EINTR;
}
static void oldalrm(void *handle)
{
Handler_t fn = *(Handler_t*)handle;
free(handle);
(*fn)(SIGALRM);
}
void *sh_timeradd(unsigned long msec,int flags,void (*action)(void*),void *handle)
{
register Timer_t *tp;
double t;
Handler_t fn;
t = ((double)msec)/1000.;
if(t<=0 || !action)
return((void*)0);
if(tp=tpfree)
tpfree = tp->next;
else
tp = (Timer_t*)sh_malloc(sizeof(Timer_t));
tp->wakeup = getnow() + t;
tp->incr = (flags?t:0);
tp->action = action;
tp->handle = handle;
time_state |= IN_ADDTIMEOUT;
tp->next = tptop;
tptop = tp;
if(!tpmin || tp->wakeup < tpmin->wakeup)
{
tpmin = tp;
fn = (Handler_t)signal(SIGALRM,sigalrm);
if((t= setalarm(t))>0 && fn && fn!=(Handler_t)sigalrm)
{
Handler_t *hp = (Handler_t*)sh_malloc(sizeof(Handler_t));
*hp = fn;
sh_timeradd((long)(1000*t), 0, oldalrm, (void*)hp);
}
tp = tptop;
}
else if(tpmin && !tpmin->action)
time_state |= DEFER_SIGALRM;
time_state &= ~IN_ADDTIMEOUT;
if(time_state&DEFER_SIGALRM)
{
time_state=SIGALRM_CALL;
sigalrm(SIGALRM);
if(tp!=tptop)
tp=0;
}
return((void*)tp);
}
/*
* delete timer <tp>. If <tp> is NULL, all timers are deleted
*/
void timerdel(void *handle)
{
register Timer_t *tp = (Timer_t*)handle;
if(tp)
tp->action = 0;
else
{
for(tp=tptop; tp; tp=tp->next)
tp->action = 0;
if(tpmin)
{
tpmin = 0;
setalarm((double)0);
}
signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
}
}