Unix Programming Frequently Asked Questions - Part I

Unix Programming Frequently Asked Questions

http://www.steve.org.uk/Reference/Unix/faq_toc.html

About this FAQ

$Id: rawfaq.texi,v 1.37 2000/09/01 06:34:57 andrew Exp $

This FAQ was originally begun by Patrick Horgan in May 1996; I took itover after it had been lying idle for several months. I've reorganisedit a bit and added some stuff; I still regard it as `under development'. Comments, suggestions, additions, corrections etc. should be sent to the maintainer at: <andrew@erlenstar.demon.co.uk>.

A hypertext version of this document is available on the WWW. The home site is located at http://www.erlenstar.demon.co.uk/unix/faq_toc.html. A US mirror site is available athttp://www.whitefang.com/unix/faq_toc.html.

This document is available by FTP from the news.answers archives atrtfm.mit.edu and its many mirror sites worldwide. The official archivename is `unix-faq/programmer/faq'. Sites which also archive *.answers posts by group should also carry the file under the`comp.unix.programmer' directory.

Other sources of information are not listed here. You can find pointersto other FAQs, books, source code etc. in the regular [READ ME FIRST]posting that should appear weekly in comp.unix.programmer. Administriviaregarding newsgroup conduct, etc., are also found there; I want toreserve this document specifically for technical Q's and A's. All contributions have been edited by the maintainer, therefore anyerrors or omissions are my responsibility rather than that of thecontributor.

This FAQ is now maintained as Texinfo source; I'm generating a raw textversion for Usenet using the makeinfo program, and an HTML versionusing texi2html.

Copyright © 1997, 1998, 1999, 2000 Andrew Gierth. Thisdocument may be distributed freely on Usenet or by email; it may bearchived on FTP or WWW sites that mirror the news.answers archives,provided that all reasonable efforts are made to ensure that the archiveis kept up-to-date. (This permission may be withdrawn on an individualbasis.) It may not be published in any other form, whether in print, onthe WWW, on CD-ROM, or in any other medium, without the expresspermission of the maintainer.

List of contributors in no particular order:

Andrew Gierth<andrew@erlenstar.demon.co.uk>
Patrick J. Horganwithheld
Stephen Baynes<stephen.baynes@soton.sc.philips.com>
James Raynardwithheld
Michael F. Quigleywithheld
Ken Pizziniwithheld
Thamer Al-Herbishwithheld
Nick Kew<nick.kew@pobox.com>
Dan Abarbanelwithheld
Billy Chambless<billy@cast.msstate.edu>
Walter Briscoe<walter@wbriscoe.demon.co.uk>
Jim Buchanan<jbuchana@buchanan1.net>
Dave Plonka<plonka@doit.wisc.edu>
Daniel Stenbergwithheld
Ralph Corderoy<ralph@inputplus.demon.co.uk>
Stuart Kempwithheld
Sergei Chernev<ser@nsu.ru>
Bjorn Reesewithheld
Joe Halpin<jhalpin@nortel.ca>
Aaron Crane<aaronc@pobox.com>
Geoff Clare<gwc@root.co.uk>


1. Process Control

1.1 Creating new processes: fork()

1.1.1 What does fork() do?

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

pid_t fork(void);

The fork() function is used to create a new process from anexisting process. The new process is called the child process, and theexisting process is called the parent. You can tell which is which bychecking the return value from fork(). The parent gets thechild's pid returned to him, but the child gets 0 returned to him. Thusthis simple code illustrate's the basics of it.

pid_t pid;

switch (pid = fork())
{
case -1:
    /* Here pid is -1, the fork failed */
    /* Some possible reasons are that you're */
    /* out of process slots or virtual memory */
    perror("The fork failed!");
    break;

case 0:
    /* pid of zero is the child */
    /* Here we're the child...what should we do? */
    /* ... */
    /* but after doing it, we should do something like: */
    _exit(0);

default:
    /* pid greater than zero is parent getting the child's pid */
    printf("Child's pid is %d\n",pid);
}

Of course, one can use if()... else... instead ofswitch(), but the above form is a useful idiom.

Of help when doing this is knowing just what is and is not inherited bythe child. This list can vary depending on Unix implementation, so takeit with a grain of salt. Note that the child gets copies of thesethings, not the real thing.

