One thing that might be relavent is it is currently single processed, but I
intend to modify it to maintain a pool of processes to handle connections
with one process as the controlling process.
--
Daniel Barron - use [at jadeb.com] for personal replys.
You might wish to be able to log a message whenever the daemon is killed.
Also, there might be cleanup to do when the process gets killed
(temporary files, PID file, ...).
--
Wolf a.k.a. Juha Laiho Espoo, Finland
(GC 3.0) GIT d- s+: a C++ UH++++ UL++++$ P++@ L+++ E(-) W+$@ N++ !K w !O
!M V PS(+) PE Y+ PGP(+) t- 5 !X R !tv b+ !DI D G e+ h--- r+++ y+++
"...cancel my subscription to the resurrection!" (Jim Morrison)
> Daniel Barron <dan...@DeleteMeAndInvalidForNoSpam.jadeb.com.invalid> said:
> >I'm writing a daemon which acts as a sort of proxy. Do I /need/ to handle
> >signals? I don't intend on using HUP for rereading config files and if it
> >gets a kill, I want it to quit. So do I really need signals? And what for?
>
Thanks for the reply.
> You might wish to be able to log a message whenever the daemon is killed.
> Also, there might be cleanup to do when the process gets killed
> (temporary files, PID file, ...).
In my case, there will be no PID files (should there?) and no temporary
files.
I suspect I'll need signalling for handling the child processes when they
die or are killed?
I've got a multitude of linux programming books. Most to do with sockets,
tcp/ip and c++, only one specific app development one. This book is not
very good at describing reasons for signals, nor offers example code and
is a bit thin on the ground on signals in general. Does anyone have a good
url for this subject or know a good book?
That's right - SIGCLD or SIGCHLD.
> I've got a multitude of linux programming books. Most to do with sockets,
> tcp/ip and c++, only one specific app development one. This book is not
> very good at describing reasons for signals, nor offers example code and
> is a bit thin on the ground on signals in general. Does anyone have a good
> url for this subject or know a good book?
The one true "bible" I'd recommend is Advanced Programming in the UNIX
Environment by W. Richard Stevens. Yes, it is a huge and quite
expensive book,
but it is still _the best_ (most detailed) book on advanced *nix
subjects (such as signals). His other books are also well recommended.
I've read the reviews and most people are very pleased with the book.
However it seems a bit dated - 9 years old! Has the way unix-like oses
work not changed much in that length of time? Will it be correct for
programming in linux which is quite a modern unix clone?
>I suspect I'll need signalling for handling the child processes when they
>die or are killed?
If you are going to have children, you should reap them. Using a
signal handler is one way to do that.
First, it's only 8 years old - my copy says copyright is from 1993 ;-)
And, yes, even it may seem a bit old basically everything is still valid.
So it's really worth its money, I very much prefer to have it near at
hand when programming.
Regards, Jens
--
_ _____ _____
| ||_ _||_ _| Jens.T...@physik.fu-berlin.de
_ | | | | | | AG Moebius, Institut fuer Molekuelphysik
| |_| | | | | | Fachbereich Physik, Freie Universitaet Berlin
\___/ens|_|homs|_|oerring Tel: ++49 (0)30 838 - 53394 / FAX: - 56046
Well one is on order at amazon now :)
PID files are one handy way for interfacing with the shell world, such as
control scripts for daemons; with a daemon, it's rather probable that you'll
sooner or later want to have a control (start/stop) script for that, to
start up the daemon at boot time, and then shut it down when the system
is going down. So, if your daemon is of the sort that's started once and
keeps on running until stopped, I'd heartily recommend a PID file.
So, at startup the control script should
- check for the existence of the PID file
- if there was no PID file, start the daemon, otherwise continue
- read the PID from the PID file
- check if the PID is active (kill -0 $PID); if not, start the daemon,
if it was, continue
- check with 'ps' whether the process name for the PID is correct;
if not, start the daemon, otherwise finish (the daemon was already
correctly running, and should not be re-executed)
It would be possible to determine the daemon presence just by grepping the
'ps' output, but that poses some problems -- especially at the shutdown
stage: if there's for some reason something else running that matches your
grep pattern, it may be that your control script kill processes it
shouldn't. At system shutdown stage this usually isn't that bad, but if
the control script was used to just bring down the single service for
a reason or another, then killing unrelated processes would be rather
bad.
... and the functionality at shutdown:
- check for the existence of the PID file
- if there was no PID file, finish, otherwise continue
- read the PID from the PID file
- check if the PID is active (kill -0 $PID); if not, finish,
if it was, continue
- check with 'ps' whether the process name for the PID is correct;
if not, stop the daemon, otherwise finish
Some bad examples of control scripts I've seen have managed to
- kill themselves, leaving alive the service-to-be-killed (control
script name contains the service name, and too simple grep pattern
used, and no PID file was used for cross-checking)
- kill unrelated processes due to bad PID files, because of no process
name checking (the actual service was not running, and there was
something running with the PID listed in the PID file)
- not start the service, because process number listed in the PID file
was already used -- but by a non-related process (again, checking the
process name would've told the PID file is stale)
- start multiple compating copies of the daemon because of no cheking
at all
.. what I still have to see would be failing to start the service because
something mathing the grep pattern (the control script itself?) is already
running. Perhaps this would be pathological enough to be found in the
vendor testing. (yes, some of the above cases are from big-money commercial
Unix systems -- and from the base OS components; third-party software can
be even worse)
So, to match the control script, one of the first tasks of the daemon should
be to create the PID file -- and I'd like to see the PID file removed when
the daemon exits. The control script shouldn't depend on this cleanup,
however -- the daemon may have exited f.ex. because of "kill -9" or a system
crash, in which situations it hasn't had the possibility to clean up.
>I suspect I'll need signalling for handling the child processes when they
>die or are killed?
True; you should at least arrange the reaping of dead children. Either by
explicitly writing a signal handler, or by ignoring the SIGCHLD signal
(or SIGCLD -- which one was the correct form nowadays?). By writing
a handler you could gather the exit status from the child processes and
perhaps use that for logging potential problems - provided that you write
the child code so that it provides meaningful exit status.
>I've got a multitude of linux programming books. Most to do with sockets,
>tcp/ip and c++, only one specific app development one. This book is not
>very good at describing reasons for signals, nor offers example code and
>is a bit thin on the ground on signals in general. Does anyone have a good
>url for this subject or know a good book?
Even though old (Old?? Not even a decade! Even the "The Unix Programming
Environment", by Kernighan&Pike, (C) 1984, is still good reading.), the
Stevens book is a good one -- and you seem to already have it in order.
But as you point out, there might be a lack of texts discussing things
like the rationale and reason for PID files - and overall integration
of software with the Unix environment.
So, many things in the Unix environment have stayed very stable for quite
a long time. IMO one of the biggest changes has been the transition from
K&R C syntax to ANSI-C.
Other areas, like network communications -- and some forms of interprocess
communications have also changed - and luckily somewhat converged. But
old things, like signals, still work mostly the same way. There has been
some changes, but mostly to provide more integrity and dependability to
signal delivery and processing.
> Daniel Barron <dan...@DeleteMeAndInvalidForNoSpam.jadeb.com.invalid> said:
> >In message <9h53o1$a57$1...@ichaos.ichaos-int>
> > Juha Laiho <Juha....@iki.fi> wrote:
> >> You might wish to be able to log a message whenever the daemon is killed.
> >> Also, there might be cleanup to do when the process gets killed
> >> (temporary files, PID file, ...).
> >
> >In my case, there will be no PID files (should there?) and no temporary
> >files.
>
> PID files are one handy way for interfacing with the shell world, such as
> control scripts for daemons; with a daemon, it's rather probable that
> you'll sooner or later want to have a control (start/stop) script for that,
> to start up the daemon at boot time, and then shut it down when the system
> is going down. So, if your daemon is of the sort that's started once and
> keeps on running until stopped, I'd heartily recommend a PID file.
OK, I'll use one.
[snip]
> >I suspect I'll need signalling for handling the child processes when they
> >die or are killed?
>
> True; you should at least arrange the reaping of dead children. Either by
> explicitly writing a signal handler, or by ignoring the SIGCHLD signal
> (or SIGCLD -- which one was the correct form nowadays?). By writing
SIGCLD is obsolete. SIGCHLD is to be used. (Just looked it up).
[snip]
> Other areas, like network communications -- and some forms of interprocess
> communications have also changed - and luckily somewhat converged. But
Oh, so how has IPC changed from Stevens to Linux 2.2?
> old things, like signals, still work mostly the same way. There has been
> some changes, but mostly to provide more integrity and dependability to
> signal delivery and processing.
Steves meantions reliable and unreliable signals. It says reliable is newer
and so I would expect linux 2.2 to use reliable. Is this the case and can I
ignore all talk of unreliable signals?
BTW, thanks for the reply.
(thanks; I have the Stevens book myself, but was just plain too lazy to
look that one up)
>> Other areas, like network communications -- and some forms of interprocess
>> communications have also changed - and luckily somewhat converged. But
>
>Oh, so how has IPC changed from Stevens to Linux 2.2?
>
>> old things, like signals, still work mostly the same way. There has been
>> some changes, but mostly to provide more integrity and dependability to
>> signal delivery and processing.
>
>Steves meantions reliable and unreliable signals. It says reliable is newer
>and so I would expect linux 2.2 to use reliable. Is this the case and can I
>ignore all talk of unreliable signals?
Trying to fetch my thoughts from yesterday evening, it looks like I must
have thought about the changes in signal delivery while mentioning the
changed IPC (because signals are just one form of IPC). Overall that
chapter I wrote looks like I have almost contradicted myself -- and I
readily admit that; I was apparently all too tired when writing that one.
As I understand it, if you use signal() calls in Linux, you'll get
unreliable signals, and if you use sigaction() and friends, you'll
get reliable signals. And at least on my Linux system the signal()
manpage appears to recommend using sigaction() instead of signal().
One effect of this is that the program written using sigaction() should
behave more consistently in a wider variety of different Unix systems
than a program written using signal(). This is one example of the
convergence I talked earlier.
So, the change has been not so much between Stevens' book and Linux,
but even before the book. But some differences still live in the
form of old, non-consistent API's, like signal().
What Linux doesn't support any way (again, AFAIK) is queuing up
multiple instances of a single signal. Consider
- program gets a SIGHUP
- at the start of the HUP handler it blocks SIGUSR1
- during the HUP handler, several USR1's are sent to the program
- at the end of the HUP handler the USR1 blocking is removed
- the program gets a notification of SIGUSR1 having been received,
but nothing indicates that it had happened multiple times; the
signal status is just a binary flag, not a counter
Similarly, if several different signals had been blocked (and sent)
in the above case, there would be no indication as to in which order
the actual signals came in -- the kernel will just use some internal
priorization mechanism to select one of the received signals to process
next -- so the distinct signals cen be delivered to the program in a
different order than they were actually sent, if the program has been
blocking several distinct signals at a time.
>BTW, thanks for the reply.
Apologies that it took so long.
I've heard signals are not a good form of IPC and that Unix Sockets are much
better and reliable. This is what I intend to use in a daemon I am writing
which will eventually manage a fork pool. At the moment it forks on
connection, but I've not got signal handling sorted so I can't reap the
zombies. I need to knuckle down with stevens.
[snip]
> As I understand it, if you use signal() calls in Linux, you'll get
> unreliable signals, and if you use sigaction() and friends, you'll
> get reliable signals. And at least on my Linux system the signal()
> manpage appears to recommend using sigaction() instead of signal().
OK, sigaction() it is then.
[snip]
> What Linux doesn't support any way (again, AFAIK) is queuing up
> multiple instances of a single signal. Consider
> - program gets a SIGHUP
> - at the start of the HUP handler it blocks SIGUSR1
> - during the HUP handler, several USR1's are sent to the program
> - at the end of the HUP handler the USR1 blocking is removed
> - the program gets a notification of SIGUSR1 having been received,
> but nothing indicates that it had happened multiple times; the
> signal status is just a binary flag, not a counter
Or along the same lines:
- gets a SIGCHLD
- blocks SIGCHLD
- is about to increment a zombie int count
- but 2 more SIGCHLD arrive
- count is incremented
- unblocks SIGCHLD
- runs sig handler again, but final count is 2, not 3
This would happen a lot more on a multi processor computer, but could,
intheory happen on a /very/ heavily loaded cpu.
>
> Similarly, if several different signals had been blocked (and sent)
> in the above case, there would be no indication as to in which order
> the actual signals came in -- the kernel will just use some internal
> priorization mechanism to select one of the received signals to process
> next -- so the distinct signals cen be delivered to the program in a
> different order than they were actually sent, if the program has been
> blocking several distinct signals at a time.
It is odd linux has no signal queueing. It seems quite backward to me. The
multithreading is also messy and in its infancy IMHO. This is why I dropped
the idea of a threadpool daemon and opted for fork pool. Context changes on
linux is quite efficient anyway.
>
> >BTW, thanks for the reply.
>
> Apologies that it took so long.
You often don't get support from commercial companies at the weekend! Thanks
for your free help.
>In message <9hmtgl$nk1$1...@ichaos.ichaos-int>
> Juha Laiho <Juha....@iki.fi> wrote:
>[snip]
>
>[snip]
>> As I understand it, if you use signal() calls in Linux, you'll get
>> unreliable signals, and if you use sigaction() and friends, you'll
>> get reliable signals. And at least on my Linux system the signal()
>> manpage appears to recommend using sigaction() instead of signal().
>
>OK, sigaction() it is then.
>
With the introduction of glibc2 the signal has been changed to become
very BSD like, that is:
- The handler remains installed
- The signal is blocked until the handler returns
- Some system calls are automatic restarted, rather then returning
an EINTR error.
Check the info page for libc; the man page has not been updated on
this point last time I looked.
>
>Or along the same lines:
>- gets a SIGCHLD
>- blocks SIGCHLD
>- is about to increment a zombie int count
>- but 2 more SIGCHLD arrive
>- count is incremented
>- unblocks SIGCHLD
>- runs sig handler again, but final count is 2, not 3
>
>This would happen a lot more on a multi processor computer, but could,
>intheory happen on a /very/ heavily loaded cpu.
>
That is why a SIGCHLD handler should normaly loop on a non-blocking
wait() until that wait() returns an error.
If you make a test program which blocks SIGCHLD while the forked
children terminates, you can easily see that only one signal will be
delivered once it is unblocked.
Villy
Sorry for being a Linux developer newbie, but when did this introduction
occur, and why? What was before, and why?
> very BSD like, that is:
Perhaps I should have favoured xBSD rather than Linux ;) (It's a joke members
of the holy church of linux!)
[snip]
> - Some system calls are automatic restarted, rather then returning
> an EINTR error.
Should this automatic restarting be assumed? I am sure recently I read that
handling EINTR is not going to hurt, even if it never occurs.
[snip]
>
> That is why a SIGCHLD handler should normaly loop on a non-blocking
> wait() until that wait() returns an error.
Wow, thanks! I was wondering what the best algorithm for dealing with that
would be. You just saved my some research. Thanks.
I'd think so.. and you can pass a larger variety of information through
sockets. But there are some cases where the choice is not yours; like
getting a SIGCHLD when a child dies. This is IPC, as well, and you can't
choose to implement it otherwise, so you'll have to do something to signals.
Also, it's good sense to do at least some cleanup (if any is needed) upon
receipt of SIGTERM. This is typically sent to the process in attempt
to stop it cleanly. F.ex. during system shutdown, if the rc script
failed to stop a process -- or there was no "stop" code for some process
in the rc script, it'll first be sent SIGTERM, then a moment later
a SIGKILL if it still hangs around.
Other than those two, I don't think it's necessary to write handlers.
Btw, Stevens' book also has good list of things to do when
daemonizing a process (pp. 417-418 in my copy).
>It is odd linux has no signal queueing.
Actually, which Unixes _do_ have signal queuing? I'd think it's an
exception rather than a rule.
>The multithreading is also messy and in its infancy IMHO.
I don't have the experience to comment on that -- but as I understand
it, the thread system will be redone at some phase of 2.5, so it appears
you're not alone with that opinion.
>Context changes on linux is quite efficient anyway.
Yep.
Just checked. It is in mine. Thanks for pointing it out.
[snip]
If you include <signal.h>, signal() gives you unreliable signals.
However, if you instead include <bsd/signal.h>, you get reliable
signals.
That is no longer the case. That was true when linking with libc5;
glibc2 will default to BSD style signal semantics, that is, reliable
signals and automatic restart of most system calls.
Villy