8 #include <sys/select.h>
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"
18 #define READ_BUFSIZE 1024
19 #define ABS_MAX_CHILDREN 256
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. */
31 struct prefork_child_struct* first_child;
32 transport_client* connection;
35 struct prefork_child_struct {
46 struct prefork_child_struct* next;
49 typedef struct prefork_child_struct prefork_child;
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 );
58 //static prefork_child* find_prefork_child( prefork_simple* forker, pid_t pid );
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 );
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* );
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;
80 static void sigchld_handler( int sig );
82 int osrf_prefork_run(const char* appname) {
85 osrfLogError( OSRF_LOG_MARK, "osrf_prefork_run requires an appname to run!");
89 set_proc_title( "OpenSRF Listener [%s]", appname );
96 osrfLogInfo( OSRF_LOG_MARK, "Loading config in osrf_forker for app %s", appname);
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);
103 if(!keepalive) osrfLogWarning( OSRF_LOG_MARK, "Keepalive is not defined, assuming %d", kalive);
104 else kalive = atoi(keepalive);
106 if(!max_req) osrfLogWarning( OSRF_LOG_MARK, "Max requests not defined, assuming %d", maxr);
107 else maxr = atoi(max_req);
109 if(!min_children) osrfLogWarning( OSRF_LOG_MARK,
110 "Min children not defined, assuming %d", minc);
111 else minc = atoi(min_children);
113 if(!max_children) osrfLogWarning( OSRF_LOG_MARK,
114 "Max children not defined, assuming %d", maxc);
115 else maxc = atoi(max_children);
121 /* --------------------------------------------------- */
123 char* resc = va_list_to_string("%s_listener", appname);
125 if(!osrfSystemBootstrapClientResc( NULL, NULL, resc )) {
126 osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
133 prefork_simple forker;
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" );
141 // Finish initializing the prefork_simple
142 forker.appname = strdup(appname);
143 forker.keepalive = kalive;
145 // Spawn the children
146 prefork_launch_children( &forker );
148 // Tell the router that you're open for business
149 osrf_prefork_register_routers(appname);
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 );
155 osrfLogWarning( OSRF_LOG_MARK, "prefork_run() retuned - how??");
156 prefork_clear( &forker );
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.
166 Tell the router that you're open for business so that it can route requests to you.
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();
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 );
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 );
187 /** parses a single "complex" router configuration chunk */
188 static void osrf_prefork_parse_router_chunk(const char* appname, jsonObject* routerChunk) {
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",
196 if( services && services->type == JSON_HASH ) {
197 osrfLogDebug(OSRF_LOG_MARK, "investigating router information...");
198 const jsonObject* service_obj = jsonObjectGetKeyConst(services, "service");
200 ; // do nothing (shouldn't happen)
201 else if( JSON_ARRAY == service_obj->type ) {
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);
209 else if( JSON_STRING == service_obj->type ) {
210 if( !strcmp(appname, jsonObjectGetString( service_obj )) )
211 osrf_prefork_send_router_registration(appname, routerName, domain);
214 osrf_prefork_send_router_registration(appname, routerName, domain);
218 static void osrf_prefork_register_routers( const char* appname ) {
220 jsonObject* routerInfo = osrfConfigGetValueObject(NULL, "/routers/router");
223 for(i = 0; i < routerInfo->size; i++) {
224 jsonObject* routerChunk = jsonObjectGetIndex(routerInfo, i);
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",
232 osrf_prefork_send_router_registration(appname, routerName, domain);
235 osrf_prefork_parse_router_chunk(appname, routerChunk);
240 static int prefork_child_init_hook(prefork_child* child) {
242 if(!child) return -1;
243 osrfLogDebug( OSRF_LOG_MARK, "Child init hook for child %d", child->pid);
245 osrfSystemInitCache();
246 char* resc = va_list_to_string("%s_drone",child->appname);
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);
254 /* we want to remove traces of our parents socket connection
255 * so we can have our own */
256 osrfSystemIgnoreTransportClient();
258 if(!osrfSystemBootstrapClientResc( NULL, NULL, resc)) {
259 osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap client for osrf_prefork_run()");
266 if( ! osrfAppRunChildInit(child->appname) ) {
267 osrfLogDebug(OSRF_LOG_MARK, "Prefork child_init succeeded\n");
269 osrfLogError(OSRF_LOG_MARK, "Prefork child_init failed\n");
273 set_proc_title( "OpenSRF Drone [%s]", child->appname );
277 static void prefork_child_process_request(prefork_child* child, char* data) {
280 transport_client* client = osrfSystemGetTransportClient();
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()");
289 osrf_prefork_child_exit(child);
293 /* construct the message from the xml */
294 transport_message* msg = new_message_from_xml( data );
296 osrfAppSession* session = osrf_stack_transport_handler(msg, child->appname);
299 if( session->stateless && session->state != OSRF_SESSION_CONNECTED ) {
300 osrfAppSessionFree( session );
304 osrfLogDebug( OSRF_LOG_MARK, "Entering keepalive loop for session %s", session->session_id );
305 int keepalive = child->keepalive;
313 osrfLogDebug(OSRF_LOG_MARK,
314 "osrf_prefork calling queue_wait [%d] in keepalive loop", keepalive);
316 retval = osrf_app_session_queue_wait(session, keepalive, &recvd);
319 osrfLogDebug(OSRF_LOG_MARK, "Data received == %d", recvd);
322 osrfLogError(OSRF_LOG_MARK, "queue-wait returned non-success %d", retval);
326 /* see if the client disconnected from us */
327 if(session->state != OSRF_SESSION_CONNECTED) break;
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(
337 0, "Disconnected on timeout" );
343 osrfLogDebug( OSRF_LOG_MARK, "Exiting keepalive loop for session %s", session->session_id );
344 osrfAppSessionFree( session );
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).
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).
358 static int prefork_simple_init( prefork_simple* prefork, transport_client* client,
359 int max_requests, int min_children, int max_children ) {
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 );
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 );
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 );
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;
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;
393 static prefork_child* launch_child( prefork_simple* forker ) {
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" );
405 if( pipe(status_fd) < 0 ) {/* build the status pipe */
406 osrfLogError( OSRF_LOG_MARK, "Pipe making error" );
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] );
415 child->appname = strdup(forker->appname);
416 child->keepalive = forker->keepalive;
419 add_prefork_child( forker, child );
421 if( (pid=fork()) < 0 ) {
422 osrfLogError( OSRF_LOG_MARK, "Forking Error" );
426 if( pid > 0 ) { /* parent */
428 signal(SIGCHLD, sigchld_handler);
429 (forker->current_num_children)++;
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 */
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 );
444 child->pid = getpid();
445 close( child->write_data_fd );
446 close( child->read_status_fd );
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);
455 prefork_child_wait( child );
456 osrf_prefork_child_exit(child); /* just to be sure */
461 static void osrf_prefork_child_exit(prefork_child* child) {
462 osrfAppRunExitCode();
466 static void prefork_launch_children( prefork_simple* forker ) {
469 while( c++ < forker->min_children )
470 launch_child( forker );
474 static void sigchld_handler( int sig ) {
475 signal(SIGCHLD, sigchld_handler);
480 void reap_children( prefork_simple* forker ) {
485 while( (child_pid=waitpid(-1,&status,WNOHANG)) > 0)
486 del_prefork_child( forker, child_pid );
489 while( forker->current_num_children < forker->min_children )
490 launch_child( forker );
495 static void prefork_run(prefork_simple* forker) {
497 if( forker->first_child == NULL )
500 transport_message* cur_msg = NULL;
505 if( forker->first_child == NULL ) {/* no more children */
506 osrfLogWarning( OSRF_LOG_MARK, "No more children..." );
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 );
514 if( cur_msg == NULL )
515 continue; // Error? Interrupted by a signal?
517 int honored = 0; /* will be set to true when we service the request */
523 check_children( forker, 0 );
526 osrfLogDebug( OSRF_LOG_MARK, "Server received inbound data" );
528 prefork_child* cur_child = forker->first_child;
530 /* Look for an available child */
531 for( k = 0; k < forker->current_num_children; k++ ) {
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);
538 if( cur_child->available ) {
539 osrfLogDebug( OSRF_LOG_MARK, "forker sending data to %d", cur_child->pid );
541 message_prepare_xml( cur_msg );
542 char* data = cur_msg->msg_xml;
543 if( ! data || strlen(data) < 1 ) break;
545 cur_child->available = 0;
546 osrfLogInternal( OSRF_LOG_MARK, "Writing to child fd %d",
547 cur_child->write_data_fd );
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;
556 forker->first_child = cur_child->next;
560 cur_child = cur_child->next;
563 /* if none available, add a new child if we can */
565 osrfLogDebug( OSRF_LOG_MARK, "Not enough children, attempting to add...");
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 );
571 prefork_child* new_child = launch_child( forker );
574 message_prepare_xml( cur_msg );
575 char* data = cur_msg->msg_xml;
578 int len = strlen(data);
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 );
585 if( write( new_child->write_data_fd, data, len + 1 ) >= 0 ) {
586 forker->first_child = new_child->next;
597 osrfLogWarning( OSRF_LOG_MARK, "No children available, waiting...");
599 check_children( forker, 1 ); /* non-poll version */
600 /* tell the loop not to call check_children again, since we're calling it now */
605 reap_children(forker);
608 //fprintf(stderr, "Parent done with request %f\n", get_timestamp_millis() );
612 message_free( cur_msg );
614 } /* top level listen loop */
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...
623 static void check_children( prefork_simple* forker, int forever ) {
635 reap_children(forker);
637 prefork_child* cur_child = forker->first_child;
640 for( i = 0; i!= forker->current_num_children; i++ ) {
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;
648 FD_CLR(0,&read_set); /* just to be sure */
651 osrfLogWarning(OSRF_LOG_MARK,
652 "We have no children available - waiting for one to show up...");
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 );
657 osrfLogInfo(OSRF_LOG_MARK,
658 "select() completed after waiting on children to become available");
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 );
671 if( select_ret == 0 )
674 /* see if one of a child has told us it's done */
675 cur_child = forker->first_child;
678 for( j = 0; j!= forker->current_num_children && num_handled < select_ret ; j++ ) {
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 );
687 /* now suck off the data */
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);
696 osrfLogDebug( OSRF_LOG_MARK, "Read %d bytes from status buffer: %s", n, buf );
698 cur_child->available = 1;
700 cur_child = cur_child->next;
706 static void prefork_child_wait( prefork_child* child ) {
709 growing_buffer* gbuf = buffer_init( READ_BUFSIZE );
710 char buf[READ_BUFSIZE];
711 osrf_clearbuf( buf, sizeof(buf) );
713 for( i = 0; i < child->max_requests; i++ ) {
717 clr_fl(child->read_data_fd, O_NONBLOCK );
719 while( (n=read(child->read_data_fd, buf, READ_BUFSIZE-1)) > 0 ) {
721 osrfLogDebug(OSRF_LOG_MARK, "Prefork child read %d bytes of data", n);
723 set_fl(child->read_data_fd, O_NONBLOCK );
724 buffer_add( gbuf, buf );
725 osrf_clearbuf( buf, sizeof(buf) );
729 if( errno == EAGAIN ) n = 0;
731 if( errno == EPIPE ) {
732 osrfLogDebug(OSRF_LOG_MARK, "C child attempted read on broken pipe, exiting...");
737 osrfLogWarning( OSRF_LOG_MARK,
738 "Prefork child read returned error with errno %d", errno );
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 );
747 if( i < child->max_requests - 1 )
748 write( child->write_status_fd, "available" /*less than 64 bytes*/, 9 );
753 osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%ld]",
754 child->max_requests, i, (long) getpid() );
756 osrf_prefork_child_exit(child); /* just to be sure */
760 static void add_prefork_child( prefork_simple* forker, prefork_child* child ) {
762 if( forker->first_child == NULL ) {
763 forker->first_child = child;
768 /* we put the child in as the last because, regardless,
769 we have to do the DLL splice dance, and this is the
772 prefork_child* start_child = forker->first_child;
774 if( forker->first_child->next == start_child )
776 forker->first_child = forker->first_child->next;
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*/
783 forker->first_child->next = child;
784 child->next = start_child;
788 //static prefork_child* find_prefork_child( prefork_simple* forker, pid_t pid ) {
790 // if( forker->first_child == NULL ) { return NULL; }
791 // prefork_child* start_child = forker->first_child;
793 // if( forker->first_child->pid == pid )
794 // return forker->first_child;
795 // } while( (forker->first_child = forker->first_child->next) != start_child );
801 static void del_prefork_child( prefork_simple* forker, pid_t pid ) {
803 if( forker->first_child == NULL ) { return; }
805 (forker->current_num_children)--;
806 osrfLogDebug( OSRF_LOG_MARK, "Deleting Child: %d", pid );
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 */
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;
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 );
822 prefork_child_free( start_child );
828 /* special case where the first item in the list needs to be removed */
829 if( start_child->pid == pid ) {
831 /* find the last one so we can remove the start_child */
833 prev_child = cur_child;
834 cur_child = cur_child->next;
835 } while( cur_child != start_child );
837 /* now cur_child == start_child */
838 prev_child->next = cur_child->next;
839 forker->first_child = prev_child;
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 );
846 prefork_child_free( cur_child );
851 prev_child = cur_child;
852 cur_child = cur_child->next;
854 if( cur_child->pid == pid ) {
855 prev_child->next = cur_child->next;
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 );
862 prefork_child_free( cur_child );
866 } while(cur_child != start_child);
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 ) {
876 prefork_child* child = (prefork_child*) safe_malloc(sizeof(prefork_child));
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;
893 static void prefork_clear( prefork_simple* prefork ) {
895 while( prefork->first_child != NULL ) {
896 osrfLogInfo( OSRF_LOG_MARK, "Killing children and sleeping 1 to reap..." );
901 client_free(prefork->connection);
902 free(prefork->appname);
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);