Inherited by the child from the parent:

  • process credentials (real/effective/saved UIDs and GIDs)
  • environment
  • stack
  • memory
  • open file descriptors (note that the underlying file positions areshared between the parent and child, which can be confusing)
  • close-on-exec flags
  • signal handling settings
  • nice value
  • scheduler class
  • process group ID
  • session ID
  • current working directory
  • root directory
  • file mode creation mask (umask)
  • resource limits
  • controlling terminal

Unique to the child:

  • process ID
  • different parent process ID
  • Own copy of file descriptors and directory streams.
  • process, text, data and other memory locks are NOT inherited.
  • process times, in the tms struct
  • resource utilizations are set to 0
  • pending signals initialized to the empty set
  • timers created by timer_create not inherited
  • asynchronous input or output operations not inherited

1.1.2 What's the difference between fork() and vfork()?

Some systems have a system call vfork(), which was originallydesigned as a lower-overhead version of fork(). Sincefork() involved copying the entire address space of the process,and was therefore quite expensive, the vfork() function wasintroduced (in 3.0BSD).

However, since vfork() was introduced, theimplementation of fork() has improved drastically, most notablywith the introduction of `copy-on-write', where the copying of theprocess address space is transparently faked by allowing both processesto refer to the same physical memory until either of them modifyit. This largely removes the justification for vfork(); indeed, alarge proportion of systems now lack the original functionality ofvfork() completely. For compatibility, though, there may still bea vfork() call present, that simply calls fork() withoutattempting to emulate all of the vfork() semantics.

As a result, it is very unwise to actually make use of any of thedifferences between fork() and vfork(). Indeed, it isprobably unwise to use vfork() at all, unless you know exactlywhy you want to.

The basic difference between the two is that when a new process iscreated with vfork(), the parent process is temporarilysuspended, and the child process might borrow the parent's addressspace. This strange state of affairs continues until the child processeither exits, or calls execve(), at which point the parentprocess continues.

This means that the child process of a vfork() must be careful toavoid unexpectedly modifying variables of the parent process. Inparticular, the child process must not return from the functioncontaining the vfork() call, and it must not callexit() (if it needs to exit, it should use _exit();actually, this is also true for the child of a normal fork()).

1.1.3 Why use _exit rather than exit in the child branch of a fork?

There are a few differences between exit() and _exit()that become significant when fork(), and especiallyvfork(), is used.

The basic difference between exit() and _exit() is thatthe former performs clean-up related to user-mode constructs in thelibrary, and calls user-supplied cleanup functions, whereas the latterperforms only the kernel cleanup for the process.

In the child branch of a fork(), it is normally incorrect to useexit(), because that can lead to stdio buffers being flushedtwice, and temporary files being unexpectedly removed. In C++ code thesituation is worse, because destructors for static objects may be runincorrectly. (There are some unusual cases, like daemons, where theparent should call _exit() rather than the child; thebasic rule, applicable in the overwhelming majority of cases, is thatexit() should be called only once for each entry intomain.)

In the child branch of a vfork(), the use of exit() iseven more dangerous, since it will affect the state of the parentprocess.

1.2 Environment variables

1.2.1 How can I get/set an environment variable from a program?

Getting the value of an environment variable is done by usinggetenv().

#include <stdlib.h>

char *getenv(const char *name);

Setting the value of an environment variable is done by usingputenv().

#include <stdlib.h>

int putenv(char *string);

The string passed to putenv must not be freed or made invalid,since a pointer to it is kept by putenv(). This means that itmust either be a static buffer or allocated off the heap. The stringcan be freed if the environment variable is redefined or deleted viaanother call to putenv().

Remember that environment variables are inherited; each process has aseparate copy of the environment. As a result, you can't change thevalue of an environment variable in another process, such as the shell.

Suppose you wanted to get the value for the TERM environmentvariable. You would use this code:

char *envvar;

envvar=getenv("TERM");

printf("The value for the environment variable TERM is ");
if(envvar)
{
    printf("%s\n",envvar);
}
else
{
    printf("not set.\n");
}

Now suppose you wanted to create a new environment variable calledMYVAR, with a value of MYVAL. This is how you'd do it.

static char envbuf[256];

sprintf(envbuf,"MYVAR=%s","MYVAL");

if(putenv(envbuf))
{
    printf("Sorry, putenv() couldn't find the memory for %s\n",envbuf);
    /* Might exit() or something here if you can't live without it */
}

1.2.2 How can I read the whole environment?

If you don't know the names of the environment variables, then thegetenv() function isn't much use. In this case, you have to digdeeper into how the environment is stored.

A global variable, environ, holds a pointer to an array ofpointers to environment strings, each string in the form"NAME=value". A NULL pointer is used to mark the end ofthe array. Here's a trivial program to print the current environment(like printenv):

#include <stdio.h>

extern char **environ;

int main()
{
    char **ep = environ;
    char *p;
    while ((p = *ep++))
        printf("%s\n", p);
    return 0;
}

In general, the environ variable is also passed as the third,optional, parameter to main(); that is, the above could have beenwritten:

#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
    char *p;
    while ((p = *envp++))
        printf("%s\n", p);
    return 0;
}

However, while pretty universally supported, this method isn't actuallydefined by the POSIX standards. (It's also less useful, in general.)

1.3 How can I sleep for less than a second?

The sleep() function, which is available on all Unixes, onlyallows for a duration specified in seconds. If you want finergranularity, then you need to look for alternatives:

  • Many systems have a function usleep()
  • You can use select() or poll(), specifying no filedescriptors to test; a common technique is to write a usleep()function based on either of these (see the comp.unix.questions FAQ forsome examples)
  • If your system has itimers (most do), you can roll your ownusleep() using them (see the BSD sources for usleep() forhow to do this)
  • If you have POSIX realtime, there is a nanosleep() function

Of the above, select() is probably the most portable (andstrangely, it is often much more efficient than usleep() or anitimer-based method). However, the behaviour may be different if signalsare caught while asleep; this may or may not be an issue depending onthe application.

Whichever route you choose, it is important to realise that you may beconstrained by the timer resolution of the system (some systems allowvery short time intervals to be specified, others have a resolution of,say, 10ms and will round all timings to that). Also, as forsleep(), the delay you specify is only a minimum value;after the specified period elapses, there will be an indeterminate delaybefore your process next gets scheduled.

1.4 How can I get a finer-grained version of alarm()?

Modern Unixes tend to implement alarms using the setitimer()function, which has a higher resolution and more options than the simplealarm() function. One should generally assume that alarm()and setitimer(ITIMER_REAL) may be the same underlying timer, andaccessing it both ways may cause confusion.

Itimers can be used to implement either one-shot or repeating signals;also, there are generally 3 separate timers available:

ITIMER_REAL
counts real (wall clock) time, and sends the SIGALRM signal
ITIMER_VIRTUAL
counts process virtual (user CPU) time, and sends the SIGVTALRMsignal
ITIMER_PROF
counts user and system CPU time, and sends the SIGPROF signal;it is intended for interpreters to use for profiling.

Itimers, however, are not part of many of the standards, despite havingbeen present since 4.2BSD. The POSIX realtime extensions define somesimilar, but different, functions.

1.5 How can a parent and child process communicate?

A parent and child can communicate through any of the normalinter-process communication schemes (pipes, sockets, message queues,shared memory), but also have some special ways to communicate that takeadvantage of their relationship as a parent and child.

One of the most obvious is that the parent can get the exit status ofthe child.

Since the child inherits file descriptors from its parent, the parentcan open both ends of a pipe, fork, then the parent close one end andthe child close the other end of the pipe. This is what happens whenyou call the popen() routine to run another program from withinyours, i.e. you can write to the file descriptor returned frompopen() and the child process sees it as its stdin, or you canread from the file descriptor and see what the program wrote to itsstdout. (The mode parameter to popen() defines which; if you wantto do both, then you can do the plumbing yourself without too muchdifficulty.)

Also, the child process inherits memory segments mmapped anonymously (orby mmapping the special file `/dev/zero') by the parent; theseshared memory segments are not accessible from unrelated processes.

