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 void ForkParent::start_child()
69 lock("ForkParent::new_child");
70 int sockets[2]; // Create the process & socket pair.
71 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
72 child_fd = sockets[0]; parent_fd = sockets[1];
75 if( !pid ) { // child process
76 ForkChild *child = new_fork();
77 child->child_fd = child_fd;
78 child->parent_fd = parent_fd;
87 // Return -1 if the parent is dead
88 // Return 0 if timeout
89 // Return 1 if success
90 int ForkBase::read_timeout(int64_t usec, int fd, void *data, int bytes)
93 struct timeval timeout_struct;
95 uint8_t *bp = (uint8_t *)data;
97 while( bytes_read < bytes ) {
98 timeout_struct.tv_sec = usec / 1000000;
99 timeout_struct.tv_usec = usec % 1000000;
102 int result = select(fd+1, &rfds, 0, 0, &timeout_struct);
103 if( result < 0 ) perror("read_timeout select");
104 if( result < 0 || !is_running() ) return -1;
105 if( !result && !bytes_read ) return 0;
106 int fragment = read(fd, bp + bytes_read, bytes - bytes_read);
107 if( fragment < 0 ) perror("read_timeout read");
108 if( fragment < 0 || !is_running() ) return -1;
109 if( fragment > 0 ) bytes_read += fragment;
114 // return 1 if child, or if parent && child is running
115 int ForkBase::is_running()
118 if( pid && waitpid(pid, &status, WNOHANG) < 0 ) return 0;
119 return !pid || !kill(pid, 0) ? 1 : 0;
122 int ForkBase::read_parent(int64_t usec)
125 int ret = read_timeout(usec, parent_fd, &bfr, sizeof(bfr));
127 parent_token = bfr.token;
128 parent_bytes = bfr.bytes;
129 if( parent_bytes && parent_allocated < parent_bytes ) {
130 delete [] parent_data;
131 parent_data = new uint8_t[parent_allocated = parent_bytes];
134 ret = read_timeout(1000000, parent_fd, parent_data, parent_bytes);
136 printf("read_parent timeout: %d\n", parent_fd);
144 int ForkBase::read_child(int64_t usec)
147 int ret = read_timeout(usec, child_fd, &bfr, sizeof(bfr));
149 child_token = bfr.token;
150 child_bytes = bfr.bytes;
151 if( child_bytes && child_allocated < child_bytes ) {
152 delete [] child_data;
153 child_data = new uint8_t[child_allocated = child_bytes];
156 ret = read_timeout(1000000, child_fd, child_data, child_bytes);
158 printf("read_child timeout: %d\n", child_fd);
166 void ForkBase::send_bfr(int fd, const void *bfr, int len)
169 for( int retries=10; --retries>=0 && (ret=write(fd, bfr, len)) < 0; ) {
170 printf("send_bfr socket(%d) write error: %d/%d bytes\n%m\n", fd,ret,len);
174 printf("send_bfr socket(%d) write short: %d/%d bytes\n%m\n", fd,ret,len);
177 int ForkBase::send_parent(int64_t token, const void *data, int bytes)
179 lock("ForkBase::send_parent");
180 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
181 bfr.token = token; bfr.bytes = bytes;
182 send_bfr(child_fd, &bfr, sizeof(bfr));
183 if( data && bytes ) send_bfr(child_fd, data, bytes);
188 int ForkBase::send_child(int64_t token, const void *data, int bytes)
190 lock("ForkBase::send_child");
191 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
192 bfr.token = token; bfr.bytes = bytes;
193 send_bfr(parent_fd, &bfr, sizeof(bfr));
194 if( data && bytes ) send_bfr(parent_fd, data, bytes);
199 ForkChild::ForkChild()
204 ForkChild::~ForkChild()
208 ForkParent::ForkParent()
214 ForkParent::~ForkParent()
218 // return 1 child is running
219 int ForkParent::is_running()
222 if( waitpid(pid, &status, WNOHANG) < 0 ) return 0;
223 return !kill(pid, 0) ? 1 : 0;
226 // Return -1,0,1 if dead,timeout,success
227 int ForkParent::parent_iteration()
229 int ret = read_parent(100);
231 if( ret < 0 ) parent_token = EXIT_CODE;
232 return handle_parent();
235 int ForkParent::handle_parent()
237 printf("ForkParent::handle_parent %d\n", __LINE__);
241 void ForkParent::start()
247 void ForkParent::stop()
250 send_child(EXIT_CODE, 0, 0);
252 while( --retry>=0 && is_running() ) usleep(100000);
253 if( retry < 0 ) kill(pid, SIGKILL);
258 void ForkParent::run()
260 while( !parent_done && parent_iteration() >= 0 );