/* * General server example: accept a client connection and do something. * This program just outputs a short HTML page, but can be easily adapted * to do other things. * * This server creates a constant number of processes ("virtual processors" * or VPs) and replaces them when they die. Each virtual processor manages * its own independent set of state threads (STs), the number of which varies * with load against the server. Each state thread listens to exactly one * listening socket. The initial process becomes the watchdog, waiting for * children (VPs) to die or for a signal requesting termination or restart. * Upon receiving a restart signal (SIGHUP), all VPs close and then reopen * log files and reload configuration. All currently active connections remain * active. It is assumed that new configuration affects only request * processing and not the general server parameters such as number of VPs, * thread limits, bind addresses, etc. Those are specified as command line * arguments, so the server has to be stopped and then started again in order * to change them. * * Each state thread loops processing connections from a single listening * socket. Only one ST runs on a VP at a time, and VPs do not share memory, * so no mutual exclusion locking is necessary on any data, and the entire * server is free to use all the static variables and non-reentrant library * functions it wants, greatly simplifying programming and debugging and * increasing performance (for example, it is safe to ++ and -- all global * counters or call inet_ntoa(3) without any mutexes). The current thread on * each VP maintains equilibrium on that VP, starting a new thread or * terminating itself if the number of spare threads exceeds the lower or * upper limit. * * All I/O operations on sockets must use the State Thread library's I/O * functions because only those functions prevent blocking of the entire VP * process and perform state thread scheduling. */ int main(int argc, char *argv[]) { /* Parse command-line options */ parse_arguments(argc, argv); /* Allocate array of server pids */ if ((vp_pids = calloc(vp_count, sizeof(pid_t))) == NULL) err_sys_quit(errfd, "ERROR: calloc failed"); /* Start the daemon */ if (!interactive_mode) start_daemon(); /* Initialize the ST library */ if (st_init() < 0) err_sys_quit(errfd, "ERROR: initialization failed: st_init"); /* Set thread throttling parameters */ set_thread_throttling(); /* Create listening sockets */ create_listeners(); /* Change the user */ if (username) change_user(); /* Open log files */ open_log_files(); /* Start server processes (VPs) */ start_processes(); /* Turn time caching on */ st_timecache_set(1); /* Install signal handlers */ install_sighandlers(); /* Load configuration from config files */ load_configs(); /* Start all threads */ start_threads(); /* Become a signal processing thread */ process_signals(NULL); /* NOTREACHED */ return 1; }
/********************************************************************* * open connections and send requested amt of data; estimate b/w */ void simple_server(int num_ports, int base_rx_port) { int datafd, maxlfd; unsigned long diffus; struct timeval last, diff, now ={ 0L, 0L }; int opened=0, closed=0, cnt=0; fd_set fds_listeners, fds_active, fds_finished; int rc; FD_ZERO(&fds_listeners); FD_ZERO(&fds_active); FD_ZERO(&fds_finished); /* listeners on num_ports */ if((maxlfd = create_listeners(&fds_listeners, num_ports, base_rx_port)) < 0) { exit(-1); } datafd = maxlfd+1; while(1) { /* grab any new incoming connections */ rc = accept_incoming(maxlfd, &fds_listeners, &fds_active); if(rc > 0) { opened += rc; } /* select on the data FD's */ rc = send_data(&fds_active, &fds_finished); if(rc > 0) { closed += rc; } cnt++; gettimeofday(&now, (struct timezone *)0); tvsub(&diff, &now, &last); diffus = diff.tv_sec*1e6 + diff.tv_usec; if(diffus > SAMPLE_PERIOD) { int i, totb=0, prog=0; double mbs, tmbs=0.0; fprintf(stderr, "\nBandwidth:\n"); for(i=datafd; i <= maxfd; i++) { if(state[i].tx_sent_cpt) { prog++; } totb += state[i].tx_sent_cpt; mbs = (double)(8.0*state[i].tx_sent_cpt) / (double)diffus; tmbs += mbs; if(state[i].open) { fprintf(stderr,"%c%.4f ",'+', mbs); } else { if(verbose) { fprintf(stderr,"%c%.4f ",'-', mbs); } } state[i].tx_sent_cpt = 0; } fprintf(stderr, "\n\t %d streams active, %d made progress: " "tot = %d, tot Mb/s = %.2f\n" "\t opened %d, closed %d descriptors (loop count %d)\n\n", FD_POP(maxfd, &fds_active), prog, totb, tmbs/scalar, opened, closed, cnt); opened = closed = cnt = 0; last = now; } } /* end of while 1 */ }