'waitpid' query

M

Mike

Hi everyone

i am learning advanced C in my spare time, just getting on to the chapter
about child processes. i am really confused about this question!


#include<signal.h>
#include<errno.h>

void handle_sigchld(signo)
int signo;
{
printf("got chld\n");
}

void main(argc, argv)
int argc; char *argv[];
{
struct sigaction myaction;
void bzero();

bzero(&myaction, sizeof myaction);
myaction.sa_handler = handle_sigchld;
sigaction(SIGCHLD, &myaction, 0);
if (!fork()) {
sleep(30);
_exit(0);
}

errno = 0;
waitpid(-1, 0, 0);
switch (errno) {
case 0:
break;

case 3407: /* EINTR */
printf("intr\n");
exit(0);

default:
exit(0);
}
}

when the parent process blocked in 'waitpid',I send it the 'SIGCHLD'
signal by 'kill -s SIGCHLD parentpid', the 'waitpid' returns and sets
'error' to 'EINTR',

when child terminates, the child will also send the parent 'SIGCHLD'
signal, but why doesn't 'waitpid' set errno to 'EINTR'?

thanks in advance!
 
K

Keith Thompson

Mike said:
i am learning advanced C in my spare time, just getting on to the chapter
about child processes. i am really confused about this question!

Your question about waitpid will get better answers in
comp.unix.programmer. The waitpid function isn't part of standard C;
it's specific to Unix/POSIX. (This newsgroup is currently infested by
trolls who claim to object to the idea of topicality; some of them
have been known to post deliberately false information.)

You have other questions about standard C that you *should* be asking;
I'll answer those.
#include<signal.h>
#include<errno.h>

void handle_sigchld(signo)
int signo;

This is an old-style function declaration/definition. It's legal, but
the language has supported new-style declarations (prototypes) since
1989; they provide substantial advantages and essentially no
disadvantages. In particular, they allow the compiler to check that
you're passing arguments of the correct type.

Change the above two lines to:

void handle_sigchld(int signo)
{
printf("got chld\n");
}

void main(argc, argv)
int argc; char *argv[];

Another old-style definition. Also, main returns int, *not* void.

Change the above two lines to:

int main(int argc, char *argv[])

Or, since you're not using argc and argv, you can write it as:

int main(void)

