8e87cb3d0678f4bf9319b9f55b7129c968b36454
[goodguy/history.git] / cinelerra-5.1 / cinelerra / forkbase.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "bcsignals.h"
23 #include "forkbase.h"
24 #include "mwindow.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/wait.h>
32 #include <unistd.h>
33
34 ForkBase::ForkBase()
35 {
36         pid = 0;
37         child = 0;
38
39         child_fd = -1;
40         child_token = 0;
41         child_bytes = 0;
42         child_allocated = 0;
43         child_data = 0;
44
45         parent_fd = -1;
46         parent_token = 0;
47         parent_bytes = 0;
48         parent_allocated = 0;
49         parent_data = 0;
50
51 }
52
53 ForkBase::~ForkBase()
54 {
55         delete [] child_data;
56         delete [] parent_data;
57         if( child_fd >= 0 ) close(child_fd);
58         if( parent_fd >= 0 ) close(parent_fd);
59 }
60
61 int ForkChild::child_iteration()
62 {
63         int ret = read_child(100);
64         if( ret <= 0 ) return ret;
65         return handle_child();
66 }
67
68 void ForkParent::start_child()
69 {
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];
74         pid = fork();
75         if( !pid ) {    // child process
76                 BC_Signals::reset_locks();
77                 BC_Signals::set_sighup_exit(1);
78                 TheList::reset();
79                 ForkChild *child = new_fork();
80                 child->child_fd = child_fd;
81                 child->parent_fd = parent_fd;
82                 child->run();
83                 _exit(0);
84         }
85         lock->unlock();
86 }
87
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)
92 {
93         fd_set rfds;
94         struct timeval timeout_struct;
95         int bytes_read = 0;
96         uint8_t *bp = (uint8_t *)data;
97
98         while( bytes_read < bytes ) {
99                 timeout_struct.tv_sec = ms / 1000;
100                 timeout_struct.tv_usec = (ms % 1000) * 1000;
101                 FD_ZERO(&rfds);
102                 FD_SET(fd, &rfds);
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;
109         }
110
111         return 1;
112 }
113
114 // return 1 if child, or if parent && child is running
115 int ForkBase::is_running()
116 {
117         int status = 0;
118         if( pid && waitpid(pid, &status, WNOHANG) < 0 ) return 0;
119         return !pid || !kill(pid, 0) ? 1 : 0;
120 }
121
122 int ForkBase::read_parent(int ms)
123 {
124         token_bfr_t bfr;
125         int ret = read_timeout(ms, parent_fd, &bfr, sizeof(bfr));
126         if( ret > 0 ) {
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];
132                 }
133                 if( parent_bytes )
134                         ret = read_timeout(1000, parent_fd, parent_data, parent_bytes);
135         }
136 //if( ret < 0 ) printf("read_parent timeout\n");
137         return ret;
138 }
139
140 int ForkBase::read_child(int ms)
141 {
142         token_bfr_t bfr;
143         int ret = read_timeout(ms, child_fd, &bfr, sizeof(bfr));
144         if( ret > 0 ) {
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];
150                 }
151                 if( child_bytes )
152                         ret = read_timeout(1000, child_fd, child_data, child_bytes);
153         }
154 //if( ret < 0 ) printf("read_child timeout\n");
155         return ret;
156 }
157
158 int ForkBase::send_parent(int64_t token, const void *data, int bytes)
159 {
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);
164         return 0;
165 }
166
167 int ForkBase::send_child(int64_t token, const void *data, int bytes)
168 {
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);
173         return 0;
174 }
175
176 ForkChild::ForkChild()
177 {
178         done = 0;
179 }
180
181 ForkChild::~ForkChild()
182 {
183 }
184
185 int ForkChild::handle_child()
186 {
187         printf("ForkChild::handle_child %d\n", __LINE__);
188         return 0;
189 }
190
191 ForkParent::ForkParent()
192  : Thread(1, 0, 0)
193 {
194         lock = new Mutex("ForkParent::lock");
195         done = -1;
196 }
197
198 ForkParent::~ForkParent()
199 {
200         delete lock;
201 }
202
203 // Return -1,0,1 if dead,timeout,success
204 int ForkParent::parent_iteration()
205 {
206         int ret = read_parent(100);
207         if( !ret ) return 0;
208         if( ret < 0 ) parent_token = EXIT_CODE;
209         return handle_parent();
210 }
211
212 int ForkParent::handle_parent()
213 {
214         printf("ForkParent::handle_parent %d\n", __LINE__);
215         return 0;
216 }
217
218 void ForkParent::start()
219 {
220         done = 0;
221         Thread::start();
222 }
223
224 void ForkParent::stop()
225 {
226         if( is_running() ) {
227                 send_child(EXIT_CODE, 0, 0);
228                 int status = 0;
229                 waitpid(pid, &status, 0);
230         }
231         join();
232 }
233
234 void ForkParent::run()
235 {
236         while( !done && parent_iteration() >= 0 );
237         done = 1;
238 }
239