1.6 How do I get rid of zombie processes?

1.6.1 What is a zombie?

When a program forks and the child finishes before the parent, thekernel still keeps some of its information about the child in case theparent might need it -- for example, the parent may need to check thechild's exit status. To be able to get this information, the parentcalls wait(); when this happens, the kernel can discard theinformation.

In the interval between the child terminating and the parent callingwait(), the child is said to be a `zombie'. (If you do `ps', thechild will have a `Z' in its status field to indicate this.) Eventhough it's not running, it's still taking up an entry in the processtable. (It consumes no other resources, but some utilities may showbogus figures for e.g. CPU usage; this is because some parts of theprocess table entry have been overlaid by accounting info to savespace.)

This is not good, as the process table has a fixed number of entries andit is possible for the system to run out of them. Even if the systemdoesn't run out, there is a limit on the number of processes each usercan run, which is usually smaller than the system's limit. This is oneof the reasons why you should always check if fork() failed, bythe way!

If the parent terminates without calling wait(), the child is `adopted'by init, which handles the work necessary to cleanup after thechild. (This is a special system program with process ID 1 -- it'sactually the first program to run after the system boots up).

1.6.2 How do I prevent them from occuring?

You need to ensure that your parent process calls wait() (orwaitpid(), wait3(), etc.) for every child process thatterminates; or, on some systems, you can instruct the system that youare uninterested in child exit states.

Another approach is to fork() twice, and have theimmediate child process exit straight away. This causes the grandchildprocess to be orphaned, so the init process is responsible for cleaningit up. For code to do this, see the function fork2() in theexamples section.

To ignore child exit states, you need to do the following (check yoursystem's manpages to see if this works):

    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
#ifdef SA_NOCLDWAIT
    sa.sa_flags = SA_NOCLDWAIT;
#else
    sa.sa_flags = 0;
#endif
    sigemptyset(&sa.sa_mask);
    sigaction(SIGCHLD, &sa, NULL);

If this is successful, then the wait() functions are preventedfrom working; if any of them are called, they will wait until allchild processes have terminated, then return failure with errno == ECHILD.

The other technique is to catch the SIGCHLD signal, and have the signalhandler call waitpid() or wait3(). See the examplessection for a complete program.

1.7 How do I get my program to act like a daemon?

A daemon process is usually defined as a background process thatdoes not belong to a terminal session. Many system services are performedby daemons; network services, printing etc.

Simply invoking a program in the background isn't really adequate for theselong-running programs; that does not correctly detach the process from theterminal session that started it. Also, the conventional way of startingdaemons is simply to issue the command manually or from an rc script; thedaemon is expected to put itself into the background.

Here are the steps to become a daemon:

  1. fork() so the parent can exit, this returns control to thecommand line or shell invoking your program. This step is required sothat the new process is guaranteed not to be a process group leader. Thenext step, setsid(), fails if you're a process group leader.
  2. setsid() to become a process group and session groupleader. Since a controlling terminal is associated with a session, andthis new session has not yet acquired a controlling terminal our processnow has no controlling terminal, which is a Good Thing for daemons.
  3. fork() again so the parent, (the session group leader), can exit.This means that we, as a non-session group leader, can never regain acontrolling terminal.
  4. chdir("/") to ensure that our process doesn't keep any directoryin use. Failure to do this could make it so that an administratorcouldn't unmount a filesystem, because it was our current directory.[Equivalently, we could change to any directory containing filesimportant to the daemon's operation.]
  5. umask(0) so that we have complete control over the permissions ofanything we write. We don't know what umask we may have inherited.[This step is optional]
  6. close() fds 0, 1, and 2. This releases the standard in, out, anderror we inherited from our parent process. We have no way of knowingwhere these fds might have been redirected to. Note that many daemonsuse sysconf() to determine the limit _SC_OPEN_MAX._SC_OPEN_MAX tells you the maximun open files/process. Then in aloop, the daemon can close all possible file descriptors. You have todecide if you need to do this or not. If you think that there might befile-descriptors open you should close them, since there's a limit onnumber of concurrent file descriptors.
  7. Establish new open descriptors for stdin, stdout and stderr. Even if youdon't plan to use them, it is still a good idea to have them open. Theprecise handling of these is a matter of taste; if you have a logfile,for example, you might wish to open it as stdout or stderr, and open`/dev/null' as stdin; alternatively, you could open`/dev/console' as stderr and/or stdout, and `/dev/null' asstdin, or any other combination that makes sense for your particulardaemon.

Almost none of this is necessary (or advisable) if your daemon is beingstarted by inetd. In that case, stdin, stdout and stderr are allset up for you to refer to the network connection, and thefork()s and session manipulation should not be done (toavoid confusing inetd). Only the chdir() andumask() steps remain as useful.

1.8 How can I look at process in the system like ps does?

You really don't want to do this.

The most portable way, by far, is to do popen(pscmd, "r") andparse the output. (pscmd should be something like `"ps -ef"' onSysV systems; on BSD systems there are many possible display options:choose one.)

