В Вт, 28/06/2022 в 15:28 +0000, adr пишет:
> 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*);
> ------------------------------------------

Thanks for the patch.


Regards,
Andrej

------------------------------------------
9fans: 9fans
Permalink: 
https://9fans.topicbox.com/groups/9fans/Tfa6823048ad90a21-Mb89a47f334b083f180f89f9a
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

Reply via email to