ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/host/c++/socket++-1.10/Fork.C
Revision: 1.1
Committed: Mon Feb 26 15:01:39 2001 UTC (23 years, 9 months ago) by ab11
Content type: text/plain
Branch: MAIN
CVS Tags: PROJECT_COMPLETION
Log Message:
Networking class. Assumed to be bug free.

File Contents

# User Rev Content
1 ab11 1.1 // Fork.C -*- C++ -*- socket library
2     // Copyright (C) 1992,1993,1994 Gnanasekaran Swaminathan <gs4t@virginia.edu>
3     //
4     // Permission is granted to use at your own risk and distribute this software
5     // in source and binary forms provided the above copyright
6     // notice and this paragraph are preserved on all copies.
7     // This software is provided "as is" with no express or implied warranty.
8     //
9     // Version: 17Oct95 1.10
10    
11     #include <config.h>
12    
13     #include <iostream.h>
14     #include <stdio.h> // perror in solaris2.3 is declared here
15     #include <stdlib.h>
16     #include <unistd.h>
17     #include <errno.h>
18     #include <signal.h>
19     #include <sys/wait.h>
20    
21     #include <Fork.h>
22    
23     Fork::ForkProcess* Fork::ForkProcess::list = 0;
24     Fork::KillForks Fork::killall;
25    
26     Fork::~Fork ()
27     {
28     if (process->pid <= 0)
29     delete process;
30     }
31    
32     Fork::KillForks::~KillForks ()
33     // First, kill all children whose kill_child flag is set.
34     // Second, wait for other children to die.
35     {
36     for (ForkProcess* cur = Fork::ForkProcess::list; cur; cur = cur->next)
37     if (cur->kill_child)
38     delete cur;
39    
40     while (Fork::ForkProcess::list && wait (0) > 0);
41     }
42    
43     Fork::ForkProcess::ForkProcess (int kill, int give_reason)
44     : kill_child (kill), reason (give_reason), next (0)
45     {
46     if (list == 0) {
47     struct sigaction sa;
48     sa.sa_handler = funcptr (&Fork::ForkProcess::reaper_nohang);
49     sigemptyset (&sa.sa_mask);
50     sa.sa_flags = SA_RESTART;
51     sigaction (SIGCHLD, &sa, 0);
52     }
53    
54     pid = fork ();
55    
56     if (pid > 0) {
57     next = list;
58     list = this;
59     } else if (pid == 0) {
60     // child process. clear list
61     ForkProcess* p = list;
62     while (p) {
63     ForkProcess* nxt = p->next;
64     p->pid = 0;
65     delete p;
66     p = nxt;
67     }
68     list = 0;
69    
70     if (kill_child) {
71     struct sigaction sa;
72     sa.sa_handler = funcptr (&Fork::ForkProcess::commit_suicide);
73     sigemptyset (&sa.sa_mask);
74     sa.sa_flags = SA_RESTART;
75     sigaction (SIGTERM, &sa, 0);
76     }
77     }
78     }
79    
80     Fork::ForkProcess::~ForkProcess ()
81     {
82     if (pid > 0) {
83     if (kill_child)
84     kill (pid, SIGTERM);
85     reap_child ();
86    
87     // I remove myself from list
88     if (list == this)
89     list = list->next;
90     else {
91     for (ForkProcess* p = list; p; p = p->next)
92     if (p->next == this) {
93     p->next = next;
94     break;
95     }
96     }
97     }
98     }
99    
100     void Fork::ForkProcess::kill_process () const
101     {
102     if (pid > 0) {
103     kill (pid, SIGKILL);
104     reap_child ();
105     }
106     }
107    
108     void Fork::ForkProcess::reap_child () const
109     {
110     int status;
111     if (pid > 0 && waitpid (pid, &status, 0) == pid && reason)
112     infanticide_reason (pid, status);
113     }
114    
115     void Fork::ForkProcess::infanticide_reason (pid_t pid, int status)
116     {
117     if (pid <= 0)
118     return;
119    
120     if (WIFSTOPPED (status))
121     cerr << "process " << pid << " gets "
122     << SYS_SIGLIST [WSTOPSIG (status)] << endl;
123     else if (WIFEXITED (status))
124     cerr << "process " << pid << " exited with status "
125     << WEXITSTATUS (status) << endl;
126     else if (WIFSIGNALED (status))
127     cerr << "process " << pid << " got "
128     << SYS_SIGLIST [WTERMSIG (status)] << endl;
129     }
130    
131     void Fork::ForkProcess::reaper_nohang (int signo)
132     {
133     if (signo != SIGCHLD)
134     return;
135    
136     int status;
137     pid_t wpid;
138     if ((wpid = waitpid (-1, &status, WNOHANG)) > 0) {
139     ForkProcess* prev = 0;
140     ForkProcess* cur = list;
141     while (cur) {
142     if (cur->pid == wpid) {
143     cur->pid = -1;
144     if (prev)
145     prev->next = cur->next;
146     else
147     list = list->next;
148    
149     if (cur->reason)
150     infanticide_reason (wpid, status);
151    
152     delete cur;
153     break;
154     }
155     prev = cur;
156     cur = cur->next;
157     }
158     }
159     }
160    
161     void Fork::ForkProcess::commit_suicide (int)
162     {
163     // if this process has any children we kill them.
164    
165     ForkProcess* p = list;
166     while (p) {
167     ForkProcess* next = p->next;
168     if (!p->kill_child) // otherwise ForkProcess::~ForkProcess will take care
169     kill (p->pid, SIGKILL);
170     delete p; // ForkProcess::~ForkProcess will call reap_child ().
171     p = next;
172     }
173    
174     exit (0x0f);
175     }
176    
177     void Fork::suicide_signal (int signo)
178     // commit suicide at the signal signo
179     {
180     struct sigaction sa;
181     sa.sa_handler = funcptr (&Fork::ForkProcess::commit_suicide);
182     sigemptyset (&sa.sa_mask);
183     sa.sa_flags = 0;
184     if (sigaction (signo, &sa, 0) == -1)
185     perror ("Fork: Cannot commit suicide with the specified signal");
186     }