/[cvs]/eggdrop1.9/src/bg.c
ViewVC logotype

Contents of /eggdrop1.9/src/bg.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Fri Oct 27 19:36:34 2000 UTC (19 years ago) by fabian
Branch: MAIN
Changes since 1.1: +79 -69 lines
File MIME type: text/x-chdr
fabian: applied bg_cleanup patch

1 /*
2 * bg.c -- handles:
3 * moving the process to the background, i.e. forking, while keeping threads
4 * happy.
5 *
6 * $Id: bg.c,v 1.1 2000/09/27 19:48:54 fabian Exp $
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999, 2000 Eggheads
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #include "main.h"
28 #include <signal.h>
29 #include "bg.h"
30
31 #ifdef HAVE_TCL_THREADS
32 # define SUPPORT_THREADS
33 #endif
34
35 extern char pid_file[];
36
37 #ifdef SUPPORT_THREADS
38
39 /* When threads are started during eggdrop's init phase, we can't simply
40 * fork() later on, because that only copies the VM space over and
41 * doesn't actually duplicate the threads.
42 *
43 * To work around this, we fork() very early and let the parent process
44 * wait in an event loop. As soon as the init phase is completed and we
45 * would normally move to the background, the child process simply
46 * messages it's parent that it may now quit. This allows us to control
47 * the terminal long enough to, e.g. properly feed error messages to
48 * cron scripts and let the user abort the loading process by hitting
49 * CTRL+C.
50 *
51 *
52 * [ Parent process ] [ Child process ]
53 *
54 * main()
55 * ...
56 * bg_prepare_split()
57 * fork() - created -
58 * waiting in event loop. continuing execution in main()
59 * ...
60 * completed init.
61 * bg_do_detach()
62 * message parent new PID file-
63 * name.
64 * receives new PID filename
65 * message.
66 * message parent to quit.
67 * receives quit message. continues to main loop.
68 * writes PID to file. ...
69 * exits.
70 */
71
72 /* Format of messages sent from the newly forked process to the
73 original process, connected to the terminal. */
74 typedef struct {
75 enum {
76 BG_COMM_QUIT, /* Quit original process. Write
77 PID file, etc. i.e. detach. */
78 BG_COMM_ABORT, /* Quit original process. */
79 BG_COMM_TRANSFERPF /* Sending pid_file. */
80 } comm_type;
81 union {
82 struct { /* Data for BG_COMM_TRANSFERPF. */
83 int len; /* Length of the file name. */
84 } transferpf;
85 } comm_data;
86 } bg_comm_t;
87
88 typedef enum {
89 BG_NONE = 0, /* No forking has taken place
90 yet. */
91 BG_SPLIT, /* I'm the newly forked process. */
92 BG_PARENT /* I'm the original process. */
93 } bg_state_t;
94
95 typedef struct {
96 int comm_recv; /* Receives messages from the
97 child process. */
98 int comm_send; /* Sends messages to the parent
99 process. */
100 bg_state_t state; /* Current state, see above
101 enum descriptions. */
102 pid_t child_pid; /* PID of split process. */
103 } bg_t;
104
105 static bg_t bg = { 0 };
106
107 #endif /* SUPPORT_THREADS */
108
109
110 /* Do everything we normally do after we have split off a new
111 * process to the background. This includes writing a PID file
112 * and informing the user of the split.
113 */
114 static void bg_do_detach(pid_t p)
115 {
116 FILE *fp;
117
118 /* Need to attempt to write pid now, not later. */
119 unlink(pid_file);
120 fp = fopen(pid_file, "w");
121 if (fp != NULL) {
122 fprintf(fp, "%u\n", p);
123 if (fflush(fp)) {
124 /* Kill bot incase a botchk is run from crond. */
125 printf(EGG_NOWRITE, pid_file);
126 printf(" Try freeing some disk space\n");
127 fclose(fp);
128 unlink(pid_file);
129 exit(1);
130 }
131 fclose(fp);
132 } else
133 printf(EGG_NOWRITE, pid_file);
134 printf("Launched into the background (pid: %d)\n\n", p);
135 #if HAVE_SETPGID
136 setpgid(p, p);
137 #endif
138 exit(0);
139 }
140
141 void bg_prepare_split(void)
142 {
143 #ifdef SUPPORT_THREADS
144 /* Create a pipe between parent and split process, fork to create a
145 parent and a split process and wait for messages on the pipe. */
146 pid_t p;
147 bg_comm_t message;
148
149 {
150 int comm_pair[2];
151
152 if (pipe(comm_pair) < 0)
153 fatal("CANNOT OPEN PIPE.", 0);
154
155 bg.comm_recv = comm_pair[0];
156 bg.comm_send = comm_pair[1];
157 }
158
159 p = fork();
160 if (p == -1)
161 fatal("CANNOT FORK PROCESS.", 0);
162 if (p == 0) {
163 bg.state = BG_SPLIT;
164 return;
165 } else {
166 bg.child_pid = p;
167 bg.state = BG_PARENT;
168 }
169
170 while (read(bg.comm_recv, &message, sizeof(message)) > 0) {
171 switch (message.comm_type) {
172 case BG_COMM_QUIT:
173 bg_do_detach(p);
174 break;
175 case BG_COMM_ABORT:
176 exit(1);
177 break;
178 case BG_COMM_TRANSFERPF:
179 /* Now transferring file from split process.
180 */
181 if (message.comm_data.transferpf.len >= 40)
182 message.comm_data.transferpf.len = 40 - 1;
183 /* Next message contains data. */
184 if (read(bg.comm_recv, pid_file, message.comm_data.transferpf.len) <= 0)
185 goto error;
186 pid_file[message.comm_data.transferpf.len] = 0;
187 break;
188 }
189 }
190
191 error:
192 /* We only reach this point in case of an error.
193 */
194 fatal("COMMUNICATION THROUGH PIPE BROKE.", 0);
195 #endif
196 }
197
198 #ifdef SUPPORT_THREADS
199 /* Transfer contents of pid_file to parent process. This is necessary,
200 * as the pid_file[] buffer has changed in this fork by now, but the
201 * parent needs an up-to-date version.
202 */
203 static void bg_send_pidfile(void)
204 {
205 bg_comm_t message;
206
207 message.comm_type = BG_COMM_TRANSFERPF;
208 message.comm_data.transferpf.len = strlen(pid_file);
209
210 /* Send type message. */
211 if (write(bg.comm_send, &message, sizeof(message)) < 0)
212 goto error;
213 /* Send data. */
214 if (write(bg.comm_send, pid_file, message.comm_data.transferpf.len) < 0)
215 goto error;
216 return;
217 error:
218 fatal("COMMUNICATION THROUGH PIPE BROKE.", 0);
219 }
220 #endif
221
222 void bg_send_quit(bg_quit_t q)
223 {
224 #ifdef SUPPORT_THREADS
225 if (bg.state == BG_PARENT) {
226 kill(bg.child_pid, SIGKILL);
227 } else if (bg.state == BG_SPLIT) {
228 bg_comm_t message;
229
230 if (q == BG_QUIT) {
231 bg_send_pidfile();
232 message.comm_type = BG_COMM_QUIT;
233 } else
234 message.comm_type = BG_COMM_ABORT;
235 /* Send message. */
236 if (write(bg.comm_send, &message, sizeof(message)) < 0)
237 fatal("COMMUNICATION THROUGH PIPE BROKE.", 0);
238 }
239 #endif
240 }
241
242 void bg_do_split(void)
243 {
244 #ifdef SUPPORT_THREADS
245 /* Tell our parent process to go away now, as we don't need it
246 anymore. */
247 bg_send_quit(BG_QUIT);
248 #else
249 /* Split off a new process.
250 */
251 int xx = fork();
252
253 if (xx == -1)
254 fatal("CANNOT FORK PROCESS.", 0);
255 if (xx != 0)
256 bg_do_detach(xx);
257 #endif
258 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23