Subject: new version of siginfo patch
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: tech-kern
Date: 09/15/2003 11:27:58
Hello,
1. Following gimpy's suggestion I converted the code to use <queue.h>
macros for list manipulation ; this required to add code to
initialize the head of the queue in a couple of places. I chose
circleq instead of stailq, because to remove an element stailq
needs to re-traverse the list. It would be nice to have a special
iterator that keeps track of the previous element, and can remove
the current element without re-scanning.
2. I added a lock to guard the queue.
3. Following enami's suggestion I made get remove the element from the
list, and eliminated other unnecessary functions.
4. in kern_proc.c, I initialized p_lwplock just for consistency, although
it is not strictly needed for proc0, and fork() takes care of the rest
of the cases.
Thanks everyone for their feedback, and keep it coming.
christos
Index: siginfo.h
===================================================================
RCS file: /cvsroot/src/sys/sys/siginfo.h,v
retrieving revision 1.3
diff -u -u -r1.3 siginfo.h
--- siginfo.h 2003/09/14 07:00:45 1.3
+++ siginfo.h 2003/09/15 14:31:34
@@ -40,6 +40,7 @@
#define _SYS_SIGINFO_H_
#include <machine/signal.h> /* XXX: __HAVE_SIGINFO */
+#include <sys/queue.h>
typedef union sigval {
int sival_int;
@@ -79,8 +80,7 @@
int _fd;
} _poll;
} _reason;
- struct ksiginfo *ksi_next;
- struct ksiginfo *ksi_prev;
+ CIRCLEQ_ENTRY(ksiginfo) _list;
};
typedef union siginfo {
@@ -125,6 +125,8 @@
#define ksi_band _reason._poll._band
#define ksi_fd _reason._poll._fd
+
+#define ksi_list _list
#endif
/** si_code */
Index: signalvar.h
===================================================================
RCS file: /cvsroot/src/sys/sys/signalvar.h,v
retrieving revision 1.43
diff -u -u -r1.43 signalvar.h
--- signalvar.h 2003/09/14 07:00:46 1.43
+++ signalvar.h 2003/09/15 14:31:35
@@ -34,6 +34,8 @@
#ifndef _SYS_SIGNALVAR_H_ /* tmp for user.h */
#define _SYS_SIGNALVAR_H_
+#include <sys/lock.h>
+#include <sys/queue.h>
/*
* Kernel signal definitions and data structures,
* not exported to user programs.
@@ -61,7 +63,8 @@
char ps_sigcheck; /* May have deliverable signals. */
int ps_sigwaited; /* Delivered signal from wait set */
sigset_t ps_sigwait; /* Signals being waited for */
- struct ksiginfo *ps_siginfo; /* for SA_SIGINFO */
+ struct simplelock ps_silock; /* Lock for ps_siginfo */
+ CIRCLEQ_HEAD(, ksiginfo) ps_siginfo;/* for SA_SIGINFO */
/* This should be copied on fork */
#define ps_startcopy ps_sigstk
Index: kern_fork.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_fork.c,v
retrieving revision 1.110
diff -u -u -r1.110 kern_fork.c
--- kern_fork.c 2003/08/07 16:31:45 1.110
+++ kern_fork.c 2003/09/15 14:34:02
@@ -274,6 +274,8 @@
memcpy(&p2->p_startcopy, &p1->p_startcopy,
(unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy));
+ simple_lock_init(&p2->p_sigctx.ps_silock);
+ CIRCLEQ_INIT(&p2->p_sigctx.ps_siginfo);
simple_lock_init(&p2->p_lwplock);
LIST_INIT(&p2->p_lwps);
Index: kern_proc.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_proc.c,v
retrieving revision 1.65
diff -u -u -r1.65 kern_proc.c
--- kern_proc.c 2003/08/07 16:31:47 1.65
+++ kern_proc.c 2003/09/15 14:34:03
@@ -464,9 +464,12 @@
{
int s;
+ simple_lock_init(&p->p_lwplock);
LIST_INIT(&p->p_lwps);
LIST_INSERT_HEAD(&p->p_lwps, l, l_sibling);
p->p_nlwps = 1;
+ simple_lock_init(&p->p_sigctx.ps_silock);
+ CIRCLEQ_INIT(&p->p_sigctx.ps_siginfo);
s = proclist_lock_write();
Index: kern_sig.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_sig.c,v
retrieving revision 1.154
diff -u -u -r1.154 kern_sig.c
--- kern_sig.c 2003/09/14 23:45:53 1.154
+++ kern_sig.c 2003/09/15 14:34:04
@@ -83,8 +83,6 @@
static void proc_stop(struct proc *);
static int build_corename(struct proc *, char [MAXPATHLEN]);
static void ksiginfo_exithook(struct proc *, void *);
-static void ksiginfo_save(struct proc *, ksiginfo_t *);
-static void ksiginfo_del(struct proc *, ksiginfo_t *);
static void ksiginfo_put(struct proc *, ksiginfo_t *);
static ksiginfo_t *ksiginfo_get(struct proc *, int);
@@ -106,72 +104,61 @@
((signum) == SIGCONT && (q)->p_session == (p)->p_session))
/*
- * return the first ksiginfo struct from our hash table
+ * Remove and return the first ksiginfo element that matches our requested
+ * signal, or return NULL if one not found.
*/
static ksiginfo_t *
ksiginfo_get(struct proc *p, int signo)
{
- ksiginfo_t *ksi, *hp = p->p_sigctx.ps_siginfo;
+ ksiginfo_t *ksi;
- if ((ksi = hp) == NULL)
- return NULL;
-
- for (;;) {
- if (ksi->ksi_signo == signo)
+ simple_lock(&p->p_sigctx.ps_silock);
+ CIRCLEQ_FOREACH(ksi, &p->p_sigctx.ps_siginfo, ksi_list) {
+ if (ksi->ksi_signo == signo) {
+ CIRCLEQ_REMOVE(&p->p_sigctx.ps_siginfo, ksi, ksi_list);
+ simple_unlock(&p->p_sigctx.ps_silock);
return ksi;
- if ((ksi = ksi->ksi_next) == hp)
- return NULL;
+ }
}
+ simple_unlock(&p->p_sigctx.ps_silock);
+ return NULL;
}
+/*
+ * Append a new ksiginfo element to the list of pending ksiginfo's, if
+ * we need to (SA_SIGINFO was requested). We replace non RT signals if
+ * they already existed in the queue and we add new entries for RT signals,
+ * or for non RT signals with non-existing entries.
+ */
static void
ksiginfo_put(struct proc *p, ksiginfo_t *ksi)
{
- ksiginfo_t *hp = p->p_sigctx.ps_siginfo;
-
- if (hp == NULL)
- p->p_sigctx.ps_siginfo = ksi->ksi_next = ksi->ksi_prev = ksi;
- else {
- ksi->ksi_prev = hp->ksi_prev;
- hp->ksi_prev->ksi_next = ksi;
- hp->ksi_prev = ksi;
- ksi->ksi_next = hp;
- }
-}
-
-static void
-ksiginfo_del(struct proc *p, ksiginfo_t *ksi)
-{
- if (ksi->ksi_next == ksi)
- p->p_sigctx.ps_siginfo = NULL;
- else {
- ksi->ksi_prev->ksi_next = ksi->ksi_next;
- ksi->ksi_next->ksi_prev = ksi->ksi_prev;
- }
-}
+ ksiginfo_t *kp;
+ struct sigaction *sa = &SIGACTION_PS(p->p_sigacts, ksi->ksi_signo);
-static void
-ksiginfo_save(struct proc *p, ksiginfo_t *ksi)
-{
- ksiginfo_t *kpool = NULL;
- if ((SIGACTION_PS(p->p_sigacts, ksi->ksi_signo).sa_flags & SA_SIGINFO)
- == 0)
+ if ((sa->sa_flags & SA_SIGINFO) == 0)
return;
- if (
+
+ simple_lock(&p->p_sigctx.ps_silock);
#ifdef notyet /* XXX: QUEUING */
- ksi->ksi_signo >= SIGRTMIN ||
+ if (ksi->ksi_signo < SIGRTMIN)
#endif
- (kpool = ksiginfo_get(p, ksi->ksi_signo)) == NULL) {
- if ((kpool = pool_get(&ksiginfo_pool, PR_NOWAIT)) == NULL)
- return;
- *kpool = *ksi;
- ksiginfo_put(p, kpool);
- } else {
- ksiginfo_t *next = ksi->ksi_next, *prev = ksi->ksi_prev;
- *kpool = *ksi;
- kpool->ksi_next = next;
- kpool->ksi_prev = prev;
+ {
+ CIRCLEQ_FOREACH(kp, &p->p_sigctx.ps_siginfo, ksi_list) {
+ if (kp->ksi_signo == ksi->ksi_signo) {
+ CIRCLEQ_ENTRY(ksiginfo) sv;
+ (void)memcpy(&sv, &kp->ksi_list, sizeof(sv));
+ *kp = *ksi;
+ (void)memcpy(&kp->ksi_list, &sv, sizeof(sv));
+ simple_unlock(&p->p_sigctx.ps_silock);
+ return;
+ }
+ }
}
+ kp = pool_get(&ksiginfo_pool, PR_NOWAIT);
+ *kp = *ksi;
+ CIRCLEQ_INSERT_TAIL(&p->p_sigctx.ps_siginfo, kp, ksi_list);
+ simple_unlock(&p->p_sigctx.ps_silock);
}
/*
@@ -180,15 +167,14 @@
static void
ksiginfo_exithook(struct proc *p, void *v)
{
- ksiginfo_t *ksi, *hp = p->p_sigctx.ps_siginfo;
- if ((ksi = hp) == NULL)
- return;
- for (;;) {
+ simple_lock(&p->p_sigctx.ps_silock);
+ while (!CIRCLEQ_EMPTY(&p->p_sigctx.ps_siginfo)) {
+ ksiginfo_t *ksi = CIRCLEQ_FIRST(&p->p_sigctx.ps_siginfo);
+ CIRCLEQ_REMOVE(&p->p_sigctx.ps_siginfo, ksi, ksi_list);
pool_put(&ksiginfo_pool, ksi);
- if ((ksi = ksi->ksi_next) == hp)
- break;
}
+ simple_unlock(&p->p_sigctx.ps_silock);
}
/*
@@ -1060,7 +1046,7 @@
&& sigismember(&p->p_sigctx.ps_sigwait, signum)
&& p->p_stat != SSTOP) {
if (action == SIG_CATCH)
- ksiginfo_save(p, ksi);
+ ksiginfo_put(p, ksi);
sigdelset(&p->p_sigctx.ps_siglist, signum);
p->p_sigctx.ps_sigwaited = signum;
sigemptyset(&p->p_sigctx.ps_sigwait);
@@ -1077,7 +1063,7 @@
*/
if (action == SIG_HOLD &&
((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) {
- ksiginfo_save(p, ksi);
+ ksiginfo_put(p, ksi);
return;
}
/* XXXSMP: works, but icky */
@@ -1261,7 +1247,7 @@
runfast:
if (action == SIG_CATCH) {
- ksiginfo_save(p, ksi);
+ ksiginfo_put(p, ksi);
action = SIG_HOLD;
}
/*
@@ -1271,14 +1257,14 @@
l->l_priority = PUSER;
run:
if (action == SIG_CATCH) {
- ksiginfo_save(p, ksi);
+ ksiginfo_put(p, ksi);
action = SIG_HOLD;
}
setrunnable(l); /* XXXSMP: recurse? */
out:
if (action == SIG_CATCH)
- ksiginfo_save(p, ksi);
+ ksiginfo_put(p, ksi);
done:
/* XXXSMP: works, but icky */
if (dolock)
@@ -1757,7 +1743,6 @@
kpsendsig(l, &ksi1, returnmask);
} else {
kpsendsig(l, ksi, returnmask);
- ksiginfo_del(p, ksi);
pool_put(&ksiginfo_pool, ksi);
}
p->p_sigctx.ps_lwp = 0;