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

# Content
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 }