(The standard specifically allows this variation. It doesn't
explicitly allow "void main". Your compiler might allow "void main",
but there's simply no good reason to use it.)
{
struct sigaction myaction;
void bzero();

If you want to use a library function, you should have a #include for
the header that declares it. Declaring (not defining) a function
inside another function is permitted, but it's almost never a good
idea. The documentation for bzero should tell you which header you
need to #include.

But, as it happens, bzero is non-standard and obsolete; memset is a
better and more portable replacement. So you can just delete the
declaration for bzero ...
bzero(&myaction, sizeof myaction);

and change this to:

memset(&myaction, 0, sizeof myaction);

*and* you need to add "#include <string.h>" to make the declaration of
memset visible.

This all assumes that setting myaction to all-bits-zero is a sensible
thing to do. I don't know whether it is or not; the folks in
comp.unix.programmer can help you with that.
myaction.sa_handler = handle_sigchld;
sigaction(SIGCHLD, &myaction, 0);
if (!fork()) {
sleep(30);
_exit(0);

Why are you using _exit rather than the standard exit? I'm not saying
you shouldn't, nor am I asking you post an answer here, but you should
think about it; if you're still not sure, ask in comp.unix.programmer.
}

errno = 0;
waitpid(-1, 0, 0);
switch (errno) {

Functions that set errno on error typically have some other way of
indicating that an error actually occurred; if an error *didn't*
occur, the value of errno could be meaningless. waitpid returns a
value; you're ignoring it.
case 0:
break;

case 3407: /* EINTR */

What is 3407? Are you assuming that EINTR == 3407? If so, why not
just write "case EINTR:" (which will require a #include for whatever
printf("intr\n");
exit(0);

default:
exit(0);
}
}

when the parent process blocked in 'waitpid',I send it the 'SIGCHLD'
signal by 'kill -s SIGCHLD parentpid', the 'waitpid' returns and sets
'error' to 'EINTR',

when child terminates, the child will also send the parent 'SIGCHLD'
signal, but why doesn't 'waitpid' set errno to 'EINTR'?

It probably does, but you're not checking for it properly.

Feel free to follow up here if you have questions about the pure C
parts of your program, or post to comp.unix.programmer for questions
about waitpid et al.
 
I

Ian Collins

Mike said:
Hi everyone

i am learning advanced C in my spare time, just getting on to the chapter
about child processes. i am really confused about this question!
Looks more like Unix programming, try comp.unix.programmer.
 
A

Antoninus Twink

(This newsgroup is currently infested by trolls who claim to object to
the idea of topicality; some of them have been known to post
deliberately false information.)

Come on Keith, I know we have a disagreement about the finer points of
"topicality", but leave the blatant lies to Heathfield will you?
 
A

Antoninus Twink

when the parent process blocked in 'waitpid',I send it the 'SIGCHLD'
signal by 'kill -s SIGCHLD parentpid', the 'waitpid' returns and sets
'error' to 'EINTR',

when child terminates, the child will also send the parent 'SIGCHLD'
signal, but why doesn't 'waitpid' set errno to 'EINTR'?

Because in that case no error has occurred!

As Keith Tompson explained (unusually for him - normally he refuses to
provide any "off topic" answers), what you need to do is check the
return value from waitpid()... actually, you can just use wait(), which
has a slightly simpler interface.

You also need to include some relevant headers, etc. Here is a
cleaned-up version of your code: shout if you have any further
questions.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void handle_sigchld(int signo)
{
puts("got chld");
}

int main(void)
{
struct sigaction myaction;
int status;

memset(&myaction, 0, sizeof myaction);
myaction.sa_handler = handle_sigchld;
if(sigaction(SIGCHLD, &myaction, 0) == -1) {
perror("sigaction");
exit(1);
}
switch(fork()) {
case 0:
sleep(20);
exit(0);

case -1:
perror("fork");
exit(1);
}

if(wait(&status) == -1)
perror("wait");
return 0;
}
 
A

Antoninus Twink

Why are you using _exit rather than the standard exit?

_exit is specified by the POSIX standard. There's also _Exit, which is
exactly the same but specified by C99. Why not mention the existence of
_Exit, if you feel you have to make the point, instead of trying to
pretend there's something "non-standard" going on?

Anyway, in this case, there is no good reason to prefer _exit() to
exit(), but in general it's good practise to consider using exit() only
in the parent process, and have child processes call _exit().

This avoids doing the things that exit() does more than once, which is
usually not what you want: for example, exit() flushes all output
streams, so if you are appending to an open file then calling exit()
twice could cause any buffered data to be written to the file twice.

There's also atexit() handlers, tmpfile()s, etc.
 
K

Kaz Kylheku

Hi everyone

i am learning advanced C in my spare time, just getting on to the chapter

I.e. you're learning C as a side effect of exploring Unix systems programming.
about child processes. i am really confused about this question!


#include<signal.h>
#include<errno.h>

void handle_sigchld(signo)
int signo;
{
printf("got chld\n");

The printf function is not for safe for calling from signal handlers.

Of course, not in ANSI C, but not in Unix C either.

It's not on the list of ``async safe'' functions.

}

void main(argc, argv)
int argc; char *argv[];

This is a style of C that has been obsolete for twenty years.
{
struct sigaction myaction;
void bzero();

bzero(&myaction, sizeof myaction);

You might want to use ANSI C functions wherever possible, even in Unix-specific
code. The ANSI C function for setting memory is called memset, defined in
the header #include <string.h>, and used like this:

memset(&myaction, 0, sizeof myaction);

But, you don't have to call a fucntion to intialize a local variable in C.
There is syntax for doing that! So the memset is superfluous. Just add an
initializer to the variable's definition. Since it's a struct, we use a
brace-enclosed initializer. We specify a zero for the first member of the
structure; the rest are implicitly zero.

struct sigaction myaction = { 0 };

Another trick is to keep around a static instance of the structure which
is implicitly initialized to zero:

static struct sigaction all_zero_sigaction;

struct sigaction myaction = all_zero_sigaction;
when child terminates, the child will also send the parent 'SIGCHLD'
signal, but why doesn't 'waitpid' set errno to 'EINTR'?

Because that's the behavior of waitpid in your operating system's kernel. That
has nothing to do with C; the function could have been designed to work in any
way whatsoever.

Think about what is going on. Your signal handler does not collect the
child process, so the dead child remains pending.

It would not make sense for waitpid to return -1 and set errno to EINTR if
there is a non-empty list of child processes to be collected!
 
K

Kenny McCormack

Keith Thompson said:
waitpid returns a value; you're ignoring it.

Oopsie!!! You can't possibly make that statement, because you have no
idea what "waitpid" is. That is the dogma. I'm just reporting it.
 
Y

Yevgen Muntyan

Your question about waitpid will get better answers in
comp.unix.programmer.  The waitpid function isn't part of standard C;
it's specific to Unix/POSIX.  (This newsgroup is currently infested by
trolls

Those bitches, huh!
who claim to object to the idea of topicality;

[1] <-- footnote
some of them have been known to post deliberately
false information.)

You, on the other hand, have been known to be a source
of infinite wisdom, whether anybody cares or not.
You have other questions about standard C that you *should* be asking;
I'll answer those.

Yay, void main! Go Keith, teach him!

[1] A footnote like it's a book or something:
"object to the idea of topicality" - you don't see
how moronic is this, do you? comp.lang.c'ese is a fine
new language, spoken by the C experts.
 
Y

Yevgen Muntyan

I see that Keith is still giving his "trolls" all the attention they
could possibly want and feeding their presence. I'm starting to feel
sorry for the man. Nobody can be *that* dense. It's basic human
nature -- unless it happens within the first few days, nobody ever
leaves a place where he's continually insulted. There's too much
pride involved. I remember one mod of an automotive Web forum who
finally managed to deal with a troll problem by banning people like
Keith and Chuck. The trolls, continual account hoppers, got bored
within a couple of weeks and left for good.

PLONK

Yours,
Chuck B. F.
 
K

Kenny McCormack

Han from China - Master Troll said:
I see that Keith is still giving his "trolls" all the attention they
could possibly want and feeding their presence. I'm starting to feel
sorry for the man. Nobody can be *that* dense.

I have *always* felt sorry for him (and the rest). The really funny thing
is to imagine actually meeting these people in real life. The mental
picture I have of that is *not* pretty.

I honestly think the diagnosis of some autism-like disorder is entirely
on the mark. They are obviously not stupid, but equally obviously,
there is something seriously damaged about them.

But note that feeling sorry for them does not preclude my twitting
them... They certainly have it coming.
It's basic human nature -- unless it happens within the first few days,
nobody ever leaves a place where he's continually insulted. There's too
much pride involved.

Very good point. Probably a bit deep for the literal-minded-crowd
around here, but I get your meaning.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top