// TODO: error handling // TODO: better exit point handling // (freeing resources for valgrind-cleanliness is too tedious at the moment) void options_parse(int argc, char * argv[], struct Options * options) { int opt; // modified when config is loaded on the command line config_t config; config_init(&config); set_default_config(&config); // only to used for -g: print default config config_t config_default; config_init(&config_default); set_default_config(&config_default); // -i flag should only print options after all other // command line arguments have been applied bool print_options = false; while (-1 != (opt = getopt(argc, argv, OPTSTR))) { switch (opt) { case 'c': config_set_auto_convert(&config, CONFIG_TRUE); if (CONFIG_FALSE == config_read_file(&config, optarg)) { // failure reporting fprintf(stderr, "Failed to use config file '%s'!\n", optarg); switch (config_error_type(&config)) { case CONFIG_ERR_NONE: fprintf(stderr, "\tno error reported\n" "\t(This might be a libconfig problem.)\n"); break; case CONFIG_ERR_FILE_IO: fprintf(stderr, "\tfile I/O error\n"); break; case CONFIG_ERR_PARSE: fprintf(stderr, "\tparse error on line %d:\n" "\t%s\n", config_error_line(&config), config_error_text(&config)); break; default: fprintf(stderr, "\tunknown error\n" "\t(A new libconfig version might have introduced" " new kinds of warnings.)\n"); } } break; case 'g': config_write(&config_default, stdout); // be valgrind-clean config_destroy(&config_default); config_destroy(&config); exit(EXIT_SUCCESS); break; case 'i': print_options = true; break; default: /* '?' 'h' */ options_help(*argv); // be valgrind-clean config_destroy(&config_default); config_destroy(&config); exit(EXIT_FAILURE); } } config2options(&config, options); // be valgrind-clean config_destroy(&config_default); config_destroy(&config); if (print_options) options_print(stderr, "", options); }
int main(int argc, char **argv) { const char *ptr; int server_mode = -1; int i; int rc = 0; FILE *xmlf; #if !defined(HPUX) setlinebuf(stdout); #endif ptr = strrchr(argv[0], '/'); if (ptr == NULL) { strncpy(prog_name, argv[0], PROG_NAME_LEN); } else { strncpy(prog_name, ptr + 1, PROG_NAME_LEN); } pagesize = getpagesize(); printf("pagesize = %d\n", pagesize); cache_line_size = OPT_CACHE_LINE_EST; #ifdef TBB_KINFO int kinfo_fd = 0; #endif /* TBB_KINFO */ #ifdef TBB_KINFO if (options.kinfo) { kinfo_fd = pre_kinfo_init(); } #endif /* TBB_KINFO */ init_print_time(&tnow, &tprev); /* must happen before processing arguments */ options_set(); /* Process command line arguments */ process_args(argc, argv); /* Check for conflicts in the specified cmd line options */ check_options(); printf("INIT START\n"); num_idle = maxconns; printf("main: num_idle = %d\n", num_idle); printf("main: maxconns = %d\n", maxconns); printf("main: max_fds = %d\n", max_fds); #ifdef DEBUG_ON printf("Debugging is on debugging messages mask = 0x%x\n", MSG_MASK); #else printf("Compiled without debugging\n"); #endif /* DEBUG_ON */ if (options.use_socket_aio) { // for now leave some room for a few open files and // a few listening sockets (unfortunately we need to call this before // we know how many listening sockets there will be // max_sock_sd = maxconns + 20; // For now we just pick a value that _SHOULD_ avoid // collisions with future tests. // Note that if there were sd/fd collisions things // _should_ likely work just fine but this may // make finding problems easier - since there is // potential to control which range of values the // underlying aio layer is returning. #ifdef HAVE_AIO_LAYER /* These are just estimates !!! */ int aio_lowest_sock_sd = OPT_AIO_LOWEST_SD; int aio_highest_sock_sd = (maxconns + aio_lowest_sock_sd - 1) + OPT_AIO_MAX_LISTENERS; max_sock_sd = aio_highest_sock_sd; if (max_sock_sd > max_fds) { printf("main: max_sock_sd = %d > max_fds = %d\n", max_sock_sd, max_fds); exit(1); } printf("main: aio_lowest_sock_sd = %d\n", aio_lowest_sock_sd); printf("main: aio_highest_sock_sd = %d\n", aio_highest_sock_sd); PRINT_TIME(NOFD, &tnow, &tprev, "main: calling aio_sock_init with " "max_sock_sd = %d", max_sock_sd); rc = aio_sock_init(aio_lowest_sock_sd, aio_highest_sock_sd); if (rc < 0) { printf("main: aio_sock_init failed rc = %d\n", rc); exit(1); } #endif /* HAVE_AIO_LAYER */ } else { max_sock_sd = max_fds; } printf("main: max_sock_sd = %d\n", max_sock_sd); printf("main: FD_SETSIZE = %d\n", FD_SETSIZE); printf("main: sizeof(fd_set) = %d\n", (int) sizeof(fd_set)); #ifdef TBB_KINFO if (options.kinfo) { kinfo_fd = pre_kinfo_init(); } #endif /* TBB_KINFO */ rc = info_init(); info_listener_init(); /* must happen after processing arguments */ init_app_queues(); create_pidfile(); options_valid(); options_print(); xmlf = fopen("options.xml", "w"); if (!xmlf) { printf("main: failed to create options.xml\n"); exit(1); } options_print_xml(xmlf); fclose(xmlf); #ifndef AIO_WORKAROUND_BUGS print_extra_info(); #endif /* AIO_WORKAROUND_BUGS */ #ifdef HAVE_NETSTAT netstat_init(); #endif /* HAVE_NETSTAT */ sock_special_init(); /* initialize the event dispatch mechanism */ if (options.use_poll) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling poll_loop_init"); poll_loop_init(); #ifdef HAVE_EPOLL } else if (options.use_epoll || options.use_epoll2) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling epoll_loop_init"); epoll_loop_init(); #endif /* HAVE_EPOLL */ #ifdef HAVE_AIO_LAYER } else if (options.use_socket_aio) { PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling aio_loop_init"); aio_loop_init(); #endif /* HAVE_AIO_LAYER */ } else if (!options.send_loop) { assert(options.send_loop == 0); PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling select_loop_init"); select_loop_init(); } else { #ifdef SEND assert(options.send_loop == 1); PRINT_TIME(NOFD, &tnow, &tprev, "userver: calling send_loop_init"); send_loop_init(); #endif } switch (options.get_connections) { case OPT_CONN_WITH_SELECT_POLL_EPOLL: server_mode = LISTENER_NOT_ASYNC_INIT; break; #ifdef SEND case OPT_CONN_WITH_SEND_SELECT: server_mode = LISTENER_NOT_ASYNC_INIT | LISTENER_SEND_INIT; break; #endif /* SEND */ case OPT_CONN_WITH_SIGIO: server_mode = LISTENER_DO_ASYNC_INIT; break; case OPT_CONN_WITH_SEND_EVTS: server_mode = LISTENER_SEND_INIT; break; case OPT_CONN_WITH_AIO_ACCEPT: server_mode = LISTENER_AIO_INIT; break; default: printf("%s: options.get_connections = %d not handled\n", argv[0], options.get_connections); exit(1); break; } /* switch */ printf("Calling server_init with mode = 0x%x = %d\n", server_mode, server_mode); server_init(server_mode); for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { printf("listen_sd = %d\n", i); if (i > max_sd) { max_sd = i; } } } switch (options.process_sds_order) { case OPT_PROCESS_SDS_LRU: lru_copy_init(); break; case OPT_PROCESS_SDS_LIFO: q_init(max_fds + 1); if (options.get_connections == OPT_CONN_WITH_SELECT_POLL_EPOLL) { for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { q_add_to_front(i); } } } break; case OPT_PROCESS_SDS_FIFO: q_init(max_fds + 1); if (options.get_connections == OPT_CONN_WITH_SELECT_POLL_EPOLL) { for (i = sock_listener_min; i <= sock_listener_max; i++) { if (sock_is_listener(i)) { q_add_to_rear(i); } } } break; default: /* do nothing */ break; } if (options.caching_on) { initCache(options.cache_table_size, options.cache_max_bytes, options.cache_max_file_size, options.cache_max_load_factor, options.cache_lock_pages); #ifdef CACHE_MAPPED_NEW if (options.cache_warm) { cache_warm(options.cache_warm_file, (options.doc_root[0] != '\0') ? options.doc_root : NULL, options.cache_table_print); } #endif } rusage_init(); fork_servers(numprocs); return 0; }