9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: adr <adr@SDF.ORG>
To: 9fans <9fans@9fans.net>
Subject: Re: [9fans] syscall silently kill processes
Date: Tue, 28 Jun 2022 15:28:20 +0000 (UTC)	[thread overview]
Message-ID: <87cff69b-4b82-8466-a34f-13c7eda24fc9@SDF.ORG> (raw)
In-Reply-To: <9307b24-ba87-e7b0-342e-71bf83835ed@SDF.ORG>

[-- Attachment #1: Type: text/plain, Size: 11131 bytes --]

Andrey, if you want to use different note handlers per process (with a big
number of processes) using libthread, this may be helpful.

The idea is this:

An array of handlers for all processes which can be changed by all processes.
When a note is received by a process, this array takes priority.

An array of pointers to structures of the type

struct Onnote
{
        int pid;
        int (*fn[NFN])(void*, char*);
};

initially of size PPCHUNK (I set it to 100, experiment with that),
but it can grow if necessary (but not shrink, I think this would
be overkilling).

These structures are allocated the first time a process record a
handler and freed when the process exits (or by calling
threadcancelnotes(), note that this function can free other processes'
function handlers, maybe should be better to make some restrictions)

The use of "in" in threadnotify(int (*f)(void*, char*), int in) is:

in > 0 : set the handler for the calling process.
in == 0 : clear the handler for the calling process.
in == -1 : clear the handler for all processes (except those who has
            registered it already for themselves).
in < -1 : set the handler for all processes.

There is no use of threadnotify with "in < 0" in /sys/src, so nothing is broken.

As you are using 9front and they are serving their sources with
9p, here is a diff to their sources. I haven't compiled it in
9front, though. Note that if you want to compile the system with
this changes, you have to eliminate the copy of note.c at
/sys/src/cmd/execnet (it seems that note.c was added afterwards as
I thought).

I haven't test it too much, this has been more like a time-destroyer
pastime.

adr
--- /tmp/main.c
+++ /sys/src/libthread/main.c
@@ -28,6 +28,10 @@
        _qlockinit(_threadrendezvous);
        _sysfatal = _threadsysfatal;
        __assert = _threadassert;
+       onnote = mallocz(PPCHUNK*sizeof(uintptr), 1);
+       if(!onnote)
+               sysfatal("Malloc of size %d failed: %r", PPCHUNK*sizeof(uintptr));
+       onnotesize = PPCHUNK;
        notify(_threadnote);
        if(mainstacksize == 0)
                mainstacksize = 8*1024;
--- /tmp/note.c
+++ /sys/src/libthread/note.c
@@ -5,9 +5,9 @@

  int   _threadnopasser;

-#define        NFN             33
  #define       ERRLEN  48
  typedef struct Note Note;
+
  struct Note
  {
        Lock            inuse;
@@ -17,62 +17,155 @@

  static Note   notes[128];
  static Note   *enotes = notes+nelem(notes);
-static int             (*onnote[NFN])(void*, char*);
-static int             onnotepid[NFN];
+Onnote **onnote;
+int onnotesize;
+static int (*onnoteall[NFN])(void*, char*);
  static Lock   onnotelock;

  int
  threadnotify(int (*f)(void*, char*), int in)
  {
-       int i, topid;
-       int (*from)(void*, char*), (*to)(void*, char*);
+       int i, j;

-       if(in){
-               from = nil;
-               to = f;
-               topid = _threadgetproc()->pid;
-       }else{
-               from = f;
-               to = nil;
-               topid = 0;
-       }
        lock(&onnotelock);
-       for(i=0; i<NFN; i++)
-               if(onnote[i]==from){
-                       onnote[i] = to;
-                       onnotepid[i] = topid;
+
+       /* add note for all processes */
+       if(in < -1){
+               for(i=0; i<NFN; i++)
+                       if(onnoteall[i] == f){
+                               unlock(&onnotelock);
+                               return 1;
+                       }
+               for(i=0; i<NFN; i++)
+                       if(onnoteall[i] == nil){
+                               onnoteall[i] = f;
+                               break;
+                       }
+               unlock(&onnotelock);
+               return i<NFN;
+       }
+
+       /* remove note for all processes */
+       if(in == -1){
+               for(i=0; i<NFN; i++)
+                       if(onnoteall[i] == f){
+                               onnoteall[i] = nil;
+                               break;
+                       }
+               unlock(&onnotelock);
+               return i<NFN;
+       }
+
+       /* remove note for current process */
+       if(!in){
+               for(i=0; i<onnotesize; i++){
+                       if(onnote[i]!=nil && onnote[i]->pid==_threadgetproc()->pid){
+                               for(j=0; j<NFN; j++){
+                                       if(onnote[i]->fn[j] == f){
+                                               onnote[i]->fn[j] = 0;
+                                               break;
+                                       }
+                               }
+                               unlock(&onnotelock);
+                               return j<NFN;
+                       }
+               }
+               unlock(&onnotelock);
+               return i<onnotesize;
+       }
+
+       /* add note for current process */
+       for(i=0; i<onnotesize; i++)
+               if(onnote[i] && onnote[i]->pid==_threadgetproc()->pid)
+                       break;
+
+       /* process has already a slot */
+       if(i < onnotesize){
+               for(j=0; j<NFN; j++){
+                       if(onnote[i]->fn[j] == nil){
+                               onnote[i]->fn[j] = f;
+                               break;
+                       }
+               }
+               unlock(&onnotelock);
+               return j<NFN;
+ 
+       }
+
+       for(i=0; i<onnotesize; i++)
+               if(!onnote[i])
+                       break;
+
+       /* there is no free slot */
+       if(i == onnotesize){
+               onnotesize += PPCHUNK;
+               onnote = realloc(onnote, onnotesize*sizeof(uintptr));
+               if(!onnote){
+                       unlock(&onnotelock);
+                       sysfatal("Malloc of size %d failed: %r", onnotesize*sizeof(uintptr));
+               }
+               memset(onnote+i+1, 0, PPCHUNK-1);
+       }
+
+       onnote[i]=mallocz(sizeof(Onnote), 1);
+       if(!onnote[i]){
+               unlock(&onnotelock);
+               sysfatal("Malloc of size %d failed: %r", sizeof(Onnote));
+       }
+       onnote[i]->pid = _threadgetproc()->pid;
+       onnote[i]->fn[0] = f;
+       unlock(&onnotelock);
+       return 1;
+}
+
+void
+threadcancelnotes(int pid)
+{
+       int i;
+
+       lock(&onnotelock);
+       for(i=0; i<onnotesize; i++)
+               if(onnote[i] && onnote[i]->pid==pid){
+                       free(onnote[i]);
+                       onnote[i] = nil;
                        break;
                }
        unlock(&onnotelock);
-       return i<NFN;
+       return;
  }

  static void
  delayednotes(Proc *p, void *v)
  {
-       int i;
+       int i, j, all;
        Note *n;
-       char s[ERRMAX];
-       int (*fn)(void*, char*);
+       int (*f)(void*, char*);

        if(!p->pending)
                return;

        p->pending = 0;
+       all = j = 0;
        for(n=notes; n<enotes; n++){
                if(n->proc == p){
-                       strcpy(s, n->s);
-                       n->proc = nil;
-                       unlock(&n->inuse);
-
-                       for(i=0; i<NFN; i++){
-                               if(onnotepid[i]!=p->pid || (fn = onnote[i])==nil)
-                                       continue;
-                               if((*fn)(v, s))
-                                       break;
+                       for(i=0; i<NFN; i++)
+                               if(f=onnoteall[i])
+                                       if((*f)(v, n->s)){
+                                               all = 1;
+                                               break;
+                                       }
+                       if(!all){
+                               for(i=0; i<onnotesize; i++)
+                                       if(onnote[i] && onnote[i]->pid==p->pid){
+                                               for(j=0; j<NFN; j++)
+                                                       if(f=onnote[i]->fn[j])
+                                                               if((*f)(v, n->s))
+                                                                       break;
+                                               break;
+                                       }
                        }
-                       if(i==NFN){
-                               _threaddebug(DBGNOTE, "Unhandled note %s, proc %p", n->s, p);
+                       if(!all && (i==onnotesize || j==NFN)){
+                               _threaddebug(DBGNOTE, "Unhandled note %s, proc %p\n", n->s, p);
                                if(v != nil)
                                        noted(NDFLT);
                                else if(strncmp(n->s, "sys:", 4)==0)
@@ -79,6 +172,8 @@
                                        abort();
                                threadexitsall(n->s);
                        }
+                       n->proc = nil;
+                       unlock(&n->inuse);
                }
        }
  }
@@ -94,7 +189,7 @@
                noted(NDFLT);

        if(_threadexitsallstatus){
-               _threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'", _threadexitsallstatus);
+               _threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'\n", _threadexitsallstatus);
                _exits(_threadexitsallstatus);
        }

--- /tmp/sched.c
+++ /sys/src/libthread/sched.c
@@ -157,6 +157,7 @@
                t = runthread(p);
                if(t == nil){
                        _threaddebug(DBGSCHED, "all threads gone; exiting");
+                       threadcancelnotes(p->pid);
                        unlinkproc(p);
                        _schedexit(p);  /* frees proc */
                }
--- /tmp/thread.h
+++ /sys/include/thread.h
@@ -97,6 +97,7 @@
  void  threadkillgrp(int);     /* kill threads in group */
  void  threadmain(int argc, char *argv[]);
  int   threadnotify(int (*f)(void*, char*), int in);
+void threadcancelnotes(int pid);
  int   threadid(void);
  int   threadpid(int);
  int   threadsetgrp(int);              /* set thread group, return old */
--- /tmp/threadimpl.h
+++ /sys/src/libthread/threadimpl.h
@@ -192,3 +192,15 @@
  #define       _threaddebug(flag, ...) if((_threaddebuglevel&(flag))==0){}else _threadprint(__VA_ARGS__)

  #define ioproc_arg(io, type)  (va_arg((io)->arg, type))
+
+#define        PPCHUNK 100
+#define        NFN 33
+typedef struct Onnote Onnote;
+struct Onnote
+{
+       int pid;
+       int (*fn[NFN])(void*, char*);
+};
+extern Onnote **onnote;
+extern int onnotesize;
+void _threadnote(void*, char*);
------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/Tfa6823048ad90a21-M401cfa47db4a93cc273cac83
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-diff; name=thread.patch, Size: 6088 bytes --]

--- /tmp/main.c
+++ /sys/src/libthread/main.c
@@ -28,6 +28,10 @@
 	_qlockinit(_threadrendezvous);
 	_sysfatal = _threadsysfatal;
 	__assert = _threadassert;
+	onnote = mallocz(PPCHUNK*sizeof(uintptr), 1);
+	if(!onnote)
+		sysfatal("Malloc of size %d failed: %r", PPCHUNK*sizeof(uintptr));
+	onnotesize = PPCHUNK;
 	notify(_threadnote);
 	if(mainstacksize == 0)
 		mainstacksize = 8*1024;
--- /tmp/note.c
+++ /sys/src/libthread/note.c
@@ -5,9 +5,9 @@
 
 int	_threadnopasser;
 
-#define	NFN		33
 #define	ERRLEN	48
 typedef struct Note Note;
+
 struct Note
 {
 	Lock		inuse;
@@ -17,62 +17,155 @@
 
 static Note	notes[128];
 static Note	*enotes = notes+nelem(notes);
-static int		(*onnote[NFN])(void*, char*);
-static int		onnotepid[NFN];
+Onnote **onnote;
+int onnotesize;
+static int (*onnoteall[NFN])(void*, char*);
 static Lock	onnotelock;
 
 int
 threadnotify(int (*f)(void*, char*), int in)
 {
-	int i, topid;
-	int (*from)(void*, char*), (*to)(void*, char*);
+	int i, j;
 
-	if(in){
-		from = nil;
-		to = f;
-		topid = _threadgetproc()->pid;
-	}else{
-		from = f;
-		to = nil;
-		topid = 0;
-	}
 	lock(&onnotelock);
-	for(i=0; i<NFN; i++)
-		if(onnote[i]==from){
-			onnote[i] = to;
-			onnotepid[i] = topid;
+
+	/* add note for all processes */
+	if(in < -1){
+		for(i=0; i<NFN; i++)
+			if(onnoteall[i] == f){
+				unlock(&onnotelock);
+				return 1;
+			}
+		for(i=0; i<NFN; i++)
+			if(onnoteall[i] == nil){
+				onnoteall[i] = f;
+				break;
+			}
+		unlock(&onnotelock);
+		return i<NFN;
+	}
+
+	/* remove note for all processes */
+	if(in == -1){
+		for(i=0; i<NFN; i++)
+			if(onnoteall[i] == f){
+				onnoteall[i] = nil;
+				break;
+			}
+		unlock(&onnotelock);
+		return i<NFN;
+	}
+
+	/* remove note for current process */
+	if(!in){
+		for(i=0; i<onnotesize; i++){
+			if(onnote[i]!=nil && onnote[i]->pid==_threadgetproc()->pid){
+				for(j=0; j<NFN; j++){
+					if(onnote[i]->fn[j] == f){
+						onnote[i]->fn[j] = 0;
+						break;
+					}
+				}
+				unlock(&onnotelock);
+				return j<NFN;
+			}
+		}
+		unlock(&onnotelock);
+		return i<onnotesize;
+	}
+
+	/* add note for current process */
+	for(i=0; i<onnotesize; i++)
+		if(onnote[i] && onnote[i]->pid==_threadgetproc()->pid)
+			break;
+
+	/* process has already a slot */
+	if(i < onnotesize){
+		for(j=0; j<NFN; j++){
+			if(onnote[i]->fn[j] == nil){
+				onnote[i]->fn[j] = f;
+				break;
+			}
+		}
+		unlock(&onnotelock);
+		return j<NFN;
+		
+	}
+
+	for(i=0; i<onnotesize; i++)
+		if(!onnote[i])
+			break;
+
+	/* there is no free slot */
+	if(i == onnotesize){
+		onnotesize += PPCHUNK;
+		onnote = realloc(onnote, onnotesize*sizeof(uintptr));
+		if(!onnote){
+			unlock(&onnotelock);
+			sysfatal("Malloc of size %d failed: %r", onnotesize*sizeof(uintptr));
+		}
+		memset(onnote+i+1, 0, PPCHUNK-1);
+	}
+
+	onnote[i]=mallocz(sizeof(Onnote), 1);
+	if(!onnote[i]){
+		unlock(&onnotelock);
+		sysfatal("Malloc of size %d failed: %r", sizeof(Onnote));
+	}
+	onnote[i]->pid = _threadgetproc()->pid;
+	onnote[i]->fn[0] = f;
+	unlock(&onnotelock);
+	return 1;
+}
+
+void
+threadcancelnotes(int pid)
+{
+	int i;
+
+	lock(&onnotelock);
+	for(i=0; i<onnotesize; i++)
+		if(onnote[i] && onnote[i]->pid==pid){
+			free(onnote[i]);
+			onnote[i] = nil;
 			break;
 		}
 	unlock(&onnotelock);
-	return i<NFN;
+	return;
 }
 
 static void
 delayednotes(Proc *p, void *v)
 {
-	int i;
+	int i, j, all;
 	Note *n;
-	char s[ERRMAX];
-	int (*fn)(void*, char*);
+	int (*f)(void*, char*);
 
 	if(!p->pending)
 		return;
 
 	p->pending = 0;
+	all = j = 0;
 	for(n=notes; n<enotes; n++){
 		if(n->proc == p){
-			strcpy(s, n->s);
-			n->proc = nil;
-			unlock(&n->inuse);
-
-			for(i=0; i<NFN; i++){
-				if(onnotepid[i]!=p->pid || (fn = onnote[i])==nil)
-					continue;
-				if((*fn)(v, s))
-					break;
+			for(i=0; i<NFN; i++)
+				if(f=onnoteall[i])
+					if((*f)(v, n->s)){
+						all = 1;
+						break;
+					}
+			if(!all){
+				for(i=0; i<onnotesize; i++)
+					if(onnote[i] && onnote[i]->pid==p->pid){
+						for(j=0; j<NFN; j++)
+							if(f=onnote[i]->fn[j])
+								if((*f)(v, n->s))
+									break;
+						break;
+					}
 			}
-			if(i==NFN){
-				_threaddebug(DBGNOTE, "Unhandled note %s, proc %p", n->s, p);
+			if(!all && (i==onnotesize || j==NFN)){
+				_threaddebug(DBGNOTE, "Unhandled note %s, proc %p\n", n->s, p);
 				if(v != nil)
 					noted(NDFLT);
 				else if(strncmp(n->s, "sys:", 4)==0)
@@ -79,6 +172,8 @@
 					abort();
 				threadexitsall(n->s);
 			}
+			n->proc = nil;
+			unlock(&n->inuse);
 		}
 	}
 }
@@ -94,7 +189,7 @@
 		noted(NDFLT);
 
 	if(_threadexitsallstatus){
-		_threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'", _threadexitsallstatus);
+		_threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'\n", _threadexitsallstatus);
 		_exits(_threadexitsallstatus);
 	}
 
--- /tmp/sched.c
+++ /sys/src/libthread/sched.c
@@ -157,6 +157,7 @@
 		t = runthread(p);
 		if(t == nil){
 			_threaddebug(DBGSCHED, "all threads gone; exiting");
+			threadcancelnotes(p->pid);
 			unlinkproc(p);
 			_schedexit(p);	/* frees proc */
 		}
--- /tmp/thread.h
+++ /sys/include/thread.h
@@ -97,6 +97,7 @@
 void	threadkillgrp(int);	/* kill threads in group */
 void	threadmain(int argc, char *argv[]);
 int	threadnotify(int (*f)(void*, char*), int in);
+void threadcancelnotes(int pid);
 int	threadid(void);
 int	threadpid(int);
 int	threadsetgrp(int);		/* set thread group, return old */
--- /tmp/threadimpl.h
+++ /sys/src/libthread/threadimpl.h
@@ -192,3 +192,15 @@
 #define	_threaddebug(flag, ...)	if((_threaddebuglevel&(flag))==0){}else _threadprint(__VA_ARGS__)
 
 #define ioproc_arg(io, type)	(va_arg((io)->arg, type))
+
+#define	PPCHUNK 100
+#define	NFN 33
+typedef struct Onnote Onnote;
+struct Onnote
+{
+	int pid;
+	int (*fn[NFN])(void*, char*);
+};
+extern Onnote **onnote;
+extern int onnotesize;
+void _threadnote(void*, char*);

  reply	other threads:[~2022-06-28 15:28 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-17  9:37 andrey100100100
2022-06-17 13:46 ` Thaddeus Woskowiak
2022-06-17 14:11   ` Jacob Moody
2022-06-17 14:39     ` Thaddeus Woskowiak
2022-06-17 15:06     ` andrey100100100
2022-06-17 16:08       ` Skip Tavakkolian
2022-06-17 16:11         ` Skip Tavakkolian
2022-06-17 16:16           ` Skip Tavakkolian
2022-06-17 17:42             ` adr
2022-06-17 16:11       ` Jacob Moody
2022-06-17 18:48         ` andrey100100100
2022-06-17 19:28           ` Jacob Moody
2022-06-17 21:15           ` adr
2022-06-18  6:40             ` andrey100100100
2022-06-18  8:37               ` adr
2022-06-18  9:22                 ` adr
2022-06-18 12:53                   ` Jacob Moody
2022-06-18 22:03                     ` andrey100100100
2022-06-19  5:54                     ` adr
2022-06-19  6:13                       ` Jacob Moody
2022-06-18 22:22                   ` andrey100100100
2022-06-18 16:57                 ` andrey100100100
2022-06-19  2:40                   ` adr
2022-06-19  5:01                     ` adr
2022-06-19  8:52                       ` andrey100100100
2022-06-19 10:32                         ` adr
2022-06-19 11:40                           ` andrey100100100
2022-06-19 12:01                             ` andrey100100100
2022-06-19 15:10                           ` andrey100100100
2022-06-19 16:41                             ` adr
2022-06-19 21:22                               ` andrey100100100
2022-06-19 21:26                                 ` andrey100100100
2022-06-20  4:41                                 ` adr
2022-06-20  5:39                                   ` andrey100100100
2022-06-20  5:59                                   ` adr
2022-06-20 15:56                                     ` andrey100100100
2022-06-20 22:29                                       ` Skip Tavakkolian
2022-06-21  7:07                                         ` andrey100100100
2022-06-21 11:26                                           ` adr
2022-06-21 13:03                                             ` andrey100100100
2022-06-21 13:22                                               ` adr
2022-06-28 15:28                                                 ` adr [this message]
2022-06-28 16:43                                                   ` ori
2022-06-28 18:19                                                   ` adr
2022-06-28 18:28                                                     ` adr
2022-06-28 19:09                                                   ` andrey100100100
2022-06-28 19:42                                                     ` adr
2022-06-29 13:14                                                       ` adr
2022-06-21 13:47                                             ` andrey100100100
2022-06-21  7:22                                         ` adr

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87cff69b-4b82-8466-a34f-13c7eda24fc9@SDF.ORG \
    --to=adr@sdf.org \
    --cc=9fans@9fans.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).