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