XXX under some circumstances not understood, children can get stuck * in start_threads forever trying to take over slots which will * never be cleaned up; for now there is an APLOG_DEBUG message issued * every so often when this condition occurs */
| 953 | * every so often when this condition occurs |
| 954 | */ |
| 955 | static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) |
| 956 | { |
| 957 | thread_starter *ts = dummy; |
| 958 | apr_thread_t **threads = ts->threads; |
| 959 | apr_threadattr_t *thread_attr = ts->threadattr; |
| 960 | int my_child_num = ts->child_num_arg; |
| 961 | proc_info *my_info; |
| 962 | apr_status_t rv; |
| 963 | int threads_created = 0; |
| 964 | int listener_started = 0; |
| 965 | int prev_threads_created; |
| 966 | int loops, i; |
| 967 | |
| 968 | loops = prev_threads_created = 0; |
| 969 | while (1) { |
| 970 | /* threads_per_child does not include the listener thread */ |
| 971 | for (i = 0; i < threads_per_child; i++) { |
| 972 | int status = ap_scoreboard_image->servers[my_child_num][i].status; |
| 973 | |
| 974 | if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { |
| 975 | continue; |
| 976 | } |
| 977 | |
| 978 | my_info = (proc_info *)ap_malloc(sizeof(proc_info)); |
| 979 | my_info->pid = my_child_num; |
| 980 | my_info->tid = i; |
| 981 | my_info->sd = 0; |
| 982 | |
| 983 | /* We are creating threads right now */ |
| 984 | ap_update_child_status_from_indexes(my_child_num, i, |
| 985 | SERVER_STARTING, NULL); |
| 986 | /* We let each thread update its own scoreboard entry. This is |
| 987 | * done because it lets us deal with tid better. |
| 988 | */ |
| 989 | rv = ap_thread_create(&threads[i], thread_attr, |
| 990 | worker_thread, my_info, pruntime); |
| 991 | if (rv != APR_SUCCESS) { |
| 992 | ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(03142) |
| 993 | "ap_thread_create: unable to create worker thread"); |
| 994 | /* let the parent decide how bad this really is */ |
| 995 | clean_child_exit(APEXIT_CHILDSICK); |
| 996 | } |
| 997 | threads_created++; |
| 998 | } |
| 999 | /* Start the listener only when there are workers available */ |
| 1000 | if (!listener_started && threads_created) { |
| 1001 | create_listener_thread(ts); |
| 1002 | listener_started = 1; |
| 1003 | } |
| 1004 | if (start_thread_may_exit || threads_created == threads_per_child) { |
| 1005 | break; |
| 1006 | } |
| 1007 | /* wait for previous generation to clean up an entry */ |
| 1008 | apr_sleep(apr_time_from_sec(1)); |
| 1009 | ++loops; |
| 1010 | if (loops % 120 == 0) { /* every couple of minutes */ |
| 1011 | if (prev_threads_created == threads_created) { |
| 1012 | ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, |
nothing calls this directly
no test coverage detected