[PATCH] Add signal sets and sigprocmask
by Richard Ipsum
---
luxio.c | 206 ++++++++++++++++++++++++++++++++++++-
luxio_constants.inc.in | 3 +
tests/test-sigprocmask.lua | 109 ++++++++++++++++++++
3 files changed, 317 insertions(+), 1 deletion(-)
create mode 100644 tests/test-sigprocmask.lua
diff --git a/luxio.c b/luxio.c
index f3e298d..0db4979 100644
--- a/luxio.c
+++ b/luxio.c
@@ -480,7 +480,144 @@ luxio_kill(lua_State *L) /* 3.3.2 */
/* Signals are going to be almost impossible to do nicely and safely. */
-/* TODO: Manipulate Signal Sets 3.3.3 */
+#define LUXIO_SIGNALSET_METATABLE "luxio.signalset"
+
+typedef struct {
+ sigset_t set;
+} luxio_signalset;
+
+static int
+luxio_signalset_tostring(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "sigset: %p", &s->set);
+ lua_pushstring(L, buf);
+
+ return 1;
+}
+
+static void
+luxio__bless_signalset(lua_State *L)
+{
+ int create = luaL_newmetatable(L, LUXIO_SIGNALSET_METATABLE);
+
+ if (create != 0) {
+ lua_pushcfunction(L, luxio_signalset_tostring);
+ lua_setfield(L, -2, "__tostring");
+ }
+
+ lua_setmetatable(L, -2);
+}
+
+/*** Create a new signal set
+@treturn A new signal set
+*/
+static int
+luxio_newsigset(lua_State *L)
+{
+ luxio_signalset *s = lua_newuserdata(L, sizeof(*s));
+
+ luxio__bless_signalset(L);
+
+ return 1;
+}
+
+/*** Initialise a signal set to be empty.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigemptyset
+*/
+static int
+luxio_sigemptyset(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ lua_pushinteger(L, sigemptyset(&s->set));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+/*** Initialise a signal set to contain all signals.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigfillset
+*/
+static int
+luxio_sigfillset(lua_State *L)
+{
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE);
+ lua_pushinteger(L, sigfillset(&s->set));
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
+#define LUXIO__SIGSET_OPERATION(L, op) do { \
+ luxio_signalset *s = luaL_checkudata(L, 1, LUXIO_SIGNALSET_METATABLE); \
+ int signo = luaL_checkinteger(L, 2); \
+ lua_pushinteger(L, op(&s->set, signo)); \
+ lua_pushinteger(L, errno); \
+ return 2; \
+} while (0)
+
+/*** Add a signal to a signal set.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigaddset
+*/
+static int
+luxio_sigaddset(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigaddset);
+}
+
+/*** Remove a signal from a signal set.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigdelset
+*/
+static int
+luxio_sigdelset(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigdelset);
+}
+
+/*** Check whether a signal set contains a given signal.
+
+Return 0 on success, or -1 on error with errno set appropriately.
+
+@tparam sigset signal set
+@tparam number signo signal
+@treturn number return value
+@treturn errno errno
+@function sigismember
+*/
+static int luxio_sigismember(lua_State *L)
+{
+ LUXIO__SIGSET_OPERATION(L, sigismember);
+}
/* NSIG is not in POSIX, it's 64 on Linux and 33 on OpenBSD
* we define a value much larger than either to be on the safe side */
@@ -703,6 +840,10 @@ luxio_sigaction(lua_State *L)
} else {
goto einval;
}
+ } else if (strcmp(key, "sa_mask") == 0) {
+ luxio_signalset *s = luaL_checkudata(L, -1, LUXIO_SIGNALSET_METATABLE);
+ sa.sa_mask = s->set;
+ lua_pop(L, 1);
} else if (strcmp(key, "sa_flags") == 0) {
sa.sa_flags = luaL_checkint(L, -1);
lua_pop(L, 1);
@@ -738,6 +879,61 @@ enospc:
}
/* TODO: pthread_sigmask(), sigprocmask() 3.3.5 */
+
+/*** Manipulate the current signal mask.
+
+sigprocmask examines and/or changes the current process signal mask.
+Signals are blocked if they are members of the current signal mask set.
+
+The action performed by sigprocmask depends on the value of `how`,
+which can be one of:
+
+- `luxio.SIG_BLOCK` - The new mask is the existing mask plus all of the
+signals in the specified set.
+
+- `luxio.SIG_UNBLOCK` - The new mask is the existing mask minus the signals
+contained within the specified set.
+
+- `luxio.SIG_SETMASK` - The current mask is replaced with the specified set.
+
+On success the previous signal mask will be returned, otherwise on error
+nil will be returned and errno will be set appropriately.
+
+If the `set` parameter is set to nil then the current signal mask will
+be returned without performing any modification to the current signal mask,
+and the `how` parameter will be ignored.
+
+@tparam number how Action to perform on signal mask
+@tparam sigset set signal set
+@treturn return number return value
+@treturn errno
+@function sigprocmask
+*/
+static int
+luxio_sigprocmask(lua_State *L)
+{
+ int how = luaL_checkinteger(L, 1);
+ void *p = lua_touserdata(L, 2);
+ sigset_t orig, *set = NULL;
+
+ if (p != NULL) {
+ luxio_signalset *s = luaL_checkudata(L, 2, LUXIO_SIGNALSET_METATABLE);
+ set = &s->set;
+ }
+
+ if (sigprocmask(how, set, &orig) == -1) {
+ lua_pushnil(L);
+ } else {
+ luxio_signalset *o = lua_newuserdata(L, sizeof(*o));
+ o->set = orig;
+ luxio__bless_signalset(L);
+ }
+
+ lua_pushinteger(L, errno);
+
+ return 2;
+}
+
/* TODO: sigpending() 3.3.6 */
/* TODO: sigsuspend() 3.3.7 */
/* TODO: sigwait(), sigwaitinfo(), sigtimedwait() 3.3.8 */
@@ -4818,7 +5014,15 @@ luxio_functions[] = {
{ "chdir", luxio_chdir },
{ "getcwd", luxio_getcwd },
+ { "newsigset", luxio_newsigset },
+ { "sigemptyset", luxio_sigemptyset },
+ { "sigfillset", luxio_sigfillset },
+ { "sigaddset", luxio_sigaddset },
+ { "sigdelset", luxio_sigdelset },
+ { "sigismember", luxio_sigismember },
+
{ "sigaction", luxio_sigaction },
+ { "sigprocmask", luxio_sigprocmask },
{ "alarm", luxio_alarm },
{ "pause", luxio_pause },
diff --git a/luxio_constants.inc.in b/luxio_constants.inc.in
index ef3cadb..22a1f13 100644
--- a/luxio_constants.inc.in
+++ b/luxio_constants.inc.in
@@ -216,6 +216,9 @@ static const struct {
/* signals */
{"SIG_DFL", (int) SIG_DFL},
{"SIG_IGN", (int) SIG_IGN},
+ E(SIG_BLOCK),
+ E(SIG_UNBLOCK),
+ E(SIG_SETMASK),
E(SIGHUP),
E(SIGINT),
E(SIGQUIT),
diff --git a/tests/test-sigprocmask.lua b/tests/test-sigprocmask.lua
new file mode 100644
index 0000000..490672b
--- /dev/null
+++ b/tests/test-sigprocmask.lua
@@ -0,0 +1,109 @@
+local l = require "luxio"
+
+set = l.newsigset()
+
+r, errno = l.sigemptyset(set)
+if r == -1 then
+ io.stderr:write(("sigemptyset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Empty set", set)
+
+r, errno = l.sigfillset(set)
+if r == -1 then
+ io.stderr:write(("sigfillset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Full set", set)
+
+r, errno = l.sigismember(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("SIGINT is member of set?", r == 1 and "yes" or "no")
+
+print("sigdelset(set, SIGINT)...")
+r, errno = l.sigdelset(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigdelset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+r, errno = l.sigismember(set, l.SIGINT)
+if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("SIGINT is member of set?", r == 1 and "yes" or "no")
+
+print("l.sigemptyset(set)...")
+r, errno = l.sigemptyset(set)
+if r == -1 then
+ io.stderr:write(("sigemptyset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("Empty set", set)
+
+
+to_block = {["SIGINT"] = l.SIGINT, ["SIGUSR1"] = l.SIGUSR1}
+
+for signame, signo in pairs(to_block) do
+ print(("sigaddset(set, %s)..."):format(signame))
+ r, errno = l.sigaddset(set, signo)
+ if r == -1 then
+ io.stderr:write(("sigaddset: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+ end
+
+ r, errno = l.sigismember(set, signo)
+ if r == -1 then
+ io.stderr:write(("sigismember: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+ end
+
+ print(("%s is member of set?"):format(signame), r == 1 and "yes" or "no")
+end
+
+origset, errno = l.sigprocmask(0, nil)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+print("Got the current signal set", origset)
+
+print("set", set)
+origset, errno = l.sigprocmask(l.SIG_BLOCK, set)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+print("origset", origset)
+
+i = 1
+while (i <= 5) do
+ print(i)
+ l.sleep(2)
+ i = i + 1
+end
+
+print("restoring original signal mask...")
+
+origset, errno = l.sigprocmask(l.SIG_SETMASK, origset)
+if origset == nil then
+ io.stderr:write(("sigprocmask: %s\n"):format(l.strerror(errno)))
+ os.exit(os.EXIT_FAILURE)
+end
+
+print("done")
+print("origset", origset)
+
+while (true) do
+ l.sleep(2)
+ print("sleep")
+end
--
2.21.0
4 years, 1 month
Summary of commit times in gitano
by Richard Ipsum
Hi,
Having seen
https://ivan.bessarabov.com/blog/famous-programmers-work-time
I thought it would be fun to analyse commits in gitano.
Since gitano is split across several repos I first combined everything
into a monorepo to make the analysis more complete. This was done by
merging each remote into the repo one at a time[1], the resulting repo
is here in case you want to run your own queries on it[2].
Merge commits are done by an author called "Null" so we can exclude
this author.
% git log --author="^[^N]"
--date=iso | perl -nalE 'if (/^Date:\s+[\d-]{10}\s(\d{2})/) { say $1+0
}' | sort | uniq -c|perl -MList::Util=max -nalE '$h{$F[1]} = $F[0]; }{
$m = max values %h; foreach (0..23) { $h{$_} = 0 if not exists $h{$_} }
foreach (sort {$a <=> $b } keys %h) { say sprintf "%02d - %4d %s", $_,
$h{$_}, "*"x ($h{$_} / $m * 50); }'
00 - 4 *
01 - 0
02 - 3
03 - 0
04 - 0
05 - 0
06 - 0
07 - 3
08 - 8 **
09 - 58 ****************
10 - 91 **************************
11 - 155 ********************************************
12 - 111 ********************************
13 - 109 *******************************
14 - 173 **************************************************
15 - 167 ************************************************
16 - 164 ***********************************************
17 - 95 ***************************
18 - 73 *********************
19 - 49 **************
20 - 41 ***********
21 - 62 *****************
22 - 75 *********************
23 - 44 ************
So it seems the project has a total of 1485 commits, and that gitano
devs sleep unlike some of the authors listed in the blog. :)
Richard
[1]:
https://bneijt.nl/blog/post/merge-a-subdirectory-of-another-repository-wi...
[2]: http://violaine.xyz/git/gitano-monorepo.git/
4 years, 2 months