🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.sys.next.programmer
3 messages
3 total messages Started by avsoftjeff Jeff Roberts Tue, 28 Jul 1992 23:05
signals and the appkit
#302
Author: avsoftjeff Jeff Roberts
Date: Tue, 28 Jul 1992 23:05
32 lines
1935 bytes
We've been having a bit of difficulty with the interaction of the UNIX  
signal facilities and appkit based applications.  Any help would be  
greatly apprecatiated.

We are using sigvec to set a handler to catch SIGCHLD. (wait?(2) is no  
good as this application has other tasks to perform.)  Since the handler's  
stack is finite, we want to post an event to notify the application and  
that there is work to be done and get off the stack.  The handler is  
getting called ok but we can't seem to find a way to let the application  
know that it should re-run the event loop.  timer events, delayed  
performs, etc do nothing. If you take on too ambitious a task in the  
signal handler itself, like sending appkit objects messages, the  
application seems to get hung in the event loop and we get an infinite  
wait cursor.(This condition applies to sending the activateSelf: message  
to NXApp)  I'm not sure why.  My guess would be that we've over ran the  
signal handler stack frame???

Other facts:
1. By design, at the time the signal handler is called, this application  
has no screen realestate;  no icon miniwindow, no nothing.  All windows  
have been ordered out.

2. any events we post in the handler appear to be getting queued up.  if  
we leave a window exposed and mouse down on that window we get a flood of  
all of the queued up timer events, etc.

This sounds strange, and believe me it is.  I'm a pretty familiar with  
UNIX systems in general but i must admit i'm left without a clue on this.   
Any ideas?

J Roberts
jeff@oceania.com
Re: signals and the appkit
#470
Author: Josh Doenias
Date: Mon, 03 Aug 1992 20:40
59 lines
2443 bytes
In article <Bs4G4M.19M@oceania.com>  writes:

>We are using sigvec to set a handler to catch SIGCHLD. (wait?(2) is no  
>good as this application has other tasks to perform.)  Since the  
handler's  
>stack is finite, we want to post an event to notify the application and  
>that there is work to be done and get off the stack.  

First of all, I would recommend avoiding signals and signal handling in an  
application at all costs.  Besides the inherent problems of protecting  
yourself against unwanted signals at the appropriate times, they are also  
really bad news if your program ever becomes multi-threaded.  You have no  
guarantee as to which thread will receive the signal, and things can get  
ugly.

In your case, where you're interested in child processes completing, I  
would recommend the following solution.

1.  Create a DPSTimedEntry function that gets called at some regular  
interval (using DPSAddTimedEntry)
2.  In that function, use the wait3() system call.  You said that wait()  
is no good, since it is blocking, but wait3() can be passed parameters  
making it non-blocking.
3.  If the wait3() call tells you a process has finished, send a message  
to whoever cares.  You can queue the messages up or handle them  
immediately.

Something like the following:

  void myHandlerFunction(DPSTimedEntry tenum, double now, MyObject *self)
  {
    union wait status;
    int pid = wait3(&status,WNOHANG,NULL);
    
    if (pid > 0) [self processFinished:pid withStatus:&status];
  }

  @interface MyObject
  
  #define CHILD_CHECKING_PERIOD 2.0    /* Check every two seconds */

  - init
  {
   [super init];
   childhandler = DPSAddTimedEntry(CHILD_CHECKING_PERIOD, 
			(DPSTimedEntryProc)myHandlerFunction,
			(void *)self, NX_BASETHRESHOLD);
  }

  - processFinished:(int)pid withStatus:(union wait *)status
  {
  /* do something interesting here */
  }

..

Hope this helps.  Again, I would recommend against using signals.

-- josh
Re: signals and the appkit
#475
Author: Chris Lloyd
Date: Thu, 06 Aug 1992 23:09
97 lines
3873 bytes
In article <4536@rosie.NeXT.COM> jdoenias@next.com (Josh Doenias) writes:
>In article <Bs4G4M.19M@oceania.com>  writes:
>>We are using sigvec to set a handler to catch SIGCHLD. (wait?(2) is no  
>>good as this application has other tasks to perform.)  Since the handler's  
>>stack is finite, we want to post an event to notify the application and  
>>that there is work to be done and get off the stack.  
>
[ recommendation about avoiding signals and signal handling deleted ]

Agreed.

>In your case, where you're interested in child processes completing, I  
>would recommend the following solution.
>
>1.  Create a DPSTimedEntry function that gets called at some regular  
>interval (using DPSAddTimedEntry)
>2.  In that function, use the wait3() system call.  You said that wait()  
>is no good, since it is blocking, but wait3() can be passed parameters  
>making it non-blocking.
>3.  If the wait3() call tells you a process has finished, send a message  
>to whoever cares.  You can queue the messages up or handle them  
>immediately.

ACK! Polling is Evil with a capital E.

- Give the app's task a notify port.
- setup a handler for the notify port.
- each time you fork a child, request the child's task port, this
    gives you rights to the childs task and you will get a message on
    the task notify port about the death of this port.

death_handler(msg_header_t *msg,id self)
{
/* Stolen from Josh's example .. */
    union wait status;
    int pid = wait3(&status,WNOHANG,NULL);
    
    if (pid > 0) [self processFinished:pid withStatus:&status];
}

For the curious at heart, *msg is:
struct {
  msg_header_t header;
  msg_type_t   type;
  port_t       port;
} *msg;

and port will be the port that was destroyed (in this case, the child's task
port)

Then in the object that starts up the children:

-init
{
   port_t notify;
   kern_return_t r;

   if(r=port_allocate(task_self(),&notify))
    mach_error("port_allocate",r);

   if(r=task_set_notify_port(task_self(),notify))
    mach_error("task_set_notify_port");

   DPSAddPort(notify,death_handler,MSG_SIZE_MAX,self,NX_MODALRESPTHRESHOLD);
}

Then for the trick:

A task is a port, in order to be notified of a ports death, you need to
have rights to it, since a parent process doesnt have rights to the
childs task by default (neh?), you need to do the following right after 
your fork() in order to get the rights, so that a message is sent to you
when the task , er port, right? is destroyed...

  task_t child;

  if((pid=fork())==0)
   { /* do childish things */ }

  task_by_unix_pid(task_self(),pid,&child);

dat's it.

One thing to notice here is that there is this really nasty window
between the time the fork() happens and the time you get the task port of
the child in which the child can die and you dont have rights and you
never get a notification message and the handler is never called.  If this
is a concern, the thing to do would be to fire a bogus message down your
own notify port right after the task_by_unix_pid() so that the handler
is called and the wait status is checked and in effect eliminating the window.

It would be handy to have a fork() variant which returned a task_t for
the child...

la la la,
-- 
:: Christopher Lloyd :: a74k110@titan.ucc.umass.edu :: Yrrid, Inc. ::
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads