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
Author: avsoftjeff Jeff Roberts
Date: Tue, 28 Jul 1992 23:05
Date: Tue, 28 Jul 1992 23:05
32 lines
1935 bytes
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
Author: Josh Doenias
Date: Mon, 03 Aug 1992 20:40
Date: Mon, 03 Aug 1992 20:40
59 lines
2443 bytes
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
Author: Chris Lloyd
Date: Thu, 06 Aug 1992 23:09
Date: Thu, 06 Aug 1992 23:09
97 lines
3873 bytes
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(),¬ify))
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