libassa 3.5.1
Loading...
Searching...
No Matches
Fork.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// Fork.cpp
4//------------------------------------------------------------------------------
5// Copyright (C) 1997-2003,2005 Vladislav Grinchenko
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Library General Public
9// License as published by the Free Software Foundation; either
10// version 2 of the License, or (at your option) any later version.
11//------------------------------------------------------------------------
12
13#include <iostream>
14#include <fcntl.h>
15
16#if !defined(WIN32)
17# include <syslog.h>
18#endif
19
20#include "assa/Fork.h"
21#include "assa/CmdLineOpts.h"
22#include "assa/SigAction.h"
23#include "assa/EventHandler.h"
24#include "assa/SigHandler.h"
25
26using namespace ASSA;
27
28//------------------------------------------------------------------------------
29/*
30 * Note the use of _exit () instead of exit () in the child's portion.
31 * For some GUI toolkits, calling exit() causes problems.
32 *
33 * From Gtk+ (www.gtk.org) FAQ:
34 *
35 * "When GDK opens an X display, it creates a socket file descriptor.
36 * When you use the exit() function, you implicitly close all the
37 * open file descriptors, and the underlying X library really
38 * doesn't like this. The right function to use here is _exit()."
39 *
40 * From UNIX exit(2) man page:
41 *
42 * "The function _exit terminates the calling process "immediately".
43 * Any open file descriptors belonging to the process are closed;
44 * any children of the process are inherited by process 1, init, and
45 * the process's parent is sent a SIGCHLD signal."
46 *
47 * _exit() doesn't not call standard I/O cleanup routines.
48 *
49 * From S.A. Rago "Unix System V Network Programming", sec. 2.4, p.74
50 *
51 * "When a child terminates, the operationg system sends the SIGCHLD
52 * signal to the parent process. The default disposition for SIGCHLD
53 * is to ignore the signal, but a process can catch the signal and
54 * obtain the status of its children."
55 *
56 * We also preserve the SIGCHLD action mask here and catch it to get
57 * the child's completion status. SIGCHLD signal mask is initially set to
58 * SIG_IGN by GenServer, but can be reset later on by a third-party library
59 * linked into the application code.
60 */
61int
63fork_exec (const string& cmd_,
64 const string& args_,
66 bool ignore_output_)
67{
68 trace_with_mask("Fork[static]::fork_exec",FORK);
69
70 DL((FORK,"exec \"%s %s\")\n", cmd_.c_str (), args_.c_str ()));
71 if (cmd_.size () == 0) {
72 return -1;
73 }
74
75#if defined(WIN32)
76
77 return -1; // NOT IMPLEMENTED YET
78
79#else
80
82
83 if (f.isChild ()) {
84 string arg_list (cmd_);
85 arg_list += " " + args_;
86 int argc = 0;
87 char** argv = 0;
89
93 if (ignore_output_) {
94 for (int i = 0; i < 1024; i++) {
95 (void) close(i);
96 }
97 pid_t nullfd = open("/dev/null", O_WRONLY | O_CREAT, 0666);
98 if (nullfd == -1) {
99 syslog (LOG_ERR,"failed to open \"/dev/null\"");
100 _exit (-1);
101 }
102
103 (void) dup2 (nullfd, 1);
104 (void) dup2 (nullfd, 2);
105 (void) close (nullfd);
106 }
107
108 execvp (cmd_.c_str (), argv);
109
110 EL((ASSAERR,"fork_exec (\"%s\") failed\n", cmd_.c_str ()));
111 _exit (-1);
112 }
113
114 if (! wait_for_completion_) {
115 return f.getChildPID ();
116 }
117
118 return f.get_exit_status ();
119
120#endif // defined(WIN32)
121}
122
123
124#if !defined(WIN32)
125//------------------------------------------------------------------------------
126// Static declarations
127//
129
130//------------------------------------------------------------------------------
131// Member functions
132//
133int
136{
137 trace_with_mask("ChildStatusHandler::handle_signal", FORK);
138 DL((FORK, "Caught signal # %d\n", signum_));
139
140 if (signum_ == SIGCHLD) {
141 int status;
142 m_caught = true;
143 pid_t ret = ::wait (&status);
144 DL((FORK,"wait() = %d (PID)\n", ret));
145
146 if (ret > 0 && (WIFEXITED (status))) {
148 }
149 else {
151 }
152 }
153
154 DL((FORK,"child exit_status = %d\n", m_exit_status));
155 return 0;
156}
157
158//------------------------------------------------------------------------------
161{
162 trace_with_mask("Fork::Fork",FORK);
163
166 }
167
168 if ((m_pid = fork()) < 0) {
169 EL((ASSAERR,"failed to fork() - out of swap space?\n"));
170 exit (1); // die right here
171 }
172
173 if (m_pid) { // The Parent
174 if (exit_action_ != LEAVE_ALONE) {
175 ForkList::get_instance()->m_list.push_back (new fnode_t (m_pid, exit_action_));
176 }
178 if (! m_chstath.caught ()) {
179 pause ();
180 }
182 }
183 }
184}
185
186
188~ForkList()
189{
190 trace_with_mask("ForkList::~ForkList",FORK);
191
192 list<fnode_t* >::iterator i;
193 pid_t pid;
194
195 // Go through the list and send SIGTERM to those children
196 // whose flags were set at fork time.
197
198 for (i = m_list.begin(); i != m_list.end(); i++) {
199 if ((*i)->needKill()) {
200 ::kill((*i)->getPID(), SIGTERM);
201 }
202 }
203 // Wait for all children to exit.
204
205 while ( ! m_list.empty() ) { // wait for child to exit
206 pid = ::wait(NULL);
207 if ( pid < 0 ) { // error on wait
208 EL((ASSAERR,"Error on wait()\n"));
210 }
211 // Search for child through the list by its pid.
212 // If found, remove it from list and release memory.
213
214 list<fnode_t* >::iterator j;
215
216 for (j = m_list.begin(); j != m_list.end(); j++) {
217 if ((*j)->getPID() == pid) {
218 fnode_t* ep = *j;
219 m_list.erase(j);
220 delete ep;
221 break;
222 }
223 }
224 }
225}
226
227#endif // !defined(WIN32)
Class to handle processing command-line options.
An abstract interface for handling I/O events, timers, and such.
A simple wrapper around fork() library function call.
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
SigAction is a C++ wrapper around sigaction structure.
Class SigHandler is a UNIX signal handlers manager/dispatcher class.
#define ASSA_DECL_SINGLETON(K)
ASSA_DECL_SINGLETON macro inserts static member declarations mandated by the Singleton class.
Definition Singleton.h:82
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
int handle_signal(int signum_)
Signal handler callback.
Definition Fork.cpp:135
bool caught() const
Definition Fork.h:73
static void str_to_argv(const string &src_, int &argc_, char **&argv_)
Static function.
ForkList is a singleton class that keeps a list of all forked children.
Definition Fork.h:232
list< fnode_t * > m_list
List of children's data structures.
Definition Fork.h:241
~ForkList()
Destructor. Wipe out childer based on their state.
Definition Fork.cpp:188
Fork class is a simple wrapper around C library function fork().
Definition Fork.h:86
pid_t m_pid
Child pid.
Definition Fork.h:178
state_t
Child completion states.
Definition Fork.h:91
@ LEAVE_ALONE
Ignore all running children on exit.
Definition Fork.h:94
wait4status_t
Definition Fork.h:99
@ COLLECT_STATUS
Wait for child to complete and collect its exit status.
Definition Fork.h:101
SigAction m_old_disp
Old signal disposition.
Definition Fork.h:187
SigHandler m_local_sh
Local signal handler.
Definition Fork.h:181
static int fork_exec(const string &cmd_, const string &args_, wait4status_t wait_for_completion_, bool ignore_output_=false)
Execute an external command.
Definition Fork.cpp:63
Fork(state_t exit_action_=WAIT_ON_EXIT, wait4status_t catch_status_=COLLECT_STATUS)
Fork the current process in two immediately.
Definition Fork.cpp:160
ChildStatusHandler m_chstath
Handler to catch Child's status.
Definition Fork.h:184
virtual int remove(int signum_, EventHandler *eh_=0, SigAction *new_disp_=0, SigAction *old_disp_=0)
Remove EventHandler associated with signum_.
virtual int install(int signum_, EventHandler *new_hand_, SigAction *new_disp_=0, EventHandler **old_hand_=0, SigAction *old_disp_=0)
Add new signal handler and new disposition for the signal.
static ForkList * get_instance()
Return an instance of templated class T.
Definition Singleton.h:47
forknode_t class.
Definition Fork.h:195
@ FORK
Class Fork messages
Definition LogMask.h:47
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34