4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcsignals.h"
28 #include <sys/types.h>
29 #include <sys/socket.h>
35 : Mutex("ForkBase::lock")
56 delete [] parent_data;
57 if( child_fd >= 0 ) close(child_fd);
58 if( parent_fd >= 0 ) close(parent_fd);
61 // return 1 parent is running
62 int ForkChild::is_running()
64 return !ppid || !kill(ppid, 0) ? 1 : 0;
67 int ForkChild::child_iteration()
69 int ret = read_child(100);
70 if( ret <= 0 ) return ret;
71 return handle_child();
74 void ForkParent::start_child()
76 lock("ForkParent::new_child");
77 int sockets[2]; // Create the process & socket pair.
78 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
79 child_fd = sockets[0]; parent_fd = sockets[1];
82 if( !pid ) { // child process
83 ForkChild *child = new_fork();
84 child->child_fd = child_fd;
85 child->parent_fd = parent_fd;
94 // Return -1 if the parent is dead
95 // Return 0 if timeout
96 // Return 1 if success
97 int ForkBase::read_timeout(int ms, int fd, void *data, int bytes)
100 struct timeval timeout_struct;
102 uint8_t *bp = (uint8_t *)data;
104 while( bytes_read < bytes ) {
105 timeout_struct.tv_sec = ms / 1000;
106 timeout_struct.tv_usec = (ms % 1000) * 1000;
109 int result = select(fd+1, &rfds, 0, 0, &timeout_struct);
110 if( result < 0 ) perror("read_timeout select");
111 if( result < 0 || !is_running() ) return -1;
112 if( !result && !bytes_read ) return 0;
113 int fragment = read(fd, bp + bytes_read, bytes - bytes_read);
114 if( fragment < 0 ) perror("read_timeout read");
115 if( fragment < 0 || !is_running() ) return -1;
116 if( fragment > 0 ) bytes_read += fragment;
121 // return 1 if child, or if parent && child is running
122 int ForkBase::is_running()
125 if( pid && waitpid(pid, &status, WNOHANG) < 0 ) return 0;
126 return !pid || !kill(pid, 0) ? 1 : 0;
129 int ForkBase::read_parent(int ms)
132 int ret = read_timeout(ms, parent_fd, &bfr, sizeof(bfr));
134 parent_token = bfr.token;
135 parent_bytes = bfr.bytes;
136 if( parent_bytes && parent_allocated < parent_bytes ) {
137 delete [] parent_data;
138 parent_data = new uint8_t[parent_allocated = parent_bytes];
141 ret = read_timeout(1000, parent_fd, parent_data, parent_bytes);
143 printf("read_parent timeout: %d\n", parent_fd);
151 int ForkBase::read_child(int ms)
154 int ret = read_timeout(ms, child_fd, &bfr, sizeof(bfr));
156 child_token = bfr.token;
157 child_bytes = bfr.bytes;
158 if( child_bytes && child_allocated < child_bytes ) {
159 delete [] child_data;
160 child_data = new uint8_t[child_allocated = child_bytes];
163 ret = read_timeout(1000, child_fd, child_data, child_bytes);
165 printf("read_child timeout: %d\n", child_fd);
173 void ForkBase::send_bfr(int fd, const void *bfr, int len)
176 for( int retries=10; --retries>=0 && (ret=write(fd, bfr, len)) < 0; ) {
177 printf("send_bfr socket(%d) write error: %d/%d bytes\n%m\n", fd,ret,len);
181 printf("send_bfr socket(%d) write short: %d/%d bytes\n%m\n", fd,ret,len);
184 int ForkBase::send_parent(int64_t token, const void *data, int bytes)
186 lock("ForkBase::send_parent");
187 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
188 bfr.token = token; bfr.bytes = bytes;
189 send_bfr(child_fd, &bfr, sizeof(bfr));
190 if( data && bytes ) send_bfr(child_fd, data, bytes);
195 int ForkBase::send_child(int64_t token, const void *data, int bytes)
197 lock("ForkBase::send_child");
198 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
199 bfr.token = token; bfr.bytes = bytes;
200 send_bfr(parent_fd, &bfr, sizeof(bfr));
201 if( data && bytes ) send_bfr(parent_fd, data, bytes);
206 ForkChild::ForkChild()
211 ForkChild::~ForkChild()
215 int ForkChild::handle_child()
217 printf("ForkChild::handle_child %d\n", __LINE__);
221 ForkParent::ForkParent()
227 ForkParent::~ForkParent()
231 // return 1 child is running
232 int ForkParent::is_running()
235 if( waitpid(pid, &status, WNOHANG) < 0 ) return 0;
236 return !kill(pid, 0) ? 1 : 0;
239 // Return -1,0,1 if dead,timeout,success
240 int ForkParent::parent_iteration()
242 int ret = read_parent(100);
244 if( ret < 0 ) parent_token = EXIT_CODE;
245 return handle_parent();
248 int ForkParent::handle_parent()
250 printf("ForkParent::handle_parent %d\n", __LINE__);
254 void ForkParent::start()
260 void ForkParent::stop()
263 send_child(EXIT_CODE, 0, 0);
265 while( --retry>=0 && is_running() ) usleep(100000);
266 if( retry < 0 ) kill(pid, SIGKILL);
271 void ForkParent::run()
273 while( !done && parent_iteration() >= 0 );