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

Annotation of /eggdrop1.8/src/bg.c

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


Revision 1.2 - (hide annotations) (download) (as text)
Mon Mar 14 03:03:28 2011 UTC (8 years, 1 month ago) by thommey
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +4 -4 lines
File MIME type: text/x-chdr
Moved variable declarations to conform to C89 (beginning of blocks only)

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23