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