Subject: [clisp-list] sigaction for linux.lisp

From: Peter Wood <[email-masked]>
Date: Fri Mar 8 06:34:04 2002

Hi,

I would like to submit for inclusion in linux.lisp the following ffi
definitions for signal handling with sigaction. This augments
"LINUX" with access to the following functions:

sigemptyset, sigfillset, sigdelset, sigismember, sigprocmask,
sigpending, sigsuspend, sigaction, kill, killpg, raise, sigpause

Attached is sigaction.lisp (which can just be pasted into linux.lisp at
the end before the clean up comment) and siga-wrap.lisp which should
be loaded from a lisp run with ./full/lisp.run -M full/lispinit.mem in
the directory you have built in.

A problem which I encountered was that the signal handler function in
a sigaction struct can be (in C) either a pointer to a function, or an
int!  However the only ints which get used are SIG_IGN for ignoring
the signal, or SIG_DFL for restoring the default.  So I have not
attempted to solve this problem because it is easy to provide the same
functionality as SIG_DFL and SIG_IGN by other means.  If anyone has a
reasonably simple way to enable the use of SIG_DFL and SIG_IGN as ints
in the struct, I would be very interested to hear.  If it was a
c function, I would split it into 2 cases, for handling the different
types, but what does one do when it's a struct!?

A peculiarity which may be a bug in the ffi was this: The sa_flags
member in a sigaction structure is declared (in C) as an int.  However
Clisp reported that it could not coerce SA_RESETHAND (reset to default
handler) to an ffi:int. It had no problem handling the flags for (eg)
linux:SIGINT, which was also type BIGNUM.  According to the
documentation, lisp name 'int' and C 'int' are equivalent.
SA_RESETHAND is defined as #x80000000.  Changing ffi:int to ffi:uint32
in the ffi definition for the sigact struct solved the problem.  Why
does it work in C if SA_RESETHAND is too large.  There may be a
problem here, or am I missing something.

Obviously, the sigaction stuff has not been _rigorously_ tested.
However it has worked nicely for me, up to now. You should probably be
careful in case there is some unknown problem.  Here is an example
session using the definitions, and siga-wrap.lisp (also included)
which is just a bunch of convenience functions.

-----------------------example -----------------------------------

[2]> (load #"bindings/linuxlibc6/siga-wrap.lisp")
;; Loading file bindings/linuxlibc6/siga-wrap.lisp ...
;; Loading of file bindings/linuxlibc6/siga-wrap.lisp is finished.
T
[3]> (setf oldsigact (signal-action-retrieve linux:SIGINT))
#S(LINUX:sigaction :|sa_handler| #<FOREIGN-FUNCTION #x080525D0> :|sa_mask| #S(LINUX:sigset_t :|val| #(2))
   :|sa_flags| 335544320 :|sa_restorer| #<FOREIGN-FUNCTION #x400ACB18>)
[4]> (setf savehandler (sa-handler oldsigact))
#<FOREIGN-FUNCTION #x080525D0>
[5]> (defun wow (s) (format t "Wow! You zapped me with signal ~R~%" s))
WOW
[6]> (setf (sa-handler oldsigact) #'wow)
#<CLOSURE WOW (S) (DECLARE (SYSTEM::IN-DEFUN WOW)) (BLOCK WOW (FORMAT T "Wow! You zapped me with signal ~R~%" S))>
[7]> (signal-action-install linux:SIGINT oldsigact)
T

;;now Ctrl-C calls #'wow !!

[8]> Wow! You zapped me with signal two
Wow! You zapped me with signal two
Wow! You zapped me with signal two
Wow! You zapped me with signal two
:a
:A
[9]> (setf (sa-handler oldsigact) savehandler)
#<FOREIGN-FUNCTION #x080525D0>
[10]> (signal-action-install linux:SIGINT oldsigact)
T

;;Ctrl-C calls the original handler !!

[11]> 
*** - Ctrl-C: User break
1. Break [12]> :a

[13]> (dribble)

:-)) cute, huh?
------------------------------------------------------------------------

#'mysignal in siga-wrap.lisp is an example of how easy it is to write
signal() using sigaction.

----------------------------example usage ---------------------------

[2]> (load #"bindings/linuxlibc6/siga-wrap.lisp")
;; Loading file bindings/linuxlibc6/siga-wrap.lisp ...
;; Loading of file bindings/linuxlibc6/siga-wrap.lisp is finished.
T
[3]> (setf oldh (mysignal linux:SIGINT #'test1))
#<FOREIGN-FUNCTION #x08052620>
[4]> (linux:raise linux:SIGINT)
got signal two
0
[5]> (linux:raise linux:SIGINT)
got signal two
0
[6]> (mysignal linux:SIGINT oldh)
#<FOREIGN-FUNCTION #x08268520>
[7]> (linux:raise linux:SIGINT)

** - Continuable Error
PRINT: User break
If you continue (by typing 'continue'): Continue execution
1. Break [8]> :a

[9]> (dribble)

----------------------------voila :-) ----------------------------

According to my manual, sa_restorer is obsolete and should not be
used. 

Please note that if you use SA_RESETHAND, you reset the handler to the
system's notion of default handler, not Clisp's, so if you then hit
Ctrl-c, you would exit Clisp!

Finally, here's an example of using sigprocmask and sigpending.

---------------------------example--------------------------------

[15]> (setf sigact (signal-action-retrieve linux:SIGINT))
#S(LINUX:sigaction :|sa_handler| #<FOREIGN-FUNCTION #x08052620>
   :|sa_mask| #S(LINUX:sigset_t :|val| #(2)) :|sa_flags| 335544320
   :|sa_restorer| #<FOREIGN-FUNCTION #x400ACB18>)
[16]> (linux:raise linux:SIGINT)

** - Continuable Error
PRINT: User break
If you continue (by typing 'continue'): Continue execution
1. Break [17]> :a

[18]> (set-sigprocmask linux:SIG_BLOCK (sa-mask sigact))
T
[19]> (linux:raise linux:SIGINT)
0
[20]> (sigpending? )
#S(LINUX:sigset_t :|val| #(2))
[21]> (set-sigprocmask linux:SIG_UNBLOCK (sa-mask sigact))

** - Continuable Error
EVAL: User break
If you continue (by typing 'continue'): Continue execution
1. Break [22]> :a

[23]> (sigpending? )
#S(LINUX:sigset_t :|val| #())
[24]> (linux:raise linux:SIGINT)

** - Continuable Error
PRINT: User break
If you continue (by typing 'continue'): Continue execution
1. Break [25]> 0
[26]> (dribble)
-----------------------------------------------------------

Sorry about the long post.

Have fun,

Regards
Peter

---

From: Sam Steingold <[email-masked]>
Date: Fri Mar 8 21:29:03 2002

committed.
I changed the wrappers to barf on errors instead of returning nil, as
is the Lisp way (as opposed to the UNIX way).

Thanks!

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
Keep Jerusalem united! <http://www.onejerusalem.org/Petition.asp>
Read, think and remember! <http://www.iris.org.il> <http://www.memri.org/>
Live Lisp and prosper.