Support Racket on Chez Scheme
Remove the dependency on Racket BC's C API. We now build a plain C shared library and interact with it through the FFI. Closes https://github.com/tonyg/racket-unix-signals/issues/1
This commit is contained in:
parent
7231d17617
commit
a0c50918da
|
@ -0,0 +1,50 @@
|
||||||
|
language: c
|
||||||
|
|
||||||
|
# Based on: https://github.com/greghendershott/travis-racket
|
||||||
|
|
||||||
|
dist: bionic
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# Supply a global RACKET_DIR environment variable. This is where
|
||||||
|
# Racket will be installed. A good idea is to use ~/racket because
|
||||||
|
# that doesn't require sudo to install and is therefore compatible
|
||||||
|
# with Travis CI's newer container infrastructure.
|
||||||
|
- RACKET_DIR=~/racket
|
||||||
|
matrix:
|
||||||
|
# Supply at least one RACKET_VERSION environment variable. This is
|
||||||
|
# used by the install-racket.sh script (run at before_install,
|
||||||
|
# below) to select the version of Racket to download and install.
|
||||||
|
#
|
||||||
|
# Supply more than one RACKET_VERSION (as in the example below) to
|
||||||
|
# create a Travis-CI build matrix to test against multiple Racket
|
||||||
|
# versions.
|
||||||
|
- RACKET_VERSION=7.6
|
||||||
|
- RACKET_VERSION=HEAD
|
||||||
|
- RACKET_VERSION=HEADCS
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
# - env: RACKET_VERSION=HEAD
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- git clone https://github.com/greghendershott/travis-racket.git ~/travis-racket
|
||||||
|
- cat ~/travis-racket/install-racket.sh | bash # pipe to bash not sh!
|
||||||
|
- export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us
|
||||||
|
|
||||||
|
install:
|
||||||
|
- raco pkg install -j 4 --auto --name unix-signals
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
|
||||||
|
# Here supply steps such as raco make, raco test, etc. You can run
|
||||||
|
# `raco pkg install --deps search-auto` to install any required
|
||||||
|
# packages without it getting stuck on a confirmation prompt.
|
||||||
|
script:
|
||||||
|
- raco test -x -p unix-signals
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- raco setup --check-pkg-deps --pkgs unix-signals
|
||||||
|
- raco pkg install --deps search-auto cover cover-coveralls
|
||||||
|
- raco cover -b -f coveralls -d $TRAVIS_BUILD_DIR/coverage .
|
14
info.rkt
14
info.rkt
|
@ -1,5 +1,11 @@
|
||||||
#lang setup/infotab
|
#lang info
|
||||||
|
(define pkg-name 'unix-signals)
|
||||||
(define collection 'multi)
|
(define collection 'multi)
|
||||||
(define deps '("base" "rackunit-lib" "make"))
|
(define deps
|
||||||
(define build-deps '("racket-doc" "scribble-lib"))
|
'(["base" #:version "6.12"]
|
||||||
(define homepage "https://github.com/tonyg/racket-unix-signals")
|
"dynext-lib"))
|
||||||
|
(define build-deps
|
||||||
|
'("racket-doc"
|
||||||
|
"scribble-lib"))
|
||||||
|
(define homepage
|
||||||
|
"https://github.com/tonyg/racket-unix-signals")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#lang setup/infotab
|
#lang info
|
||||||
(define scribblings '(("unix-signals.scrbl" ())))
|
(define scribblings '(("unix-signals.scrbl" ())))
|
||||||
(define pre-install-collection "private/install.rkt")
|
(define pre-install-collection "private/install.rkt")
|
||||||
(define compile-omit-files '("private/install.rkt"))
|
(define compile-omit-files '("private/install.rkt"))
|
||||||
|
|
|
@ -1,48 +1,137 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(provide next-signal-evt
|
(require ffi/unsafe
|
||||||
read-signal
|
ffi/unsafe/port
|
||||||
lookup-signal-number
|
ffi/unsafe/define
|
||||||
|
racket/port
|
||||||
|
(rename-in racket/contract
|
||||||
|
[-> ->/c])
|
||||||
|
(only-in racket/os getpid))
|
||||||
|
|
||||||
|
(provide lookup-signal-number
|
||||||
lookup-signal-name
|
lookup-signal-name
|
||||||
capture-signal!
|
|
||||||
ignore-signal!
|
|
||||||
release-signal!
|
|
||||||
getpid
|
getpid
|
||||||
send-signal!)
|
(contract-out
|
||||||
|
;; These may not do what you want,
|
||||||
|
;; but they shouldn't break invariants
|
||||||
|
;; of the runtime system:
|
||||||
|
[next-signal-evt
|
||||||
|
(evt/c byte?)]
|
||||||
|
[read-signal
|
||||||
|
(->/c byte?)])
|
||||||
|
;; These are unsafe:
|
||||||
|
(protect-out
|
||||||
|
(contract-out
|
||||||
|
[capture-signal!
|
||||||
|
(->/c (or/c symbol? fixnum?) boolean?)]
|
||||||
|
[ignore-signal!
|
||||||
|
(->/c (or/c symbol? fixnum?) boolean?)]
|
||||||
|
[release-signal!
|
||||||
|
(->/c (or/c symbol? fixnum?) boolean?)]
|
||||||
|
[send-signal!
|
||||||
|
(->/c fixnum? (or/c symbol? fixnum?) boolean?)])))
|
||||||
|
|
||||||
(require (only-in racket/os getpid))
|
(define (local-lib-dirs)
|
||||||
(require "private/unix-signals-extension.rkt")
|
;; FIXME: There's probably a better way to do this with
|
||||||
|
;; define-runtime-path and cross-system-library-subpath,
|
||||||
|
;; but this is what the bcrypt package is doing.
|
||||||
|
(list (build-path (collection-path "unix-signals")
|
||||||
|
"private"
|
||||||
|
"compiled"
|
||||||
|
"native"
|
||||||
|
(system-library-subpath #f))))
|
||||||
|
|
||||||
(define signal-fd (get-signal-fd))
|
(define libracket-unix-signals
|
||||||
|
(ffi-lib "libracket_unix_signals" #:get-lib-dirs local-lib-dirs))
|
||||||
|
|
||||||
(define next-signal-evt
|
(define-ffi-definer define-unix libracket-unix-signals
|
||||||
(handle-evt signal-fd (lambda (_) (read-signal))))
|
#:default-make-fail make-not-available)
|
||||||
|
|
||||||
(define (read-signal) (read-byte signal-fd))
|
;; TODO: should we be using #:lock-name, #:in-original-place?,
|
||||||
|
;; or other options for some of these _fun types?
|
||||||
|
|
||||||
(define signals-by-name (get-signal-names))
|
(define-values [signals-by-name signals-by-number]
|
||||||
(define signals-by-number
|
(let ([signals-by-name #hasheq()]
|
||||||
(for/hash [((name number) (in-hash signals-by-name))] (values number name)))
|
[signals-by-number #hasheq()])
|
||||||
|
;; "two fixnums that are `=` are also the same according to `eq?`"
|
||||||
|
(define-unix racket_unix_signals_init
|
||||||
|
(_fun -> _stdbool))
|
||||||
|
(unless (racket_unix_signals_init)
|
||||||
|
(error 'unix-signals "error initializing foreign library"))
|
||||||
|
(define-unix prim_signal_names_for_each
|
||||||
|
(_fun (_fun _symbol _fixint -> _void)
|
||||||
|
-> _void))
|
||||||
|
(prim_signal_names_for_each
|
||||||
|
(λ (name num)
|
||||||
|
(set! signals-by-name (hash-set signals-by-name name num))
|
||||||
|
(set! signals-by-number (hash-set signals-by-number num name))))
|
||||||
|
(values signals-by-name signals-by-number)))
|
||||||
|
|
||||||
(define (lookup-signal-number sym) (hash-ref signals-by-name sym #f))
|
(define (lookup-signal-number sym)
|
||||||
(define (lookup-signal-name num) (hash-ref signals-by-number num #f))
|
(hash-ref signals-by-name sym #f))
|
||||||
|
(define (lookup-signal-name num)
|
||||||
|
(hash-ref signals-by-number num #f))
|
||||||
|
|
||||||
(define (name->signum who n)
|
|
||||||
(cond
|
(define-values [read-signal next-signal-evt]
|
||||||
[(symbol? n) (or (lookup-signal-number n)
|
(let ()
|
||||||
(error who "Unknown signal name ~a" n))]
|
(define-unix prim_get_signal_fd
|
||||||
[(fixnum? n) n]
|
(_fun -> _int))
|
||||||
[else (error who "Expects signal name symbol or signal number; got ~v" n)]))
|
(define signal-fd-in
|
||||||
|
;; NB: closing this port closes the file descriptor
|
||||||
|
;; (that was already true with scheme_make_fd_input_port)
|
||||||
|
(unsafe-file-descriptor->port (prim_get_signal_fd)
|
||||||
|
'signal-fd
|
||||||
|
'(read)))
|
||||||
|
(define (assert-not-eof who v)
|
||||||
|
(if (eof-object? v)
|
||||||
|
(raise (exn:fail:read:eof
|
||||||
|
(format "~a: internal error;\n unexpected eof" who)
|
||||||
|
(current-continuation-marks)
|
||||||
|
null))
|
||||||
|
v))
|
||||||
|
(define (read-signal)
|
||||||
|
(assert-not-eof 'read-signal (read-byte signal-fd-in)))
|
||||||
|
(values read-signal
|
||||||
|
(wrap-evt (read-bytes-evt 1 signal-fd-in)
|
||||||
|
(λ (bs)
|
||||||
|
(assert-not-eof 'next-signal-evt bs)
|
||||||
|
(bytes-ref bs 0))))))
|
||||||
|
|
||||||
|
(define name->signum
|
||||||
|
(case-lambda
|
||||||
|
[(who sig)
|
||||||
|
(name->signum who #f sig)]
|
||||||
|
[(who ?pid sig)
|
||||||
|
(cond
|
||||||
|
[(fixnum? sig)
|
||||||
|
sig]
|
||||||
|
[(lookup-signal-number sig)]
|
||||||
|
[else
|
||||||
|
(error who
|
||||||
|
"unknown signal name\n given: ~e~a\n known names...:~a"
|
||||||
|
sig
|
||||||
|
(if ?pid (format "\n pid: ~e" ?pid) "")
|
||||||
|
(apply string-append
|
||||||
|
(hash-map signals-by-name
|
||||||
|
(λ (name _num)
|
||||||
|
(format "\n ~e" name))
|
||||||
|
'ordered)))])]))
|
||||||
|
|
||||||
|
(define-unix prim_capture_signal
|
||||||
|
(_fun _fixint _fixint -> _stdbool))
|
||||||
|
|
||||||
(define (capture-signal! sig)
|
(define (capture-signal! sig)
|
||||||
(set-signal-handler! (name->signum 'capture-signal! sig) 0))
|
(prim_capture_signal (name->signum 'capture-signal! sig) 0))
|
||||||
|
|
||||||
(define (ignore-signal! sig)
|
(define (ignore-signal! sig)
|
||||||
(set-signal-handler! (name->signum 'capture-signal! sig) 1))
|
(prim_capture_signal (name->signum 'ignore-signal! sig) 1))
|
||||||
|
|
||||||
(define (release-signal! sig)
|
(define (release-signal! sig)
|
||||||
(set-signal-handler! (name->signum 'capture-signal! sig) 2))
|
(prim_capture_signal (name->signum 'release-signal! sig) 2))
|
||||||
|
|
||||||
|
(define-unix prim_send_signal
|
||||||
|
(_fun _fixint _fixint -> _stdbool))
|
||||||
|
|
||||||
(define (send-signal! pid sig)
|
(define (send-signal! pid sig)
|
||||||
(when (not (fixnum? pid)) (error 'send-signal! "Expected fixnum pid; got ~v" pid))
|
(prim_send_signal pid (name->signum 'send-signal! pid sig)))
|
||||||
(lowlevel-send-signal! pid (name->signum 'send-signal! sig)))
|
|
||||||
|
|
|
@ -1,19 +1,32 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require make/setup-extension)
|
(require dynext/file
|
||||||
|
dynext/link
|
||||||
|
racket/file)
|
||||||
|
|
||||||
(provide pre-installer)
|
(provide pre-installer)
|
||||||
|
|
||||||
(define (pre-installer collections-top-path our-path)
|
;; Used by "../info.rkt" (so this-collection-path is "..").
|
||||||
(pre-install our-path
|
|
||||||
(build-path our-path "private")
|
;; Heavily based on Sam Tobin-Hochstadt's bcrypt/private/install.rkt
|
||||||
"unix-signals-extension.c"
|
;; https://github.com/samth/bcrypt.rkt
|
||||||
"."
|
|
||||||
'()
|
(define (pre-installer collections-top-path this-collection-path)
|
||||||
'()
|
(define unix-signals/private/
|
||||||
'()
|
(build-path this-collection-path "private"))
|
||||||
'()
|
(parameterize ([current-directory unix-signals/private/]
|
||||||
'()
|
[current-use-mzdyn #f])
|
||||||
'()
|
(define racket_unix_signals.c
|
||||||
(lambda (thunk) (thunk))
|
(build-path unix-signals/private/ "racket_unix_signals.c"))
|
||||||
#t))
|
(define libracket_unix_signals.so
|
||||||
|
(build-path unix-signals/private/
|
||||||
|
"compiled"
|
||||||
|
"native"
|
||||||
|
(system-library-subpath #f)
|
||||||
|
(append-extension-suffix "libracket_unix_signals")))
|
||||||
|
(when (file-exists? libracket_unix_signals.so)
|
||||||
|
(delete-file libracket_unix_signals.so))
|
||||||
|
(make-parent-directory* libracket_unix_signals.so)
|
||||||
|
(link-extension #f ;; not quiet
|
||||||
|
(list racket_unix_signals.c)
|
||||||
|
libracket_unix_signals.so)))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -9,11 +10,12 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "escheme.h"
|
|
||||||
|
|
||||||
/* This implementation uses djb's "self-pipe trick".
|
/* This implementation uses djb's "self-pipe trick".
|
||||||
* See http://cr.yp.to/docs/selfpipe.html. */
|
* See http://cr.yp.to/docs/selfpipe.html. */
|
||||||
|
|
||||||
|
/* TODO: Communicate errno to Racket rather than using `perror`.
|
||||||
|
* See Racket's `saved-errno` and `lookup-errno`. */
|
||||||
|
|
||||||
static int self_pipe_initialized = 0;
|
static int self_pipe_initialized = 0;
|
||||||
static int self_pipe_read_end = -1;
|
static int self_pipe_read_end = -1;
|
||||||
static int self_pipe_write_end = -1;
|
static int self_pipe_write_end = -1;
|
||||||
|
@ -71,20 +73,13 @@ static void signal_handler_fn(int signum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *prim_get_signal_fd(int argc, Scheme_Object **argv) {
|
int prim_get_signal_fd(void) {
|
||||||
if (self_pipe_read_end == -1) {
|
return self_pipe_read_end;
|
||||||
return scheme_false;
|
|
||||||
} else {
|
|
||||||
return scheme_make_fd_input_port(self_pipe_read_end, scheme_intern_symbol("signal-fd"), 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *prim_get_signal_names(int argc, Scheme_Object **argv) {
|
void prim_signal_names_for_each(void (*callback)(char*, int)) {
|
||||||
Scheme_Hash_Table *ht;
|
|
||||||
|
|
||||||
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
#define ADD_SIGNAL_NAME(n) callback(#n, n)
|
||||||
|
|
||||||
#define ADD_SIGNAL_NAME(n) scheme_hash_set(ht, scheme_intern_symbol(#n), scheme_make_integer(n))
|
|
||||||
|
|
||||||
/* POSIX.1-1990 */
|
/* POSIX.1-1990 */
|
||||||
ADD_SIGNAL_NAME(SIGHUP);
|
ADD_SIGNAL_NAME(SIGHUP);
|
||||||
|
@ -127,80 +122,51 @@ Scheme_Object *prim_get_signal_names(int argc, Scheme_Object **argv) {
|
||||||
|
|
||||||
#undef ADD_SIGNAL_NAME
|
#undef ADD_SIGNAL_NAME
|
||||||
|
|
||||||
return (Scheme_Object *) ht;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *prim_capture_signal(int argc, Scheme_Object **argv) {
|
bool prim_capture_signal(int signum, int code) {
|
||||||
int signum = SCHEME_INT_VAL(argv[0]);
|
|
||||||
int code = SCHEME_INT_VAL(argv[1]);
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0:
|
case 0:
|
||||||
if (XFORM_HIDE_EXPR(signal(signum, signal_handler_fn) == SIG_ERR)) {
|
if (signal(signum, signal_handler_fn) == SIG_ERR) {
|
||||||
perror("unix-signals-extension signal(2) install");
|
perror("unix-signals-extension signal(2) install");
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (XFORM_HIDE_EXPR(signal(signum, SIG_IGN) == SIG_ERR)) {
|
if (signal(signum, SIG_IGN) == SIG_ERR) {
|
||||||
perror("unix-signals-extension signal(2) ignore");
|
perror("unix-signals-extension signal(2) ignore");
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (XFORM_HIDE_EXPR(signal(signum, SIG_DFL) == SIG_ERR)) {
|
if (signal(signum, SIG_DFL) == SIG_ERR) {
|
||||||
perror("unix-signals-extension signal(2) default");
|
perror("unix-signals-extension signal(2) default");
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
return scheme_true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *prim_send_signal(int argc, Scheme_Object **argv) {
|
bool prim_send_signal(pid_t pid, int sig) {
|
||||||
pid_t pid = SCHEME_INT_VAL(argv[0]);
|
|
||||||
int sig = SCHEME_INT_VAL(argv[1]);
|
|
||||||
if (kill(pid, sig) == -1) {
|
if (kill(pid, sig) == -1) {
|
||||||
perror("unix-signals-extension kill(2)");
|
perror("unix-signals-extension kill(2)");
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
return scheme_true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *scheme_reload(Scheme_Env *env) {
|
bool racket_unix_signals_init(void) {
|
||||||
Scheme_Env *module_env;
|
|
||||||
Scheme_Object *proc;
|
|
||||||
|
|
||||||
if (!self_pipe_initialized) {
|
if (!self_pipe_initialized) {
|
||||||
if (setup_self_pipe() == -1) {
|
if (setup_self_pipe() == -1) {
|
||||||
return scheme_false;
|
return false;
|
||||||
}
|
}
|
||||||
self_pipe_initialized = 1;
|
self_pipe_initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_env = scheme_primitive_module(scheme_intern_symbol("unix-signals-extension"), env);
|
return true;
|
||||||
|
|
||||||
proc = scheme_make_prim_w_arity(prim_get_signal_fd, "get-signal-fd", 0, 0);
|
|
||||||
scheme_add_global("get-signal-fd", proc, module_env);
|
|
||||||
|
|
||||||
proc = scheme_make_prim_w_arity(prim_get_signal_names, "get-signal-names", 0, 0);
|
|
||||||
scheme_add_global("get-signal-names", proc, module_env);
|
|
||||||
|
|
||||||
proc = scheme_make_prim_w_arity(prim_capture_signal, "set-signal-handler!", 2, 2);
|
|
||||||
scheme_add_global("set-signal-handler!", proc, module_env);
|
|
||||||
|
|
||||||
proc = scheme_make_prim_w_arity(prim_send_signal, "lowlevel-send-signal!", 2, 2);
|
|
||||||
scheme_add_global("lowlevel-send-signal!", proc, module_env);
|
|
||||||
|
|
||||||
scheme_finish_primitive_module(module_env);
|
|
||||||
return scheme_void;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scheme_Object *scheme_initialize(Scheme_Env *env) {
|
|
||||||
return scheme_reload(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
Scheme_Object *scheme_module_name() {
|
|
||||||
return scheme_intern_symbol("unix-signals-extension");
|
|
||||||
}
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env racket
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(module test '#%kernel)
|
||||||
|
|
||||||
|
(require unix-signals)
|
||||||
|
|
||||||
|
(module+ main
|
||||||
|
(capture-signal! 'SIGUSR1)
|
||||||
|
(capture-signal! 'SIGUSR2)
|
||||||
|
(printf "Try 'kill -USR1 ~a' and 'kill -USR2 ~a'\n" (getpid) (getpid))
|
||||||
|
(let loop ([mode #t])
|
||||||
|
(define signum
|
||||||
|
(if mode
|
||||||
|
(read-signal)
|
||||||
|
(sync next-signal-evt)))
|
||||||
|
(printf "Received signal ~v (name ~v)\n" signum (lookup-signal-name signum))
|
||||||
|
(loop (not mode))))
|
|
@ -6,30 +6,25 @@
|
||||||
@title{unix-signals}
|
@title{unix-signals}
|
||||||
@author[(author+email "Tony Garnock-Jones" "tonyg@leastfixedpoint.com")]
|
@author[(author+email "Tony Garnock-Jones" "tonyg@leastfixedpoint.com")]
|
||||||
|
|
||||||
If you find that this library lacks some feature you need, or you have
|
@(defmodule unix-signals)
|
||||||
a suggestion for improving it, please don't hesitate to
|
|
||||||
@link["mailto:tonyg@leastfixedpoint.com"]{get in touch with me}!
|
|
||||||
|
|
||||||
@section{Introduction}
|
@nested[#:style 'inset]{
|
||||||
|
If you find that this library lacks some feature you need, or you have
|
||||||
|
a suggestion for improving it, please don't hesitate to
|
||||||
|
@link["mailto:tonyg@leastfixedpoint.com"]{get in touch with me}!
|
||||||
|
}
|
||||||
|
|
||||||
This library provides a means of sending and receiving Unix signals to
|
This library provides a means of sending and receiving Unix signals to
|
||||||
Racket programs.
|
Racket programs.
|
||||||
|
|
||||||
Be warned that attempting to receive certain signals used by the
|
@(define unsafe
|
||||||
Racket runtime is dangerous, as the code here will conflict with the
|
@tech[#:doc '(lib "scribblings/reference/reference.scrbl")]{unsafe})
|
||||||
|
|
||||||
|
@bold{Be warned} that attempting to receive certain signals used by the
|
||||||
|
Racket runtime is @|unsafe|, as the code here will conflict with the
|
||||||
code in Racket itself.
|
code in Racket itself.
|
||||||
|
|
||||||
@section{What to require}
|
@section{Waiting for a signal}
|
||||||
|
|
||||||
All the functionality below can be accessed with a single
|
|
||||||
@racket[require]:
|
|
||||||
|
|
||||||
@(defmodule unix-signals)
|
|
||||||
|
|
||||||
This library represents signal names as symbols all in upper-case;
|
|
||||||
for example, @racket['SIGUSR1] and @racket['SIGKILL].
|
|
||||||
|
|
||||||
@subsection{Waiting for a signal}
|
|
||||||
|
|
||||||
To receive Unix signals using this library, call
|
To receive Unix signals using this library, call
|
||||||
@racket[capture-signal!] once for each signal of interest, and then
|
@racket[capture-signal!] once for each signal of interest, and then
|
||||||
|
@ -56,15 +51,27 @@ Racket process.
|
||||||
@defproc[(capture-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
@defproc[(capture-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
||||||
Installs a signal handler for the given signal. When the given signal
|
Installs a signal handler for the given signal. When the given signal
|
||||||
is received by the process, its signal number will be returned by uses
|
is received by the process, its signal number will be returned by uses
|
||||||
of @racket[next-signal-evt] and/or @racket[read-signal]. }
|
of @racket[next-signal-evt] and/or @racket[read-signal].
|
||||||
|
|
||||||
|
Note that this function is @|unsafe|:
|
||||||
|
it can corrupt or crash the Racket runtime system.
|
||||||
|
}
|
||||||
|
|
||||||
@defproc[(ignore-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
@defproc[(ignore-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
||||||
Causes the given signal to be ignored (@tt{SIG_IGN}) by the process. }
|
Causes the given signal to be ignored (@tt{SIG_IGN}) by the process.
|
||||||
|
|
||||||
|
Note that this function is @|unsafe|:
|
||||||
|
it can corrupt or crash the Racket runtime system.
|
||||||
|
}
|
||||||
|
|
||||||
@defproc[(release-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
@defproc[(release-signal! [sig (or/c fixnum? symbol?)]) boolean?]{
|
||||||
Installs the default handler (@tt{SIG_DFL}) for the given signal. }
|
Installs the default handler (@tt{SIG_DFL}) for the given signal.
|
||||||
|
|
||||||
@defthing[next-signal-evt evt?]{ @tech[#:doc
|
Note that this function is @|unsafe|:
|
||||||
|
it can corrupt or crash the Racket runtime system.
|
||||||
|
}
|
||||||
|
|
||||||
|
@defthing[next-signal-evt (evt/c fixnum?)]{ @tech[#:doc
|
||||||
'(lib "scribblings/reference/reference.scrbl")]{Synchronizable event} which
|
'(lib "scribblings/reference/reference.scrbl")]{Synchronizable event} which
|
||||||
becomes ready when a signal previously registered with
|
becomes ready when a signal previously registered with
|
||||||
@racket[capture-signal!] is received, at which point it returns the
|
@racket[capture-signal!] is received, at which point it returns the
|
||||||
|
@ -77,17 +84,21 @@ number of the received signal. Signals are buffered internally using
|
||||||
the @link["http://cr.yp.to/docs/selfpipe.html"]{self-pipe trick}, and
|
the @link["http://cr.yp.to/docs/selfpipe.html"]{self-pipe trick}, and
|
||||||
are therefore delivered in order of receipt. }
|
are therefore delivered in order of receipt. }
|
||||||
|
|
||||||
@subsection{Sending a signal}
|
@section{Sending a signal}
|
||||||
|
|
||||||
This library provides @racket[getpid] from @racketmodname[racket/os]
|
|
||||||
for convenience.
|
|
||||||
|
|
||||||
@defproc[(send-signal! [pid fixnum?] [sig (or/c fixnum? symbol?)])
|
@defproc[(send-signal! [pid fixnum?] [sig (or/c fixnum? symbol?)])
|
||||||
boolean?]{ Calls @tt{kill(2)} to deliver the given signal to the
|
boolean?]{ Calls @tt{kill(2)} to deliver the given signal to the
|
||||||
given process ID. All special cases for @racket[pid] from the
|
given process ID. All special cases for @racket[pid] from the
|
||||||
@tt{kill(2)} manpage apply. }
|
@tt{kill(2)} manpage apply.
|
||||||
|
|
||||||
@subsection{Mapping between signal names and signal numbers}
|
Note that this function is @|unsafe|:
|
||||||
|
it can corrupt or crash the Racket runtime system.
|
||||||
|
|
||||||
|
For convenience, this library also re-exports
|
||||||
|
@racket[getpid] from @racketmodname[racket/os].
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Mapping between signal names and signal numbers}
|
||||||
|
|
||||||
@defproc[(lookup-signal-number [sym symbol?]) (opt/c fixnum?)]{
|
@defproc[(lookup-signal-number [sym symbol?]) (opt/c fixnum?)]{
|
||||||
Returns a fixnum if the symbol name is defined, or @racket[#f] if not. }
|
Returns a fixnum if the symbol name is defined, or @racket[#f] if not. }
|
||||||
|
|
Loading…
Reference in New Issue