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