In the examples section, there are two complete versions of this; onefor SunOS 4, which requires root permission to run and uses the`kvm_*' routines to read the information from kernel datastructures; and another for SVR4 systems (including SunOS 5), which usesthe `/proc' filesystem.

It's even easier on systems with an SVR4.2-style `/proc'; just reada psinfo_t structure from the file `/proc/PID/psinfo' for each PIDof interest. However, this method, while probably the cleanest, is alsoperhaps the least well-supported. (On FreeBSD's `/proc', you read asemi-undocumented printable string from `/proc/PID/status'; Linuxhas something similar.)

1.9 Given a pid, how can I tell if it's a running program?

Use kill() with 0 for the signal number.

There are four possible results from this call:

  • kill() returns 0
    • this implies that a process exists with the given PID, and the systemwould allow you to send signals to it. It is system-dependent whetherthe process could be a zombie.
  • kill() returns @math{-1}, errno == ESRCH
    • either no process exists with the given PID, or security enhancementsare causing the system to deny its existence. (On some systems, theprocess could be a zombie.)
  • kill() returns @math{-1}, errno == EPERM
    • the system would not allow you to kill the specified process. Thismeans that either the process exists (again, it could be a zombie) ordraconian security enhancements are present (e.g. your process is notallowed to send signals to anybody).
  • kill() returns @math{-1}, with some other value of errno
    • you are in trouble!

