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