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>
56 delete [] parent_data;
57 if( child_fd >= 0 ) close(child_fd);
58 if( parent_fd >= 0 ) close(parent_fd);
61 int ForkChild::child_iteration()
63 int ret = read_child(100);
64 if( ret <= 0 ) return ret;
65 return handle_child();
68 void ForkParent::start_child()
70 lock->lock("ForkParent::new_child");
71 int sockets[2]; // Create the process & socket pair.
72 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
73 child_fd = sockets[0]; parent_fd = sockets[1];
75 if( !pid ) { // child process
76 BC_Signals::reset_locks();
77 BC_Signals::set_sighup_exit(1);
79 ForkChild *child = new_fork();
80 child->child_fd = child_fd;
81 child->parent_fd = parent_fd;
88 // Return -1 if the parent is dead
89 // Return 0 if timeout
90 // Return 1 if success
91 int ForkBase::read_timeout(int ms, int fd, void *data, int bytes)
94 struct timeval timeout_struct;
96 uint8_t *bp = (uint8_t *)data;
98 while( bytes_read < bytes ) {
99 timeout_struct.tv_sec = ms / 1000;
100 timeout_struct.tv_usec = (ms % 1000) * 1000;
103 int result = select(fd+1, &rfds, 0, 0, &timeout_struct);
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 || !is_running() ) return -1;
108 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(int ms)
125 int ret = read_timeout(ms, 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(1000, parent_fd, parent_data, parent_bytes);
136 //if( ret < 0 ) printf("read_parent timeout\n");
140 int ForkBase::read_child(int ms)
143 int ret = read_timeout(ms, child_fd, &bfr, sizeof(bfr));
145 child_token = bfr.token;
146 child_bytes = bfr.bytes;
147 if( child_bytes && child_allocated < child_bytes ) {
148 delete [] child_data;
149 child_data = new uint8_t[child_allocated = child_bytes];
152 ret = read_timeout(1000, child_fd, child_data, child_bytes);
154 //if( ret < 0 ) printf("read_child timeout\n");
158 int ForkBase::send_parent(int64_t token, const void *data, int bytes)
160 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
161 bfr.token = token; bfr.bytes = bytes;
162 write(child_fd, &bfr, sizeof(bfr));
163 if( data && bytes ) write(child_fd, data, bytes);
167 int ForkBase::send_child(int64_t token, const void *data, int bytes)
169 token_bfr_t bfr; memset(&bfr, 0, sizeof(bfr));
170 bfr.token = token; bfr.bytes = bytes;
171 write(parent_fd, &bfr, sizeof(bfr));
172 if( data && bytes ) write(parent_fd, data, bytes);
176 ForkChild::ForkChild()
181 ForkChild::~ForkChild()
185 int ForkChild::handle_child()
187 printf("ForkChild::handle_child %d\n", __LINE__);
191 ForkParent::ForkParent()
194 lock = new Mutex("ForkParent::lock");
198 ForkParent::~ForkParent()
203 // Return -1,0,1 if dead,timeout,success
204 int ForkParent::parent_iteration()
206 int ret = read_parent(100);
208 if( ret < 0 ) parent_token = EXIT_CODE;
209 return handle_parent();
212 int ForkParent::handle_parent()
214 printf("ForkParent::handle_parent %d\n", __LINE__);
218 void ForkParent::start()
224 void ForkParent::stop()
227 send_child(EXIT_CODE, 0, 0);
229 waitpid(pid, &status, 0);
234 void ForkParent::run()
236 while( !done && parent_iteration() >= 0 );