The most-used technique is to assume that success or failure withEPERM implies that the process exists, and any other errorimplies that it doesn't.

An alternative exists, if you are writing specifically for a system (orall those systems) that provide a `/proc' filesystem: checking forthe existence of `/proc/PID' may work.

1.10 What's the return value of system/pclose/waitpid?

The return value of system(), pclose(), orwaitpid() doesn't seem to be the exit value of my process...or the exit value is shifted left 8 bits... what's the deal?

The man page is right, and so are you! If you read the man page forwaitpid() you'll find that the return code for the process isencoded. The value returned by the process is normally in the top 16bits, and the rest is used for other things. You can't rely on thisthough, not if you want to be portable, so the suggestion is that youuse the macros provided. These are usually documented underwait() or wstat.

Macros defined for the purpose (in `<sys/wait.h>') include (stat isthe value returned by waitpid()):

WIFEXITED(stat)
Non zero if child exited normally.
WEXITSTATUS(stat)
exit code returned by child
WIFSIGNALED(stat)
Non-zero if child was terminated by a signal
WTERMSIG(stat)
signal number that terminated child
WIFSTOPPED(stat)
non-zero if child is stopped
WSTOPSIG(stat)
number of signal that stopped child
WIFCONTINUED(stat)
non-zero if status was for continued child
WCOREDUMP(stat)
If WIFSIGNALED(stat) is non-zero, this is non-zero if the processleft behind a core dump.

1.11 How do I find out about a process' memory usage?

Look at getrusage(), if available.

1.12 Why do processes never decrease in size?

When you free memory back to the heap with free(), on almost allsystems that doesn't reduce the memory usage of your program.The memory free()d is still part of the process' address space,and will be used to satisfy future malloc() requests.

If you really need to free memory back to the system, look at usingmmap() to allocate private anonymous mappings. When these areunmapped, the memory really is released back to the system. Certainimplementations of malloc() (e.g. in the GNU C Library)automatically use mmap() where available to perform largeallocations; these blocks are then returned to the system onfree().

Of course, if your program increases in size when you think itshouldn't, you may have a `memory leak' -- a bug in your program thatresults in unused memory not being freed.

1.13 How do I change the name of my program (as seen by `ps')?

On BSDish systems, the ps program actually looks into the addressspace of the running process to find the current argv[], anddisplays that. That enables a program to change its `name' simply bymodifying argv[].

On SysVish systems, the command name and usually the first 80 bytes ofthe parameters are stored in the process' u-area, and so can't bedirectly modified. There may be a system call to change this (unlikely),but otherwise the only way is to perform an exec(), or write intokernel memory (dangerous, and only possible if running as root).

Some systems (notably Solaris) may have two separate versions ofps, one in `/usr/bin/ps' with SysV behaviour, and one in`/usr/ucb/ps' with BSD behaviour. On these systems, if you changeargv[], then the BSD version of ps will reflect thechange, and the SysV version won't.

Check to see if your system has a function setproctitle().

1.14 How can I find a process' executable file?

This would be a good candidate for a list of `Frequently UnansweredQuestions', because the fact of asking the question usually means thatthe design of the program is flawed. :-)

You can make a `best guess' by looking at the value of argv[0].If this contains a `/', then it is probably the absolute orrelative (to the current directory at program start) path of theexecutable. If it does not, then you can mimic the shell's search ofthe PATH variable, looking for the program. However, success isnot guaranteed, since it is possible to invoke programs with arbitraryvalues of argv[0], and in any case the executable may have beenrenamed or deleted since it was started.

If all you want is to be able to print an appropriate invocation namewith error messages, then the best approach is to have main()save the value of argv[0] in a global variable for use by theentire program. While there is no guarantee whatsoever that the valuein argv[0] will be meaningful, it is the best option available in most circumstances.

The most common reason people ask this question is in order to locateconfiguration files with their program. This is considered to be badform; directories containing executables should contain nothingexcept executables, and administrative requirements often make itdesirable for configuration files to be located on different filesystemsto executables.

A less common, but more legitimate, reason to do this is to allow theprogram to call exec() on itself; this is a method used(e.g. by some versions of sendmail) to completely reinitialisethe process (e.g. if a daemon receives a SIGHUP).

1.14.1 So where do I put my configuration files then?

The correct directory for this usually depends on the particular flavourof Unix you're using; `/var/opt/PACKAGE', `/usr/local/lib',`/usr/local/etc', or any of several other possibilities.User-specific configuration files are usually hidden `dotfiles' under$HOME (e.g. `$HOME/.exrc').

From the point of view of a package that is expected to be usable acrossa range of systems, this usually implies that the location of anysitewide configuration files will be a compiled-in default, possiblyusing a `--prefix' option on a configure script (Autoconf scriptsdo this). You might wish to allow this to be overridden at runtime byan environment variable. (If you're not using a configure script, thenput the default in the Makefile as a `-D' option on compiles, orput it in a `config.h' header file, or something similar.)

User-specific configuration should be either a single dotfile under$HOME, or, if you need multiple files, a dot-subdirectory.(Files or directories whose names start with a dot are omitted fromdirectory listings by default.) Avoid creating multiple entries under$HOME, because this can get very cluttered. Again, you can allowthe user to override this location with an environmentvariable. Programs should always behave sensibly if they fail to findany per-user configuration.

1.15 Why doesn't my process get SIGHUP when its parent dies?

Because it's not supposed to.

SIGHUP is a signal that means, by convention, "the terminal linegot hung up". It has nothing to do with parent processes, and isusually generated by the tty driver (and delivered to the foregroundprocess group).

However, as part of the session management system, there are exactly twocases where SIGHUP is sent on the death of a process:

  • When the process that dies is the session leader of a session that isattached to a terminal device, SIGHUP is sent to all processes inthe foreground process group of that terminal device.
  • When the death of a process causes a process group to become orphaned,and one or more processes in the orphaned group are stopped, thenSIGHUP and SIGCONT are sent to all members of the orphanedgroup. (An orphaned process group is one where no process in the grouphas a parent which is part of the same session, but not the same processgroup.)

1.16 How can I kill all descendents of a process?

There isn't a fully general approach to doing this. While you candetermine the relationships between processes by parsing psoutput, this is unreliable in that it represents only a snapshot of thesystem.

However, if you're lauching a subprocess that might spawn furthersubprocesses of its own, and you want to be able to kill the entirespawned job at one go, the solution is to put the subprocess into anew process group, and kill that process group if you need to.

The preferred function for creating process groups is setpgid().Use this if possible rather than setpgrp() because the latterdiffers between systems (on some systems `setpgrp();' is equivalentto `setpgid(0,0);', on others, setpgrp() and setpgid()are identical).

See the job-control example in the examples section.

Putting a subprocess into its own process group has a number of effects.In particular, unless you explicitly place the new process group in theforeground, it will be treated as a background job with theseconsequences:

  • it will be stopped with SIGTTIN if it attempts to read from theterminal
  • if tostop is set in the terminal modes, it will be stopped withSIGTTOU if it attempts to write to the terminal (attempting tochange the terminal modes should also cause this, independently of thecurrent setting of tostop)
  • The subprocess will not receive keyboard signals from the terminal(e.g. SIGINT or SIGQUIT)

In many applications input and output will be redirected anyway, so themost significant effect will be the lack of keyboard signals. The parentapplication should arrange to catch at least SIGINT andSIGQUIT (and preferably SIGTERM as well) and clean up anybackground jobs as necessary.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值