removed assumption that settings values would be numbers. cleaned up the code some...
[OpenSRF.git] / src / libopensrf / osrf_prefork.c
1 #include <opensrf/osrf_prefork.h>
2 #include <opensrf/osrf_app_session.h>
3 #include <opensrf/osrf_application.h>
4 #include <signal.h>
5
6 /* true if we just deleted a child.  This will allow us to make sure we're
7         not trying to use freed memory */
8 int child_dead;
9
10 int main();
11 void sigchld_handler( int sig );
12
13 int osrf_prefork_run(char* appname) {
14
15         if(!appname) {
16                 osrfLogError( OSRF_LOG_MARK, "osrf_prefork_run requires an appname to run!");
17                 return -1;
18         }
19
20         set_proc_title( "OpenSRF Listener [%s]", appname );
21
22         int maxr = 1000; 
23         int maxc = 10;
24         int minc = 3;
25     int kalive = 5;
26
27         osrfLogInfo( OSRF_LOG_MARK, "Loading config in osrf_forker for app %s", appname);
28
29         char* max_req = osrf_settings_host_value("/apps/%s/unix_config/max_requests", appname);
30         char* min_children = osrf_settings_host_value("/apps/%s/unix_config/min_children", appname);
31         char* max_children = osrf_settings_host_value("/apps/%s/unix_config/max_children", appname);
32         char* keepalive = osrf_settings_host_value("/apps/%s/keepalive", appname);
33
34         if(!keepalive) osrfLogWarning( OSRF_LOG_MARK, "Keepalive is not defined, assuming %d", kalive);
35         else kalive = atoi(keepalive);
36
37         if(!max_req) osrfLogWarning( OSRF_LOG_MARK, "Max requests not defined, assuming %d", maxr);
38         else maxr = atoi(max_req);
39
40         if(!min_children) osrfLogWarning( OSRF_LOG_MARK, "Min children not defined, assuming %d", minc);
41         else minc = atoi(min_children);
42
43         if(!max_children) osrfLogWarning( OSRF_LOG_MARK, "Max children not defined, assuming %d", maxc);
44         else maxc = atoi(max_children);
45
46     free(keepalive);
47         free(max_req);
48         free(min_children);
49         free(max_children);
50         /* --------------------------------------------------- */
51
52         char* resc = va_list_to_string("%s_listener", appname);
53
54         if(!osrfSystemBootstrapClientResc( NULL, NULL, resc )) {
55                 osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
56                 free(resc);
57                 return -1;
58         }
59
60         free(resc);
61
62         prefork_simple* forker = prefork_simple_init(
63                 osrfSystemGetTransportClient(), maxr, minc, maxc);
64
65         if(forker == NULL) {
66                 osrfLogError( OSRF_LOG_MARK, "osrf_prefork_run() failed to create prefork_simple object");
67                 return -1;
68         }
69
70         forker->appname = strdup(appname);
71         forker->keepalive       = kalive;
72
73         prefork_launch_children(forker);
74
75         osrf_prefork_register_routers(appname);
76         
77         osrfLogInfo( OSRF_LOG_MARK, "Launching osrf_forker for app %s", appname);
78         prefork_run(forker);
79         
80         osrfLogWarning( OSRF_LOG_MARK, "prefork_run() retuned - how??");
81         prefork_free(forker);
82         return 0;
83
84 }
85
86 void osrf_prefork_register_routers( char* appname ) {
87
88         osrfStringArray* arr = osrfNewStringArray(4);
89
90         int c = osrfConfigGetValueList( NULL, arr, "/routers/router" );
91         char* routerName = osrfConfigGetValue( NULL, "/router_name" );
92         transport_client* client = osrfSystemGetTransportClient();
93
94         osrfLogInfo( OSRF_LOG_MARK, "router name is %s and we have %d routers to connect to", routerName, c );
95
96         while( c ) {
97                 char* domain = osrfStringArrayGetString(arr, --c);
98                 if(domain) {
99
100                         char* jid = va_list_to_string( "%s@%s/router", routerName, domain );
101                         osrfLogInfo( OSRF_LOG_MARK, "Registering with router %s", jid );
102
103                         transport_message* msg = message_init("registering", NULL, NULL, jid, NULL );
104                         message_set_router_info( msg, NULL, NULL, appname, "register", 0 );
105
106                         client_send_message( client, msg );
107                         message_free( msg );
108                         free(jid);
109                 }
110         }
111
112         free(routerName);
113         osrfStringArrayFree(arr);
114 }
115
116 int prefork_child_init_hook(prefork_child* child) {
117
118         if(!child) return -1;
119         osrfLogDebug( OSRF_LOG_MARK, "Child init hook for child %d", child->pid);
120         char* resc = va_list_to_string("%s_drone",child->appname);
121
122    /* if we're a source-client, tell the logger now that we're a new process*/
123    char* isclient = osrfConfigGetValue(NULL, "/client");
124    if( isclient && !strcasecmp(isclient,"true") )
125       osrfLogSetIsClient(1);
126    free(isclient);
127
128
129         /* we want to remove traces of our parents socket connection 
130          * so we can have our own */
131         osrfSystemIgnoreTransportClient();
132
133         if(!osrfSystemBootstrapClientResc( NULL, NULL, resc)) {
134                 osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
135                 free(resc);
136                 return -1;
137         }
138
139         free(resc);
140
141         if( ! osrfAppRunChildInit(child->appname) ) {
142                 osrfLogDebug(OSRF_LOG_MARK, "Prefork child_init succeeded\n");
143         } else {
144                 osrfLogError(OSRF_LOG_MARK, "Prefork child_init failed\n");
145                 return -1;
146         }
147
148         set_proc_title( "OpenSRF Drone [%s]", child->appname );
149         return 0;
150 }
151
152 void prefork_child_process_request(prefork_child* child, char* data) {
153         if( !child ) return;
154
155         transport_client* client = osrfSystemGetTransportClient();
156
157         if(!client_connected(client)) {
158                 osrfSystemIgnoreTransportClient();
159                 osrfLogWarning(OSRF_LOG_MARK, "Reconnecting child to opensrf after disconnect...");
160                 if(!osrf_system_bootstrap_client(NULL, NULL)) {
161                         osrfLogError( OSRF_LOG_MARK, 
162                                 "Unable to bootstrap client in prefork_child_process_request()");
163                         sleep(1);
164          osrf_prefork_child_exit(child);
165                 }
166         }
167
168         /* construct the message from the xml */
169         transport_message* msg = new_message_from_xml( data );
170
171         osrfAppSession* session = osrf_stack_transport_handler(msg, child->appname);
172         if(!session) return;
173
174         if( session->stateless && session->state != OSRF_SESSION_CONNECTED ) {
175                 osrfAppSessionFree( session );
176                 return;
177         }
178
179         osrfLogDebug( OSRF_LOG_MARK, "Entering keepalive loop for session %s", session->session_id );
180         int keepalive = child->keepalive;
181         int retval;
182         int recvd;
183         time_t start;
184         time_t end;
185
186         while(1) {
187
188                 osrfLogDebug(OSRF_LOG_MARK, 
189                                 "osrf_prefork calling queue_wait [%d] in keepalive loop", keepalive);
190                 start           = time(NULL);
191                 retval  = osrf_app_session_queue_wait(session, keepalive, &recvd);
192                 end             = time(NULL);
193
194                 osrfLogDebug(OSRF_LOG_MARK, "Data received == %d", recvd);
195
196                 if(retval) {
197                         osrfLogError(OSRF_LOG_MARK, "queue-wait returned non-success %d", retval);
198                         break;
199                 }
200
201                 /* see if the client disconnected from us */
202                 if(session->state != OSRF_SESSION_CONNECTED) break;
203
204                 /* if no data was reveived within the timeout interval */
205                 if( !recvd && (end - start) >= keepalive ) {
206                         osrfLogInfo(OSRF_LOG_MARK, "No request was received in %d seconds, exiting stateful session", keepalive);
207                         osrfAppSessionStatus( 
208                                         session, 
209                                         OSRF_STATUS_TIMEOUT, 
210                                         "osrfConnectStatus", 
211                                         0, "Disconnected on timeout" );
212
213                         break;
214                 }
215         }
216
217         osrfLogDebug( OSRF_LOG_MARK, "Exiting keepalive loop for session %s", session->session_id );
218         osrfAppSessionFree( session );
219         return;
220 }
221
222
223 prefork_simple*  prefork_simple_init( transport_client* client, 
224                 int max_requests, int min_children, int max_children ) {
225
226         if( min_children > max_children ) {
227                 osrfLogError( OSRF_LOG_MARK,  "min_children (%d) is greater "
228                                 "than max_children (%d)", min_children, max_children );
229                 return NULL;
230         }
231
232         if( max_children > ABS_MAX_CHILDREN ) {
233                 osrfLogError( OSRF_LOG_MARK,  "max_children (%d) is greater than ABS_MAX_CHILDREN (%d)",
234                                 max_children, ABS_MAX_CHILDREN );
235                 return NULL;
236         }
237
238         osrfLogInfo(OSRF_LOG_MARK, "Prefork launching child with max_request=%d,"
239                 "min_children=%d, max_children=%d", max_requests, min_children, max_children );
240
241         /* flesh out the struct */
242         prefork_simple* prefork = (prefork_simple*) safe_malloc(sizeof(prefork_simple));        
243         prefork->max_requests = max_requests;
244         prefork->min_children = min_children;
245         prefork->max_children = max_children;
246         prefork->first_child = NULL;
247         prefork->connection = client;
248
249         return prefork;
250 }
251
252 prefork_child*  launch_child( prefork_simple* forker ) {
253
254         pid_t pid;
255         int data_fd[2];
256         int status_fd[2];
257
258         /* Set up the data pipes and add the child struct to the parent */
259         if( pipe(data_fd) < 0 ) { /* build the data pipe*/
260                 osrfLogError( OSRF_LOG_MARK,  "Pipe making error" );
261                 return NULL;
262         }
263
264         if( pipe(status_fd) < 0 ) {/* build the status pipe */
265                 osrfLogError( OSRF_LOG_MARK,  "Pipe making error" );
266                 return NULL;
267         }
268
269         osrfLogInternal( OSRF_LOG_MARK,  "Pipes: %d %d %d %d", data_fd[0], data_fd[1], status_fd[0], status_fd[1] );
270         prefork_child* child = prefork_child_init( forker->max_requests, data_fd[0], 
271                         data_fd[1], status_fd[0], status_fd[1] );
272
273         child->appname = strdup(forker->appname);
274         child->keepalive = forker->keepalive;
275
276
277         add_prefork_child( forker, child );
278
279         if( (pid=fork()) < 0 ) {
280                 osrfLogError( OSRF_LOG_MARK,  "Forking Error" );
281                 return NULL;
282         }
283
284         if( pid > 0 ) {  /* parent */
285
286                 signal(SIGCHLD, sigchld_handler);
287                 (forker->current_num_children)++;
288                 child->pid = pid;
289
290                 osrfLogDebug( OSRF_LOG_MARK,  "Parent launched %d", pid );
291                 /* *no* child pipe FD's can be closed or the parent will re-use fd's that
292                         the children are currently using */
293                 return child;
294         }
295
296         else { /* child */
297
298                 osrfLogInternal( OSRF_LOG_MARK, "I am  new child with read_data_fd = %d and write_status_fd = %d",
299                         child->read_data_fd, child->write_status_fd );
300
301                 child->pid = getpid();
302                 close( child->write_data_fd );
303                 close( child->read_status_fd );
304
305                 /* do the initing */
306                 if( prefork_child_init_hook(child) == -1 ) {
307                         osrfLogError(OSRF_LOG_MARK, 
308                                 "Forker child going away because we could not connect to OpenSRF...");
309          osrf_prefork_child_exit(child);
310                 }
311
312                 prefork_child_wait( child );
313       osrf_prefork_child_exit(child); /* just to be sure */
314          }
315         return NULL;
316 }
317
318 void osrf_prefork_child_exit(prefork_child* child) {
319    osrfAppRunExitCode();
320    exit(0);
321 }
322
323 void prefork_launch_children( prefork_simple* forker ) {
324         if(!forker) return;
325         int c = 0;
326         while( c++ < forker->min_children )
327                 launch_child( forker );
328 }
329
330
331 void sigchld_handler( int sig ) {
332         signal(SIGCHLD, sigchld_handler);
333         child_dead = 1;
334 }
335
336
337 void reap_children( prefork_simple* forker ) {
338
339         pid_t child_pid;
340         int status;
341
342         while( (child_pid=waitpid(-1,&status,WNOHANG)) > 0) 
343                 del_prefork_child( forker, child_pid ); 
344
345         /* replenish */
346         while( forker->current_num_children < forker->min_children ) 
347                 launch_child( forker );
348
349         child_dead = 0;
350 }
351
352 void prefork_run(prefork_simple* forker) {
353
354         if( forker->first_child == NULL )
355                 return;
356
357         transport_message* cur_msg = NULL;
358
359
360         while(1) {
361
362                 if( forker->first_child == NULL ) {/* no more children */
363                         osrfLogWarning( OSRF_LOG_MARK, "No more children..." );
364                         return;
365                 }
366
367                 osrfLogDebug( OSRF_LOG_MARK, "Forker going into wait for data...");
368                 cur_msg = client_recv( forker->connection, -1 );
369
370                 //fprintf(stderr, "Got Data %f\n", get_timestamp_millis() );
371
372                 if( cur_msg == NULL ) continue;
373
374                 int honored = 0;        /* true if we've serviced the request */
375                 int no_recheck = 0;
376
377                 while( ! honored ) {
378
379                         if(!no_recheck) check_children( forker, 0 ); 
380                         no_recheck = 0;
381
382                         osrfLogDebug( OSRF_LOG_MARK,  "Server received inbound data" );
383                         int k;
384                         prefork_child* cur_child = forker->first_child;
385
386                         /* Look for an available child */
387                         for( k = 0; k < forker->current_num_children; k++ ) {
388
389                                 osrfLogInternal( OSRF_LOG_MARK, "Searching for available child. cur_child->pid = %d", cur_child->pid );
390                                 osrfLogInternal( OSRF_LOG_MARK, "Current num children %d and loop %d", forker->current_num_children, k);
391                         
392                                 if( cur_child->available ) {
393                                         osrfLogDebug( OSRF_LOG_MARK,  "forker sending data to %d", cur_child->pid );
394
395                                         message_prepare_xml( cur_msg );
396                                         char* data = cur_msg->msg_xml;
397                                         if( ! data || strlen(data) < 1 ) break;
398
399                                         cur_child->available = 0;
400                                         osrfLogInternal( OSRF_LOG_MARK,  "Writing to child fd %d", cur_child->write_data_fd );
401
402                                         int written = 0;
403                                         //fprintf(stderr, "Writing Data %f\n", get_timestamp_millis() );
404                                         if( (written = write( cur_child->write_data_fd, data, strlen(data) + 1 )) < 0 ) {
405                                                 osrfLogWarning( OSRF_LOG_MARK, "Write returned error %d", errno);
406                                                 cur_child = cur_child->next;
407                                                 continue;
408                                         }
409
410                                         //fprintf(stderr, "Wrote %d bytes to child\n", written);
411
412                                         forker->first_child = cur_child->next;
413                                         honored = 1;
414                                         break;
415                                 } else 
416                                         cur_child = cur_child->next;
417                         } 
418
419                         /* if none available, add a new child if we can */
420                         if( ! honored ) {
421                                 osrfLogDebug( OSRF_LOG_MARK, "Not enough children, attempting to add...");
422
423                                 if( forker->current_num_children < forker->max_children ) {
424                                         osrfLogDebug( OSRF_LOG_MARK,  "Launching new child with current_num = %d",
425                                                         forker->current_num_children );
426
427                                         prefork_child* new_child = launch_child( forker );
428                     if( new_child ) {
429
430                                             message_prepare_xml( cur_msg );
431                                             char* data = cur_msg->msg_xml;
432
433                         if( data ) {
434                             int len = strlen(data);
435
436                             if( len > 0 ) {
437                                                     new_child->available = 0;
438                                                     osrfLogDebug( OSRF_LOG_MARK,  "Writing to new child fd %d : pid %d", 
439                                                                 new_child->write_data_fd, new_child->pid );
440         
441                                                     if( write( new_child->write_data_fd, data, len + 1 ) >= 0 ) {
442                                                         forker->first_child = new_child->next;
443                                                         honored = 1;
444                                 }
445                             }
446                         }
447                     }
448
449                                 }
450                         }
451
452                         if( !honored ) {
453                                 osrfLogWarning( OSRF_LOG_MARK,  "No children available, waiting...");
454
455                                 check_children( forker, 1 );  /* non-poll version */
456                                 /* tell the loop no to call check_children again, since we're calling it now */
457                                 no_recheck = 1;
458                         }
459
460                         if( child_dead )
461                                 reap_children(forker);
462
463
464                         //fprintf(stderr, "Parent done with request %f\n", get_timestamp_millis() );
465
466                 } // honored?
467
468                 message_free( cur_msg );
469
470         } /* top level listen loop */
471
472 }
473
474
475 /** XXX Add a flag which tells select() to wait forever on children
476  * in the best case, this will be faster than calling usleep(x), and
477  * in the worst case it won't be slower and will do less logging...
478  */
479
480 void check_children( prefork_simple* forker, int forever ) {
481
482         //check_begin:
483
484         int select_ret;
485         fd_set read_set;
486         FD_ZERO(&read_set);
487         int max_fd = 0;
488         int n;
489
490
491         if( child_dead )
492                 reap_children(forker);
493
494         prefork_child* cur_child = forker->first_child;
495
496         int i;
497         for( i = 0; i!= forker->current_num_children; i++ ) {
498
499                 if( cur_child->read_status_fd > max_fd )
500                         max_fd = cur_child->read_status_fd;
501                 FD_SET( cur_child->read_status_fd, &read_set );
502                 cur_child = cur_child->next;
503         }
504
505         FD_CLR(0,&read_set);/* just to be sure */
506
507         if( forever ) {
508                 osrfLogWarning(OSRF_LOG_MARK, "We have no children available - waiting for one to show up...");
509
510                 if( (select_ret=select( max_fd + 1 , &read_set, NULL, NULL, NULL)) == -1 ) {
511                         osrfLogWarning( OSRF_LOG_MARK,  "Select returned error %d on check_children", errno );
512                 }
513                 osrfLogInfo(OSRF_LOG_MARK, "select() completed after waiting on children to become available");
514
515         } else {
516
517                 struct timeval tv;
518                 tv.tv_sec       = 0;
519                 tv.tv_usec      = 0;
520         
521                 if( (select_ret=select( max_fd + 1 , &read_set, NULL, NULL, &tv)) == -1 ) {
522                         osrfLogWarning( OSRF_LOG_MARK,  "Select returned error %d on check_children", errno );
523                 }
524         }
525
526         if( select_ret == 0 )
527                 return;
528
529         /* see if one of a child has told us it's done */
530         cur_child = forker->first_child;
531         int j;
532         int num_handled = 0;
533         for( j = 0; j!= forker->current_num_children && num_handled < select_ret ; j++ ) {
534
535                 if( FD_ISSET( cur_child->read_status_fd, &read_set ) ) {
536                         //printf( "Server received status from a child %d\n", cur_child->pid );
537                         osrfLogDebug( OSRF_LOG_MARK,  "Server received status from a child %d", cur_child->pid );
538
539                         num_handled++;
540
541                         /* now suck off the data */
542                         char buf[64];
543                         osrf_clearbuf( buf, sizeof(buf) );
544                         if( (n=read(cur_child->read_status_fd, buf, 63))  < 0 ) {
545                                 osrfLogWarning( OSRF_LOG_MARK, "Read error after select in child status read with errno %d", errno);
546                         }
547
548                         osrfLogDebug( OSRF_LOG_MARK,  "Read %d bytes from status buffer: %s", n, buf );
549                         cur_child->available = 1;
550                 }
551                 cur_child = cur_child->next;
552         } 
553
554 }
555
556
557 void prefork_child_wait( prefork_child* child ) {
558
559         int i,n;
560         growing_buffer* gbuf = buffer_init( READ_BUFSIZE );
561         char buf[READ_BUFSIZE];
562         osrf_clearbuf( buf, sizeof(buf) );
563
564         for( i = 0; i < child->max_requests; i++ ) {
565
566                 n = -1;
567                 int gotdata = 0;
568                 clr_fl(child->read_data_fd, O_NONBLOCK );
569
570                 while( (n=read(child->read_data_fd, buf, READ_BUFSIZE-1)) > 0 ) {
571                         osrfLogDebug(OSRF_LOG_MARK, "Prefork child read %d bytes of data", n);
572                         if(!gotdata)
573                                 set_fl(child->read_data_fd, O_NONBLOCK );
574                         buffer_add( gbuf, buf );
575                         osrf_clearbuf( buf, sizeof(buf) );
576                         gotdata = 1;
577                 }
578
579                 if( errno == EAGAIN ) n = 0;
580
581       if( errno == EPIPE ) {
582          osrfLogDebug(OSRF_LOG_MARK, "C child attempted read on broken pipe, exiting...");
583          break;
584       }
585
586                 if( n < 0 ) {
587                         osrfLogWarning( OSRF_LOG_MARK,  "Prefork child read returned error with errno %d", errno );
588                         break;
589
590                 } else if( gotdata ) {
591                         osrfLogDebug(OSRF_LOG_MARK, "Prefork child got a request.. processing..");
592                         prefork_child_process_request(child, gbuf->buf);
593                         buffer_reset( gbuf );
594                 }
595
596                 if( i < child->max_requests - 1 ) 
597                         write( child->write_status_fd, "available" /*less than 64 bytes*/, 9 );
598         }
599
600         buffer_free(gbuf);
601
602         osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%ld]", 
603                         child->max_requests, i, (long) getpid() );
604
605    osrf_prefork_child_exit(child); /* just to be sure */
606 }
607
608
609 void add_prefork_child( prefork_simple* forker, prefork_child* child ) {
610         
611         if( forker->first_child == NULL ) {
612                 forker->first_child = child;
613                 child->next = child;
614                 return;
615         }
616
617         /* we put the child in as the last because, regardless, 
618                 we have to do the DLL splice dance, and this is the
619            simplest way */
620
621         prefork_child* start_child = forker->first_child;
622         while(1) {
623                 if( forker->first_child->next == start_child ) 
624                         break;
625                 forker->first_child = forker->first_child->next;
626         }
627
628         /* here we know that forker->first_child is the last element 
629                 in the list and start_child is the first.  Insert the
630                 new child between them*/
631
632         forker->first_child->next = child;
633         child->next = start_child;
634         return;
635 }
636
637 prefork_child* find_prefork_child( prefork_simple* forker, pid_t pid ) {
638
639         if( forker->first_child == NULL ) { return NULL; }
640         prefork_child* start_child = forker->first_child;
641         do {
642                 if( forker->first_child->pid == pid ) 
643                         return forker->first_child;
644         } while( (forker->first_child = forker->first_child->next) != start_child );
645
646         return NULL;
647 }
648
649
650 void del_prefork_child( prefork_simple* forker, pid_t pid ) { 
651
652         if( forker->first_child == NULL ) { return; }
653
654         (forker->current_num_children)--;
655         osrfLogDebug( OSRF_LOG_MARK, "Deleting Child: %d", pid );
656
657         prefork_child* start_child = forker->first_child; /* starting point */
658         prefork_child* cur_child        = start_child; /* current pointer */
659         prefork_child* prev_child       = start_child; /* the trailing pointer */
660
661         /* special case where there is only one in the list */
662         if( start_child == start_child->next ) {
663                 if( start_child->pid == pid ) {
664                         forker->first_child = NULL;
665
666                         close( start_child->read_data_fd );
667                         close( start_child->write_data_fd );
668                         close( start_child->read_status_fd );
669                         close( start_child->write_status_fd );
670
671                         prefork_child_free( start_child );
672                 }
673                 return;
674         }
675
676
677         /* special case where the first item in the list needs to be removed */
678         if( start_child->pid == pid ) { 
679
680                 /* find the last one so we can remove the start_child */
681                 do { 
682                         prev_child = cur_child;
683                         cur_child = cur_child->next;
684                 }while( cur_child != start_child );
685
686                 /* now cur_child == start_child */
687                 prev_child->next = cur_child->next;
688                 forker->first_child = prev_child;
689
690                 close( cur_child->read_data_fd );
691                 close( cur_child->write_data_fd );
692                 close( cur_child->read_status_fd );
693                 close( cur_child->write_status_fd );
694
695                 prefork_child_free( cur_child );
696                 return;
697         } 
698
699         do {
700                 prev_child = cur_child;
701                 cur_child = cur_child->next;
702
703                 if( cur_child->pid == pid ) {
704                         prev_child->next = cur_child->next;
705
706                         close( cur_child->read_data_fd );
707                         close( cur_child->write_data_fd );
708                         close( cur_child->read_status_fd );
709                         close( cur_child->write_status_fd );
710
711                         prefork_child_free( cur_child );
712                         return;
713                 }
714
715         } while(cur_child != start_child);
716 }
717
718
719
720
721 prefork_child* prefork_child_init( 
722         int max_requests, int read_data_fd, int write_data_fd, 
723         int read_status_fd, int write_status_fd ) {
724
725         prefork_child* child = (prefork_child*) safe_malloc(sizeof(prefork_child));
726         child->max_requests             = max_requests;
727         child->read_data_fd             = read_data_fd;
728         child->write_data_fd            = write_data_fd;
729         child->read_status_fd   = read_status_fd;
730         child->write_status_fd  = write_status_fd;
731         child->available                        = 1;
732
733         return child;
734 }
735
736
737 int prefork_free( prefork_simple* prefork ) {
738         
739         while( prefork->first_child != NULL ) {
740                 osrfLogInfo( OSRF_LOG_MARK,  "Killing children and sleeping 1 to reap..." );
741                 kill( 0,        SIGKILL );
742                 sleep(1);
743         }
744
745         client_free(prefork->connection);
746         free(prefork->appname);
747         free( prefork );
748         return 1;
749 }
750
751 int prefork_child_free( prefork_child* child ) { 
752         free(child->appname);
753         close(child->read_data_fd);
754         close(child->write_status_fd);
755         free( child ); 
756         return 1;
757 }
758