static void *create_pg_auth_dir_config(apr_pool_t * p, char *d) { pg_auth_config_rec *new_rec; #ifdef DEBUG_AUTH_PGSQL ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, "[mod_auth_pgsql.c] - going to configure directory \"%s\" ", d); #endif /* DEBUG_AUTH_PGSQL */ new_rec = apr_pcalloc(p, sizeof(pg_auth_config_rec)); if (new_rec == NULL) return NULL; if (auth_pgsql_pool == NULL) apr_pool_create_ex(&auth_pgsql_pool, NULL, NULL, NULL); if (auth_pgsql_pool == NULL) return NULL; /* sane defaults */ if (d != NULL) new_rec->dir = apr_pstrdup(p, d); else new_rec->dir = NULL; new_rec->auth_pg_host = NULL; new_rec->auth_pg_database = NULL; new_rec->auth_pg_port = NULL; new_rec->auth_pg_options = NULL; new_rec->auth_pg_user = NULL; new_rec->auth_pg_pwd = NULL; new_rec->auth_pg_pwd_table = NULL; new_rec->auth_pg_uname_field = NULL; new_rec->auth_pg_pwd_field = NULL; new_rec->auth_pg_grp_table = NULL; new_rec->auth_pg_grp_user_field = NULL; new_rec->auth_pg_grp_group_field = NULL; new_rec->auth_pg_pwd_whereclause = NULL; new_rec->auth_pg_grp_whereclause = NULL; new_rec->auth_pg_nopasswd = 0; new_rec->auth_pg_authoritative = 1; new_rec->auth_pg_lowercaseuid = 0; new_rec->auth_pg_uppercaseuid = 0; new_rec->auth_pg_pwdignorecase = 0; new_rec->auth_pg_encrypted = 1; new_rec->auth_pg_hash_type = AUTH_PG_HASH_TYPE_CRYPT; new_rec->auth_pg_cache_passwords = 0; new_rec->auth_pg_netepi_old_passwords = 0; new_rec->auth_pg_log_table = NULL; new_rec->auth_pg_log_addrs_field = NULL; new_rec->auth_pg_log_uname_field = NULL; new_rec->auth_pg_log_pwd_field = NULL; new_rec->auth_pg_log_date_field = NULL; new_rec->auth_pg_log_uri_field = NULL; /* make a per directory cache table */ new_rec->cache_pass_table = apr_table_make(auth_pgsql_pool, MAX_TABLE_LEN); if (new_rec->cache_pass_table == NULL) return NULL; #ifdef DEBUG_AUTH_PGSQL ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, "[mod_auth_pgsql.c] - configured directory \"%s\" ", d); #endif /* DEBUG_AUTH_PGSQL */ return new_rec; }
//static void child_main(int child_num_arg) void body() { mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ my_child_num = child_num_arg; ap_my_pid = getpid(); requests_this_child = 0; ap_fatal_signal_child_setup(ap_server_conf); /* Get a sub context for global allocations in this child, so that * we can have cleanups occur when the child exits. */ apr_allocator_create(allocator); //// removed deref apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(pchild, pconf, NULL, allocator); //// removed deref apr_allocator_owner_set(allocator, pchild); apr_pool_create(ptrans, pchild); //// removed deref apr_pool_tag(ptrans, 65); // "transaction"); /* needs to be done before we switch UIDs so we have permissions */ ap_reopen_scoreboard(pchild, NULL, 0); status = apr_proc_mutex_child_init(accept_mutex, ap_lock_fname, pchild); //// removed deref if (status != APR_SUCCESS) { /* ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, */ /* "Couldnt initialize crossprocess lock in child " */ /* "%s %d", ap_lock_fname, ap_accept_lock_mech); */ clean_child_exit(APEXIT_CHILDFATAL); } if (unixd_setup_child() > 0) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); ap_create_sb_handle(sbh, pchild, my_child_num, 0); //// removed deref ap_update_child_status(sbh, SERVER_READY, NULL); /* Set up the pollfd array */ /* ### check the status */ (void) apr_pollset_create(pollset, num_listensocks, pchild, 0); //// removed deref num_listensocks = nondet(); assume(num_listensocks>0); lr = ap_listeners; i = num_listensocks; while (1) { if ( i<=0 ) break; int pfd = 0; pfd_desc_type = APR_POLL_SOCKET; pfd_desc_s = 1; // lr->sd; pfd_reqevents = APR_POLLIN; pfd_client_data = lr; /* ### check the status */ (void) apr_pollset_add(pollset, pfd); //// removed deref i--; } mpm_state = AP_MPMQ_RUNNING; bucket_alloc = apr_bucket_alloc_create(pchild); while(1>0) { if (die_now>0) break; conn_rec *current_conn; void *csd; /* * (Re)initialize this child to a pre-connection state. */ apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { clean_child_exit(0); } (void) ap_update_child_status(sbh, SERVER_READY, NULL); /* * Wait for an acceptable connection to arrive. */ /* Lock around "accept", if necessary */ SAFE_ACCEPT(accept_mutex_on()); do_ACCEPT=1; do_ACCEPT=0; dummy = nondet(); if(dummy > 0) { /* goto loc_return; */ while(1>0) { int ddd; ddd=ddd; } } if (num_listensocks == 1) { /* There is only one listener record, so refer to that one. */ lr = ap_listeners; } else { /* multiple listening sockets - need to poll */ while(1) { int numdesc; const void *pdesc; /* timeout == -1 == wait forever */ status = apr_pollset_poll(pollset, -1, numdesc, pdesc); //// removed deref if (status != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(status) > 0) { if (one_process>0 && shutdown_pending>0) { /* goto loc_return; */ while(1>0) { int ddd; ddd=ddd; } } goto loc_continueA; } /* Single Unix documents select as returning errnos * EBADF, EINTR, and EINVAL... and in none of those * cases does it make sense to continue. In fact * on Linux 2.0.x we seem to end up with EFAULT * occasionally, and we'd loop forever due to it. */ /* ap_log_error5(APLOG_MARK, APLOG_ERR, status, */ /* ap_server_conf, "apr_pollset_poll: (listen)"); */ clean_child_exit(1); } /* We can always use pdesc[0], but sockets at position N * could end up completely starved of attention in a very * busy server. Therefore, we round-robin across the * returned set of descriptors. While it is possible that * the returned set of descriptors might flip around and * continue to starve some sockets, we happen to know the * internal pollset implementation retains ordering * stability of the sockets. Thus, the round-robin should * ensure that a socket will eventually be serviced. */ if (last_poll_idx >= numdesc) last_poll_idx = 0; /* Grab a listener record from the client_data of the poll * descriptor, and advance our saved index to round-robin * the next fetch. * * ### hmm... this descriptor might have POLLERR rather * ### than POLLIN */ lr = 1; //pdesc[last_poll_idx++].client_data; break; loc_continueA: {int yyy2; yyy2=yyy2; } } } /* if we accept() something we don't want to die, so we have to * defer the exit */ status = nondet(); // lr->accept_func(&csd, lr, ptrans); SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ if (status == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1); } else if (status != APR_SUCCESS) { goto loc_continueB; } /* * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. */ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); if (current_conn > 0) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } /* Check the pod and the generation number after processing a * connection so that we'll go away if a graceful restart occurred * while we were processing the connection or we are the lucky * idle server process that gets to die. */ dummy = nondet(); if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ die_now = 1; } else if (ap_my_generation != dummy) { //ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ die_now = 1; } loc_continueB: { int uuu; uuu=uuu; } } clean_child_exit(0); /* loc_return: */ while(1>0) { int ddd; ddd=ddd; } }
int SVNPatch::Init( const CString& patchfile, const CString& targetpath, CProgressDlg *pPprogDlg ) { CTSVNPath target = CTSVNPath(targetpath); if (patchfile.IsEmpty() || targetpath.IsEmpty() || !svn_dirent_is_absolute(target.GetSVNApiPath(m_pool))) { m_errorStr.LoadString(IDS_ERR_PATCHPATHS); return 0; } svn_error_t * err = NULL; apr_pool_t * scratchpool = NULL; svn_client_ctx_t * ctx = NULL; m_errorStr.Empty(); m_patchfile = patchfile; m_targetpath = targetpath; m_testPath.Empty(); m_patchfile.Replace('\\', '/'); m_targetpath.Replace('\\', '/'); apr_pool_create_ex(&scratchpool, m_pool, abort_on_pool_failure, NULL); svn_error_clear(svn_client_create_context2(&ctx, SVNConfig::Instance().GetConfig(m_pool), scratchpool)); ctx->notify_func2 = notify; ctx->notify_baton2 = this; if (pPprogDlg) { pPprogDlg->SetTitle(IDS_APPNAME); pPprogDlg->FormatNonPathLine(1, IDS_PATCH_PROGTITLE); pPprogDlg->SetShowProgressBar(false); pPprogDlg->ShowModeless(AfxGetMainWnd()); m_pProgDlg = pPprogDlg; } m_filePaths.clear(); m_nRejected = 0; m_nStrip = 0; CTSVNPath tsvnpatchfile = CTSVNPath(m_patchfile); CTSVNPath tsvntargetpath = CTSVNPath(m_targetpath); err = svn_client_patch(tsvnpatchfile.GetSVNApiPath(scratchpool), // patch_abspath tsvntargetpath.GetSVNApiPath(scratchpool), // local_abspath true, // dry_run m_nStrip, // strip_count false, // reverse true, // ignore_whitespace false, // remove_tempfiles patch_func, // patch_func this, // patch_baton ctx, // client context scratchpool); m_pProgDlg = NULL; apr_pool_destroy(scratchpool); // since we're doing a dry-run, a 'path not found' can happen // since new files/dirs aren't added in the patch func. if ((err)&&(err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)) { m_errorStr = GetErrorMessage(err); m_filePaths.clear(); svn_error_clear(err); return 0; } if ((m_nRejected > ((int)m_filePaths.size() / 3)) && !m_testPath.IsEmpty()) { m_nStrip++; bool found = false; for (m_nStrip = 0; m_nStrip < STRIP_LIMIT; ++m_nStrip) { for (std::vector<PathRejects>::iterator it = m_filePaths.begin(); it != m_filePaths.end(); ++it) { if (Strip(it->path).IsEmpty()) { found = true; m_nStrip--; break; } } if (found) break; } } if (m_nStrip == STRIP_LIMIT) m_filePaths.clear(); else if (m_nStrip > 0) { apr_pool_create_ex(&scratchpool, m_pool, abort_on_pool_failure, NULL); svn_error_clear(svn_client_create_context2(&ctx, SVNConfig::Instance().GetConfig(m_pool), scratchpool)); ctx->notify_func2 = notify; ctx->notify_baton2 = this; m_filePaths.clear(); m_nRejected = 0; err = svn_client_patch(CUnicodeUtils::GetUTF8(m_patchfile), // patch_abspath CUnicodeUtils::GetUTF8(m_targetpath), // local_abspath true, // dry_run m_nStrip, // strip_count false, // reverse true, // ignore_whitespace false, // remove_tempfiles patch_func, // patch_func this, // patch_baton ctx, // client context scratchpool); apr_pool_destroy(scratchpool); if (err) { m_errorStr = GetErrorMessage(err); m_filePaths.clear(); svn_error_clear(err); } } return (int)m_filePaths.size(); }
SWITCH_DECLARE(switch_status_t) switch_core_perform_new_memory_pool(switch_memory_pool_t **pool, const char *file, const char *func, int line) { char *tmp; #ifdef INSTANTLY_DESTROY_POOLS apr_pool_create(pool, NULL); switch_assert(*pool != NULL); #else #ifdef PER_POOL_LOCK apr_allocator_t *my_allocator = NULL; apr_thread_mutex_t *my_mutex; #else void *pop = NULL; #endif #ifdef USE_MEM_LOCK switch_mutex_lock(memory_manager.mem_lock); #endif switch_assert(pool != NULL); #ifndef PER_POOL_LOCK if (switch_queue_trypop(memory_manager.pool_recycle_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { *pool = (switch_memory_pool_t *) pop; } else { #endif #ifdef PER_POOL_LOCK if ((apr_allocator_create(&my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_pool_create_ex(pool, NULL, NULL, my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_thread_mutex_create(&my_mutex, APR_THREAD_MUTEX_NESTED, *pool)) != APR_SUCCESS) { abort(); } apr_allocator_mutex_set(my_allocator, my_mutex); apr_allocator_owner_set(my_allocator, *pool); apr_pool_mutex_set(*pool, my_mutex); #else apr_pool_create(pool, NULL); switch_assert(*pool != NULL); } #endif #endif tmp = switch_core_sprintf(*pool, "%s:%d", file, line); apr_pool_tag(*pool, tmp); #ifdef DEBUG_ALLOC2 switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_CONSOLE, "%p New Pool %s\n", (void *) *pool, apr_pool_tag(*pool, NULL)); #endif #ifdef USE_MEM_LOCK switch_mutex_unlock(memory_manager.mem_lock); #endif return SWITCH_STATUS_SUCCESS; }
switch_memory_pool_t *switch_core_memory_init(void) { #ifndef INSTANTLY_DESTROY_POOLS switch_threadattr_t *thd_attr; #endif #ifdef PER_POOL_LOCK apr_allocator_t *my_allocator = NULL; apr_thread_mutex_t *my_mutex; #endif memset(&memory_manager, 0, sizeof(memory_manager)); #ifdef PER_POOL_LOCK if ((apr_allocator_create(&my_allocator)) != APR_SUCCESS) { abort(); } if ((apr_pool_create_ex(&memory_manager.memory_pool, NULL, NULL, my_allocator)) != APR_SUCCESS) { apr_allocator_destroy(my_allocator); my_allocator = NULL; abort(); } if ((apr_thread_mutex_create(&my_mutex, APR_THREAD_MUTEX_NESTED, memory_manager.memory_pool)) != APR_SUCCESS) { abort(); } apr_allocator_mutex_set(my_allocator, my_mutex); apr_pool_mutex_set(memory_manager.memory_pool, my_mutex); apr_allocator_owner_set(my_allocator, memory_manager.memory_pool); apr_pool_tag(memory_manager.memory_pool, "core_pool"); #else apr_pool_create(&memory_manager.memory_pool, NULL); switch_assert(memory_manager.memory_pool != NULL); #endif #ifdef USE_MEM_LOCK switch_mutex_init(&memory_manager.mem_lock, SWITCH_MUTEX_NESTED, memory_manager.memory_pool); #endif #ifdef INSTANTLY_DESTROY_POOLS { void *foo; foo = (void *) (intptr_t) pool_thread; } #else switch_queue_create(&memory_manager.pool_queue, 50000, memory_manager.memory_pool); switch_queue_create(&memory_manager.pool_recycle_queue, 50000, memory_manager.memory_pool); switch_threadattr_create(&thd_attr, memory_manager.memory_pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&pool_thread_p, thd_attr, pool_thread, NULL, memory_manager.memory_pool); while (!memory_manager.pool_thread_running) { switch_cond_next(); } #endif return memory_manager.memory_pool; }
static h2_session *h2_session_create_int(conn_rec *c, request_rec *r, h2_config *config) { nghttp2_session_callbacks *callbacks = NULL; nghttp2_option *options = NULL; apr_allocator_t *allocator = NULL; apr_status_t status = apr_allocator_create(&allocator); if (status != APR_SUCCESS) { return NULL; } apr_pool_t *pool = NULL; status = apr_pool_create_ex(&pool, c->pool, NULL, allocator); if (status != APR_SUCCESS) { return NULL; } h2_session *session = apr_pcalloc(pool, sizeof(h2_session)); if (session) { session->id = c->id; session->allocator = allocator; session->pool = pool; status = apr_thread_mutex_create(&session->alock, APR_THREAD_MUTEX_DEFAULT, session->pool); if (status != APR_SUCCESS) { return NULL; } apr_allocator_mutex_set(session->allocator, session->alock); status = apr_thread_cond_create(&session->iowait, session->pool); if (status != APR_SUCCESS) { return NULL; } session->c = c; session->r = r; session->ngh2 = NULL; session->streams = h2_stream_set_create(session->pool); session->zombies = h2_stream_set_create(session->pool); session->mplx = h2_mplx_create(c, session->pool); h2_conn_io_init(&session->io, c, 0); apr_status_t status = init_callbacks(c, &callbacks); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, status, c, "nghttp2: error in init_callbacks"); h2_session_destroy(session); return NULL; } int rv = nghttp2_option_new(&options); if (rv != 0) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c, "nghttp2_option_new: %s", nghttp2_strerror(rv)); h2_session_destroy(session); return NULL; } /* Nowadays, we handle the preface ourselves. We had problems * with nghttp2 internal state machine when traffic action occured * before the preface was read. */ nghttp2_option_set_recv_client_preface(options, 1); /* Set a value, to be observed before we receive any SETTINGS * from the client. */ nghttp2_option_set_peer_max_concurrent_streams(options, 100); /* We need to handle window updates ourself, otherwise we * get flooded by nghttp2. */ nghttp2_option_set_no_auto_window_update(options, 1); rv = nghttp2_session_server_new2(&session->ngh2, callbacks, session, options); nghttp2_session_callbacks_del(callbacks); nghttp2_option_del(options); if (rv != 0) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c, "nghttp2_session_server_new: %s", nghttp2_strerror(rv)); h2_session_destroy(session); return NULL; } } return session; }
/** * A h2_mplx needs to be thread-safe *and* if will be called by * the h2_session thread *and* the h2_worker threads. Therefore: * - calls are protected by a mutex lock, m->lock * - the pool needs its own allocator, since apr_allocator_t are * not re-entrant. The separate allocator works without a * separate lock since we already protect h2_mplx itself. * Since HTTP/2 connections can be expected to live longer than * their HTTP/1 cousins, the separate allocator seems to work better * than protecting a shared h2_session one with an own lock. */ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, const h2_config *conf, apr_interval_time_t stream_timeout, h2_workers *workers) { apr_status_t status = APR_SUCCESS; apr_allocator_t *allocator = NULL; h2_mplx *m; AP_DEBUG_ASSERT(conf); status = apr_allocator_create(&allocator); if (status != APR_SUCCESS) { return NULL; } m = apr_pcalloc(parent, sizeof(h2_mplx)); if (m) { m->id = c->id; APR_RING_ELEM_INIT(m, link); m->c = c; apr_pool_create_ex(&m->pool, parent, NULL, allocator); if (!m->pool) { return NULL; } apr_pool_tag(m->pool, "h2_mplx"); apr_allocator_owner_set(allocator, m->pool); status = apr_thread_mutex_create(&m->lock, APR_THREAD_MUTEX_DEFAULT, m->pool); if (status != APR_SUCCESS) { h2_mplx_destroy(m); return NULL; } status = apr_thread_cond_create(&m->task_thawed, m->pool); if (status != APR_SUCCESS) { h2_mplx_destroy(m); return NULL; } m->bucket_alloc = apr_bucket_alloc_create(m->pool); m->max_streams = h2_config_geti(conf, H2_CONF_MAX_STREAMS); m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM); m->q = h2_iq_create(m->pool, m->max_streams); m->stream_ios = h2_io_set_create(m->pool); m->ready_ios = h2_io_set_create(m->pool); m->stream_timeout = stream_timeout; m->workers = workers; m->workers_max = workers->max_workers; m->workers_def_limit = 4; m->workers_limit = m->workers_def_limit; m->last_limit_change = m->last_idle_block = apr_time_now(); m->limit_change_interval = apr_time_from_msec(200); m->tx_handles_reserved = 0; m->tx_chunk_size = 4; m->spare_slaves = apr_array_make(m->pool, 10, sizeof(conn_rec*)); m->ngn_shed = h2_ngn_shed_create(m->pool, m->c, m->max_streams, m->stream_max_mem); h2_ngn_shed_set_ctx(m->ngn_shed , m); } return m; }
static DWORD WINAPI service_stderr_thread(LPVOID hPipe) { HANDLE hPipeRead = (HANDLE) hPipe; HANDLE hEventSource; char errbuf[256]; char *errmsg = errbuf; const char *errarg[9]; DWORD errres; ap_regkey_t *regkey; apr_status_t rv; apr_pool_t *p; apr_pool_create_ex(&p, NULL, NULL, NULL); errarg[0] = "The Apache service named"; errarg[1] = display_name; errarg[2] = "reported the following error:\r\n>>>"; errarg[3] = errbuf; errarg[4] = NULL; errarg[5] = NULL; errarg[6] = NULL; errarg[7] = NULL; errarg[8] = NULL; /* What are we going to do in here, bail on the user? not. */ if ((rv = ap_regkey_open(®key, AP_REGKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" "EventLog\\Application\\Apache Service", APR_READ | APR_WRITE | APR_CREATE, p)) == APR_SUCCESS) { DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; /* The stock message file */ ap_regkey_value_set(regkey, "EventMessageFile", "%SystemRoot%\\System32\\netmsg.dll", AP_REGKEY_EXPAND, p); ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData, sizeof(dwData), REG_DWORD, p); ap_regkey_close(regkey); } hEventSource = RegisterEventSourceW(NULL, L"Apache Service"); SetEvent(stderr_ready); while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) { if ((errmsg > errbuf) || !apr_isspace(*errmsg)) { ++errmsg; if ((*(errmsg - 1) == '\n') || (errmsg >= errbuf + sizeof(errbuf) - 1)) { while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) { --errmsg; } *errmsg = '\0'; /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' * The event code in netmsg.dll is 3299 */ ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, errarg, NULL); errmsg = errbuf; } } } if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) { apr_snprintf(errbuf, sizeof(errbuf), "Win32 error %d reading stderr pipe stream\r\n", GetLastError()); ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, errarg, NULL); } CloseHandle(hPipeRead); DeregisterEventSource(hEventSource); CloseHandle(stderr_thread); stderr_thread = NULL; apr_pool_destroy(p); return 0; }
static int32 worker_thread(void * dummy) { proc_info * ti = dummy; int child_slot = ti->slot; apr_pool_t *tpool = ti->tpool; apr_allocator_t *allocator; apr_socket_t *csd = NULL; apr_pool_t *ptrans; /* Pool for per-transaction stuff */ apr_bucket_alloc_t *bucket_alloc; apr_socket_t *sd = NULL; apr_status_t rv = APR_EINIT; int srv , n; int curr_pollfd = 0, last_pollfd = 0; sigset_t sig_mask; int requests_this_child = ap_max_requests_per_thread; apr_pollfd_t *pollset; /* each worker thread is in control of its own destiny...*/ int this_worker_should_exit = 0; free(ti); mpm_state = AP_MPMQ_STARTING; on_exit_thread(check_restart, (void*)child_slot); /* block the signals for this thread */ sigfillset(&sig_mask); sigprocmask(SIG_BLOCK, &sig_mask, NULL); apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&ptrans, tpool, NULL, allocator); apr_allocator_owner_set(allocator, ptrans); apr_pool_tag(ptrans, "transaction"); bucket_alloc = apr_bucket_alloc_create_ex(allocator); apr_thread_mutex_lock(worker_thread_count_mutex); worker_thread_count++; apr_thread_mutex_unlock(worker_thread_count_mutex); (void) ap_update_child_status_from_indexes(0, child_slot, SERVER_STARTING, (request_rec*)NULL); apr_poll_setup(&pollset, num_listening_sockets + 1, tpool); for(n=0 ; n <= num_listening_sockets ; n++) apr_poll_socket_add(pollset, listening_sockets[n], APR_POLLIN); mpm_state = AP_MPMQ_RUNNING; while (1) { /* If we're here, then chances are (unless we're the first thread created) * we're going to be held up in the accept mutex, so doing this here * shouldn't hurt performance. */ this_worker_should_exit |= (ap_max_requests_per_thread != 0) && (requests_this_child <= 0); if (this_worker_should_exit) break; (void) ap_update_child_status_from_indexes(0, child_slot, SERVER_READY, (request_rec*)NULL); apr_thread_mutex_lock(accept_mutex); while (!this_worker_should_exit) { apr_int16_t event; apr_status_t ret; ret = apr_poll(pollset, num_listening_sockets + 1, &srv, -1); if (ret != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(ret)) { continue; } /* poll() will only return errors in catastrophic * circumstances. Let's try exiting gracefully, for now. */ ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) ap_server_conf, "apr_poll: (listen)"); this_worker_should_exit = 1; } else { /* if we've bailed in apr_poll what's the point of trying to use the data? */ apr_poll_revents_get(&event, listening_sockets[0], pollset); if (event & APR_POLLIN){ apr_sockaddr_t *rec_sa; apr_size_t len = 5; char *tmpbuf = apr_palloc(ptrans, sizeof(char) * 5); apr_sockaddr_info_get(&rec_sa, "127.0.0.1", APR_UNSPEC, 7772, 0, ptrans); if ((ret = apr_recvfrom(rec_sa, listening_sockets[0], 0, tmpbuf, &len)) != APR_SUCCESS){ ap_log_error(APLOG_MARK, APLOG_ERR, ret, NULL, "error getting data from UDP!!"); }else { /* add checking??? */ } this_worker_should_exit = 1; } } if (this_worker_should_exit) break; if (num_listening_sockets == 1) { sd = ap_listeners->sd; goto got_fd; } else { /* find a listener */ curr_pollfd = last_pollfd; do { curr_pollfd++; if (curr_pollfd > num_listening_sockets) curr_pollfd = 1; /* Get the revent... */ apr_poll_revents_get(&event, listening_sockets[curr_pollfd], pollset); if (event & APR_POLLIN) { last_pollfd = curr_pollfd; sd = listening_sockets[curr_pollfd]; goto got_fd; } } while (curr_pollfd != last_pollfd); } } got_fd: if (!this_worker_should_exit) { rv = apr_accept(&csd, sd, ptrans); apr_thread_mutex_unlock(accept_mutex); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_accept"); } else { process_socket(ptrans, csd, child_slot, bucket_alloc); requests_this_child--; } } else { apr_thread_mutex_unlock(accept_mutex); break; } apr_pool_clear(ptrans); } ap_update_child_status_from_indexes(0, child_slot, SERVER_DEAD, (request_rec*)NULL); apr_bucket_alloc_destroy(bucket_alloc); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "worker_thread %ld exiting", find_thread(NULL)); apr_thread_mutex_lock(worker_thread_count_mutex); worker_thread_count--; apr_thread_mutex_unlock(worker_thread_count_mutex); return (0); }
static void child_main(int child_num_arg) { apr_pool_t *ptrans; apr_allocator_t *allocator; conn_rec *current_conn; apr_status_t status = APR_EINIT; int i; ap_listen_rec *lr; int curr_pollfd, last_pollfd = 0; apr_pollfd_t *pollset; int offset; void *csd; ap_sb_handle_t *sbh; apr_status_t rv; apr_bucket_alloc_t *bucket_alloc; mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ my_child_num = child_num_arg; ap_my_pid = getpid(); csd = NULL; requests_this_child = 0; ap_fatal_signal_child_setup(ap_server_conf); /* Get a sub context for global allocations in this child, so that * we can have cleanups occur when the child exits. */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&pchild, pconf, NULL, allocator); apr_allocator_owner_set(allocator, pchild); apr_pool_create(&ptrans, pchild); apr_pool_tag(ptrans, "transaction"); /* needs to be done before we switch UIDs so we have permissions */ ap_reopen_scoreboard(pchild, NULL, 0); rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "Couldn't initialize cross-process lock in child"); clean_child_exit(APEXIT_CHILDFATAL); } if (unixd_setup_child()) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); ap_create_sb_handle(&sbh, pchild, my_child_num, 0); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* Set up the pollfd array */ listensocks = apr_pcalloc(pchild, sizeof(*listensocks) * (num_listensocks)); for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) { listensocks[i].accept_func = lr->accept_func; listensocks[i].sd = lr->sd; } pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks); pollset[0].p = pchild; for (i = 0; i < num_listensocks; i++) { pollset[i].desc.s = listensocks[i].sd; pollset[i].desc_type = APR_POLL_SOCKET; pollset[i].reqevents = APR_POLLIN; } mpm_state = AP_MPMQ_RUNNING; bucket_alloc = apr_bucket_alloc_create(pchild); while (!die_now) { /* * (Re)initialize this child to a pre-connection state. */ current_conn = NULL; apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { clean_child_exit(0); } (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* * Wait for an acceptable connection to arrive. */ /* Lock around "accept", if necessary */ SAFE_ACCEPT(accept_mutex_on()); if (num_listensocks == 1) { offset = 0; } else { /* multiple listening sockets - need to poll */ for (;;) { apr_status_t ret; apr_int32_t n; ret = apr_poll(pollset, num_listensocks, &n, -1); if (ret != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(ret)) { continue; } /* Single Unix documents select as returning errnos * EBADF, EINTR, and EINVAL... and in none of those * cases does it make sense to continue. In fact * on Linux 2.0.x we seem to end up with EFAULT * occasionally, and we'd loop forever due to it. */ ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf, "apr_poll: (listen)"); clean_child_exit(1); } /* find a listener */ curr_pollfd = last_pollfd; do { curr_pollfd++; if (curr_pollfd >= num_listensocks) { curr_pollfd = 0; } /* XXX: Should we check for POLLERR? */ if (pollset[curr_pollfd].rtnevents & APR_POLLIN) { last_pollfd = curr_pollfd; offset = curr_pollfd; goto got_fd; } } while (curr_pollfd != last_pollfd); continue; } } got_fd: /* if we accept() something we don't want to die, so we have to * defer the exit */ status = listensocks[offset].accept_func(&csd, &listensocks[offset], ptrans); SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ if (status == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1); } else if (status != APR_SUCCESS) { continue; } /* * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. */ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); if (current_conn) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } /* Check the pod and the generation number after processing a * connection so that we'll go away if a graceful restart occurred * while we were processing the connection or we are the lucky * idle server process that gets to die. */ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ die_now = 1; } else if (ap_my_generation != ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ die_now = 1; } } clean_child_exit(0); }
/* This is the thread that actually does all the work. */ static int32 worker_thread(void *dummy) { int worker_slot = (int)dummy; apr_allocator_t *allocator; apr_bucket_alloc_t *bucket_alloc; apr_status_t rv = APR_EINIT; int last_poll_idx = 0; sigset_t sig_mask; int requests_this_child = 0; apr_pollset_t *pollset = NULL; ap_listen_rec *lr = NULL; ap_sb_handle_t *sbh = NULL; int i; /* each worker thread is in control of its own destiny...*/ int this_worker_should_exit = 0; /* We have 2 pools that we create/use throughout the lifetime of this * worker. The first and longest lived is the pworker pool. From * this we create the ptrans pool, the lifetime of which is the same * as each connection and is reset prior to each attempt to * process a connection. */ apr_pool_t *ptrans = NULL; apr_pool_t *pworker = NULL; mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ on_exit_thread(check_restart, (void*)worker_slot); /* block the signals for this thread only if we're not running as a * single process. */ if (!one_process) { sigfillset(&sig_mask); sigprocmask(SIG_BLOCK, &sig_mask, NULL); } /* Each worker thread is fully in control of it's destinay and so * to allow each thread to handle the lifetime of it's own resources * we create and use a subcontext for every thread. * The subcontext is a child of the pconf pool. */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&pworker, pconf, NULL, allocator); apr_allocator_owner_set(allocator, pworker); apr_pool_create(&ptrans, pworker); apr_pool_tag(ptrans, "transaction"); ap_create_sb_handle(&sbh, pworker, 0, worker_slot); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* We add an extra socket here as we add the udp_sock we use for signalling * death. This gets added after the others. */ apr_pollset_create(&pollset, num_listening_sockets + 1, pworker, 0); for (lr = ap_listeners, i = num_listening_sockets; i--; lr = lr->next) { apr_pollfd_t pfd = {0}; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = lr->sd; pfd.reqevents = APR_POLLIN; pfd.client_data = lr; apr_pollset_add(pollset, &pfd); } { apr_pollfd_t pfd = {0}; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = udp_sock; pfd.reqevents = APR_POLLIN; apr_pollset_add(pollset, &pfd); } bucket_alloc = apr_bucket_alloc_create(pworker); mpm_state = AP_MPMQ_RUNNING; while (!this_worker_should_exit) { conn_rec *current_conn; void *csd; /* (Re)initialize this child to a pre-connection state. */ apr_pool_clear(ptrans); if ((ap_max_requests_per_thread > 0 && requests_this_child++ >= ap_max_requests_per_thread)) clean_child_exit(0, worker_slot); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); apr_thread_mutex_lock(accept_mutex); /* We always (presently) have at least 2 sockets we listen on, so * we don't have the ability for a fast path for a single socket * as some MPM's allow :( */ for (;;) { apr_int32_t numdesc = 0; const apr_pollfd_t *pdesc = NULL; rv = apr_pollset_poll(pollset, -1, &numdesc, &pdesc); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { if (one_process && shutdown_pending) return; continue; } ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_pollset_poll: (listen)"); clean_child_exit(1, worker_slot); } /* We can always use pdesc[0], but sockets at position N * could end up completely starved of attention in a very * busy server. Therefore, we round-robin across the * returned set of descriptors. While it is possible that * the returned set of descriptors might flip around and * continue to starve some sockets, we happen to know the * internal pollset implementation retains ordering * stability of the sockets. Thus, the round-robin should * ensure that a socket will eventually be serviced. */ if (last_poll_idx >= numdesc) last_poll_idx = 0; /* Grab a listener record from the client_data of the poll * descriptor, and advance our saved index to round-robin * the next fetch. * * ### hmm... this descriptor might have POLLERR rather * ### than POLLIN */ lr = pdesc[last_poll_idx++].client_data; /* The only socket we add without client_data is the first, the UDP socket * we listen on for restart signals. If we've therefore gotten a hit on that * listener lr will be NULL here and we know we've been told to die. * Before we jump to the end of the while loop with this_worker_should_exit * set to 1 (causing us to exit normally we hope) we release the accept_mutex * as we want every thread to go through this same routine :) * Bit of a hack, but compared to what I had before... */ if (lr == NULL) { this_worker_should_exit = 1; apr_thread_mutex_unlock(accept_mutex); goto got_a_black_spot; } goto got_fd; } got_fd: /* Run beos_accept to accept the connection and set things up to * allow us to process it. We always release the accept_lock here, * even if we failt o accept as otherwise we'll starve other workers * which would be bad. */ rv = beos_accept(&csd, lr, ptrans); apr_thread_mutex_unlock(accept_mutex); if (rv == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1, worker_slot); } else if (rv != APR_SUCCESS) continue; current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, worker_slot, sbh, bucket_alloc); if (current_conn) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } if (ap_my_generation != ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ this_worker_should_exit = 1; } got_a_black_spot: } apr_pool_destroy(ptrans); apr_pool_destroy(pworker); clean_child_exit(0, worker_slot); } static int make_worker(int slot) { thread_id tid; if (slot + 1 > ap_max_child_assigned) ap_max_child_assigned = slot + 1; (void) ap_update_child_status_from_indexes(0, slot, SERVER_STARTING, (request_rec*)NULL); if (one_process) { set_signals(); ap_scoreboard_image->parent[0].pid = getpid(); ap_scoreboard_image->servers[0][slot].tid = find_thread(NULL); return 0; } tid = spawn_thread(worker_thread, "apache_worker", B_NORMAL_PRIORITY, (void *)slot); if (tid < B_NO_ERROR) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "spawn_thread: Unable to start a new thread"); /* In case system resources are maxed out, we don't want * Apache running away with the CPU trying to fork over and * over and over again. */ (void) ap_update_child_status_from_indexes(0, slot, SERVER_DEAD, (request_rec*)NULL); sleep(10); return -1; } resume_thread(tid); ap_scoreboard_image->servers[0][slot].tid = tid; return 0; }
static void child_main(int child_num_arg) { apr_pool_t *ptrans; apr_allocator_t *allocator; apr_status_t status; int i; ap_listen_rec *lr; apr_pollset_t *pollset; ap_sb_handle_t *sbh; apr_bucket_alloc_t *bucket_alloc; int last_poll_idx = 0; mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ my_child_num = child_num_arg; ap_my_pid = getpid(); requests_this_child = 0; ap_fatal_signal_child_setup(ap_server_conf); /* Get a sub context for global allocations in this child, so that * we can have cleanups occur when the child exits. */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&pchild, pconf, NULL, allocator); apr_allocator_owner_set(allocator, pchild); apr_pool_create(&ptrans, pchild); apr_pool_tag(ptrans, "transaction"); /* needs to be done before we switch UIDs so we have permissions */ ap_reopen_scoreboard(pchild, NULL, 0); status = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, "Couldn't initialize cross-process lock in child " "(%s) (%d)", ap_lock_fname, ap_accept_lock_mech); clean_child_exit(APEXIT_CHILDFATAL); } if (unixd_setup_child()) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); ap_create_sb_handle(&sbh, pchild, my_child_num, 0); (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* Set up the pollfd array */ status = apr_pollset_create(&pollset, num_listensocks, pchild, 0); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, "Couldn't create pollset in child; check system or user limits"); clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */ } for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = lr->sd; pfd.reqevents = APR_POLLIN; pfd.client_data = lr; /* ### check the status */ (void) apr_pollset_add(pollset, &pfd); } mpm_state = AP_MPMQ_RUNNING; bucket_alloc = apr_bucket_alloc_create(pchild); /* die_now is set when AP_SIG_GRACEFUL is received in the child; * shutdown_pending is set when SIGTERM is received when running * in single process mode. */ while (!die_now && !shutdown_pending) { conn_rec *current_conn; void *csd; /* * (Re)initialize this child to a pre-connection state. */ apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { clean_child_exit(0); } (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /* * Wait for an acceptable connection to arrive. */ /* Lock around "accept", if necessary */ SAFE_ACCEPT(accept_mutex_on()); if (num_listensocks == 1) { /* There is only one listener record, so refer to that one. */ lr = ap_listeners; } else { /* multiple listening sockets - need to poll */ for (;;) { apr_int32_t numdesc; const apr_pollfd_t *pdesc; /* check for termination first so we don't sleep for a while in * poll if already signalled */ if (one_process && shutdown_pending) { SAFE_ACCEPT(accept_mutex_off()); return; } else if (die_now) { /* In graceful stop/restart; drop the mutex * and terminate the child. */ SAFE_ACCEPT(accept_mutex_off()); clean_child_exit(0); } /* timeout == 10 seconds to avoid a hang at graceful restart/stop * caused by the closing of sockets by the signal handler */ status = apr_pollset_poll(pollset, apr_time_from_sec(10), &numdesc, &pdesc); if (status != APR_SUCCESS) { if (APR_STATUS_IS_TIMEUP(status) || APR_STATUS_IS_EINTR(status)) { continue; } /* Single Unix documents select as returning errnos * EBADF, EINTR, and EINVAL... and in none of those * cases does it make sense to continue. In fact * on Linux 2.0.x we seem to end up with EFAULT * occasionally, and we'd loop forever due to it. */ ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, "apr_pollset_poll: (listen)"); SAFE_ACCEPT(accept_mutex_off()); clean_child_exit(1); } /* We can always use pdesc[0], but sockets at position N * could end up completely starved of attention in a very * busy server. Therefore, we round-robin across the * returned set of descriptors. While it is possible that * the returned set of descriptors might flip around and * continue to starve some sockets, we happen to know the * internal pollset implementation retains ordering * stability of the sockets. Thus, the round-robin should * ensure that a socket will eventually be serviced. */ if (last_poll_idx >= numdesc) last_poll_idx = 0; /* Grab a listener record from the client_data of the poll * descriptor, and advance our saved index to round-robin * the next fetch. * * ### hmm... this descriptor might have POLLERR rather * ### than POLLIN */ lr = pdesc[last_poll_idx++].client_data; goto got_fd; } } got_fd: /* if we accept() something we don't want to die, so we have to * defer the exit */ status = lr->accept_func(&csd, lr, ptrans); SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ if (status == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ clean_child_exit(1); } else if (status != APR_SUCCESS) { continue; } /* * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. */ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); if (current_conn) { ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } /* Check the pod and the generation number after processing a * connection so that we'll go away if a graceful restart occurred * while we were processing the connection or we are the lucky * idle server process that gets to die. */ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ die_now = 1; } else if (ap_my_generation != ap_scoreboard_image->global->running_generation) { /* restart? */ /* yeah, this could be non-graceful restart, in which case the * parent will kill us soon enough, but why bother checking? */ die_now = 1; } } clean_child_exit(0); }
int _tmain(int argc, _TCHAR* argv[]) { // we have three parameters const TCHAR * src = NULL; const TCHAR * dst = NULL; const TCHAR * wc = NULL; BOOL bErrOnMods = FALSE; BOOL bErrOnUnversioned = FALSE; BOOL bErrOnMixed = FALSE; BOOL bQuiet = FALSE; BOOL bUseSubWCRevIgnore = TRUE; SubWCRev_t SubStat; SetDllDirectory(L""); CCrashReportTSVN crasher(L"SubWCRev " _T(APP_X64_STRING)); if (argc >= 2 && argc <= 5) { // WC path is always first argument. wc = argv[1]; } if (argc == 4 || argc == 5) { // SubWCRev Path Tmpl.in Tmpl.out [-params] src = argv[2]; dst = argv[3]; if (!PathFileExists(src)) { _tprintf(L"File '%s' does not exist\n", src); return ERR_FNF; // file does not exist } } if (argc == 3 || argc == 5) { // SubWCRev Path -params // SubWCRev Path Tmpl.in Tmpl.out -params const TCHAR * Params = argv[argc-1]; if (Params[0] == '-') { if (wcschr(Params, 'q') != 0) bQuiet = TRUE; if (wcschr(Params, 'n') != 0) bErrOnMods = TRUE; if (wcschr(Params, 'N') != 0) bErrOnUnversioned = TRUE; if (wcschr(Params, 'm') != 0) bErrOnMixed = TRUE; if (wcschr(Params, 'd') != 0) { if ((dst != NULL) && PathFileExists(dst)) { _tprintf(L"File '%s' already exists\n", dst); return ERR_OUT_EXISTS; } } // the 'f' option is useful to keep the revision which is inserted in // the file constant, even if there are commits on other branches. // For example, if you tag your working copy, then half a year later // do a fresh checkout of that tag, the folder in your working copy of // that tag will get the HEAD revision of the time you check out (or // do an update). The files alone however won't have their last-committed // revision changed at all. if (wcschr(Params, 'f') != 0) SubStat.bFolders = TRUE; if (wcschr(Params, 'e') != 0) SubStat.bExternals = TRUE; if (wcschr(Params, 'E') != 0) SubStat.bExternalsNoMixedRevision = TRUE; if (wcschr(Params, 'x') != 0) SubStat.bHexPlain = TRUE; if (wcschr(Params, 'X') != 0) SubStat.bHexX = TRUE; if (wcschr(Params, 'F') != 0) bUseSubWCRevIgnore = FALSE; } else { // Bad params - abort and display help. wc = NULL; } } if (wc == NULL) { _tprintf(L"SubWCRev %d.%d.%d, Build %d - %s\n\n", TSVN_VERMAJOR, TSVN_VERMINOR, TSVN_VERMICRO, TSVN_VERBUILD, _T(TSVN_PLATFORM)); _putts(_T(HelpText1)); _putts(_T(HelpText2)); _putts(_T(HelpText3)); _putts(_T(HelpText4)); _putts(_T(HelpText5)); return ERR_SYNTAX; } DWORD reqLen = GetFullPathName(wc, 0, NULL, NULL); auto wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(wc, reqLen, wcfullPath.get(), NULL); // GetFullPathName() sometimes returns the full path with the wrong // case. This is not a problem on Windows since its filesystem is // case-insensitive. But for SVN that's a problem if the wrong case // is inside a working copy: the svn wc database is case sensitive. // To fix the casing of the path, we use a trick: // convert the path to its short form, then back to its long form. // That will fix the wrong casing of the path. int shortlen = GetShortPathName(wcfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(wcfullPath.get(), shortPath.get(), shortlen + 1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), wcfullPath.get(), reqLen); } } wc = wcfullPath.get(); std::unique_ptr<TCHAR[]> dstfullPath = nullptr; if (dst) { reqLen = GetFullPathName(dst, 0, NULL, NULL); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(dst, reqLen, dstfullPath.get(), NULL); shortlen = GetShortPathName(dstfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(dstfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); dstfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), dstfullPath.get(), reqLen); } } dst = dstfullPath.get(); } std::unique_ptr<TCHAR[]> srcfullPath = nullptr; if (src) { reqLen = GetFullPathName(src, 0, NULL, NULL); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetFullPathName(src, reqLen, srcfullPath.get(), NULL); shortlen = GetShortPathName(srcfullPath.get(), NULL, 0); if (shortlen) { auto shortPath = std::make_unique<TCHAR[]>(shortlen + 1); if (GetShortPathName(srcfullPath.get(), shortPath.get(), shortlen+1)) { reqLen = GetLongPathName(shortPath.get(), NULL, 0); srcfullPath = std::make_unique<TCHAR[]>(reqLen + 1); GetLongPathName(shortPath.get(), srcfullPath.get(), reqLen); } } src = srcfullPath.get(); } if (!PathFileExists(wc)) { _tprintf(L"Directory or file '%s' does not exist\n", wc); if (wcschr(wc, '\"') != NULL) // dir contains a quotation mark { _tprintf(L"The WorkingCopyPath contains a quotation mark.\n"); _tprintf(L"this indicates a problem when calling SubWCRev from an interpreter which treats\n"); _tprintf(L"a backslash char specially.\n"); _tprintf(L"Try using double backslashes or insert a dot after the last backslash when\n"); _tprintf(L"calling SubWCRev\n"); _tprintf(L"Examples:\n"); _tprintf(L"SubWCRev \"path to wc\\\\\"\n"); _tprintf(L"SubWCRev \"path to wc\\.\"\n"); } return ERR_FNF; // dir does not exist } std::unique_ptr<char[]> pBuf = nullptr; DWORD readlength = 0; size_t filelength = 0; size_t maxlength = 0; if (dst != NULL) { // open the file and read the contents CAutoFile hFile = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (!hFile) { _tprintf(L"Unable to open input file '%s'\n", src); return ERR_OPEN; // error opening file } filelength = GetFileSize(hFile, NULL); if (filelength == INVALID_FILE_SIZE) { _tprintf(L"Could not determine file size of '%s'\n", src); return ERR_READ; } maxlength = filelength+4096; // We might be increasing file size. pBuf = std::make_unique<char[]>(maxlength); if (pBuf == NULL) { _tprintf(L"Could not allocate enough memory!\n"); return ERR_ALLOC; } if (!ReadFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, NULL)) { _tprintf(L"Could not read the file '%s'\n", src); return ERR_READ; } if (readlength != filelength) { _tprintf(L"Could not read the file '%s' to the end!\n", src); return ERR_READ; } } // Now check the status of every file in the working copy // and gather revision status information in SubStat. apr_pool_t * pool; svn_error_t * svnerr = NULL; svn_client_ctx_t * ctx; const char * internalpath; apr_initialize(); svn_dso_initialize2(); apr_pool_create_ex (&pool, NULL, abort_on_pool_failure, NULL); svn_client_create_context2(&ctx, NULL, pool); size_t ret = 0; getenv_s(&ret, NULL, 0, "SVN_ASP_DOT_NET_HACK"); if (ret) { svn_wc_set_adm_dir("_svn", pool); } char *wc_utf8 = Utf16ToUtf8(wc, pool); internalpath = svn_dirent_internal_style (wc_utf8, pool); if (bUseSubWCRevIgnore) { const char *wcroot; svnerr = svn_client_get_wc_root(&wcroot, internalpath, ctx, pool, pool); if ((svnerr == SVN_NO_ERROR) && wcroot) LoadIgnorePatterns(wcroot, &SubStat); svn_error_clear(svnerr); LoadIgnorePatterns(internalpath, &SubStat); } svnerr = svn_status( internalpath, //path &SubStat, //status_baton TRUE, //noignore ctx, pool); if (svnerr) { svn_handle_error2(svnerr, stdout, FALSE, "SubWCRev : "); } TCHAR wcfullpath[MAX_PATH] = { 0 }; LPTSTR dummy; GetFullPathName(wc, MAX_PATH, wcfullpath, &dummy); apr_status_t e = 0; if (svnerr) { e = svnerr->apr_err; svn_error_clear(svnerr); } apr_terminate2(); if (svnerr) { if (e == SVN_ERR_WC_NOT_DIRECTORY) return ERR_NOWC; return ERR_SVN_ERR; } char wcfull_oem[MAX_PATH] = { 0 }; CharToOem(wcfullpath, wcfull_oem); _tprintf(L"SubWCRev: '%hs'\n", wcfull_oem); if (bErrOnMods && SubStat.HasMods) { _tprintf(L"Working copy has local modifications!\n"); return ERR_SVN_MODS; } if (bErrOnUnversioned && SubStat.HasUnversioned) { _tprintf(L"Working copy has unversioned items!\n"); return ERR_SVN_UNVER; } if (bErrOnMixed && (SubStat.MinRev != SubStat.MaxRev)) { if (SubStat.bHexPlain) _tprintf(L"Working copy contains mixed revisions %lX:%lX!\n", SubStat.MinRev, SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Working copy contains mixed revisions %#lX:%#lX!\n", SubStat.MinRev, SubStat.MaxRev); else _tprintf(L"Working copy contains mixed revisions %ld:%ld!\n", SubStat.MinRev, SubStat.MaxRev); return ERR_SVN_MIXED; } if (!bQuiet) { if (SubStat.bHexPlain) _tprintf(L"Last committed at revision %lX\n", SubStat.CmtRev); else if (SubStat.bHexX) _tprintf(L"Last committed at revision %#lX\n", SubStat.CmtRev); else _tprintf(L"Last committed at revision %ld\n", SubStat.CmtRev); if (SubStat.MinRev != SubStat.MaxRev) { if (SubStat.bHexPlain) _tprintf(L"Mixed revision range %lX:%lX\n", SubStat.MinRev, SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Mixed revision range %#lX:%#lX\n", SubStat.MinRev, SubStat.MaxRev); else _tprintf(L"Mixed revision range %ld:%ld\n", SubStat.MinRev, SubStat.MaxRev); } else { if (SubStat.bHexPlain) _tprintf(L"Updated to revision %lX\n", SubStat.MaxRev); else if (SubStat.bHexX) _tprintf(L"Updated to revision %#lX\n", SubStat.MaxRev); else _tprintf(L"Updated to revision %ld\n", SubStat.MaxRev); } if (SubStat.HasMods) { _tprintf(L"Local modifications found\n"); } if (SubStat.HasUnversioned) { _tprintf(L"Unversioned items found\n"); } } if (dst == NULL) { return 0; } // now parse the file contents for version defines. size_t index = 0; while (InsertRevision(VERDEF, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFAND, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFAND), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFOFFSET1, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFOFFSET1), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(VERDEFOFFSET2, pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(VERDEFOFFSET2), (wchar_t*)pBuf.get(), index, filelength, maxlength, -1, SubStat.CmtRev, &SubStat)); index = 0; while (InsertRevision(RANGEDEF, pBuf.get(), index, filelength, maxlength, SubStat.MinRev, SubStat.MaxRev, &SubStat)); index = 0; while (InsertRevisionW(TEXT(RANGEDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.MinRev, SubStat.MaxRev, &SubStat)); index = 0; while (InsertDate(DATEDEF, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEWFMTDEF, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(DATEWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDateW(TEXT(DATEWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.CmtDate)); index = 0; while (InsertDate(NOWDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEF, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDate(NOWWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertDateW(TEXT(NOWWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, USE_TIME_NOW)); index = 0; while (InsertBoolean(MODDEF, pBuf.get(), index, filelength, SubStat.HasMods)); index = 0; while (InsertBooleanW(TEXT(MODDEF), (wchar_t*)pBuf.get(), index, filelength, SubStat.HasMods)); index = 0; while (InsertBoolean(UNVERDEF, pBuf.get(), index, filelength, SubStat.HasUnversioned)); index = 0; while (InsertBooleanW(TEXT(UNVERDEF), (wchar_t*)pBuf.get(), index, filelength, SubStat.HasUnversioned)); index = 0; while (InsertBoolean(MIXEDDEF, pBuf.get(), index, filelength, (SubStat.MinRev != SubStat.MaxRev) || SubStat.bIsExternalMixed)); index = 0; while (InsertBooleanW(TEXT(MIXEDDEF), (wchar_t*)pBuf.get(), index, filelength, (SubStat.MinRev != SubStat.MaxRev) || SubStat.bIsExternalMixed)); index = 0; while (InsertBoolean(EXTALLFIXED, pBuf.get(), index, filelength, !SubStat.bIsExternalsNotFixed)); index = 0; while (InsertBooleanW(TEXT(EXTALLFIXED), (wchar_t*)pBuf.get(), index, filelength, !SubStat.bIsExternalsNotFixed)); index = 0; while (InsertBoolean(ISTAGGED, pBuf.get(), index, filelength, SubStat.bIsTagged)); index = 0; while (InsertBooleanW(TEXT(ISTAGGED), (wchar_t*)pBuf.get(), index, filelength, SubStat.bIsTagged)); index = 0; while (InsertUrl(URLDEF, pBuf.get(), index, filelength, maxlength, SubStat.Url)); index = 0; while (InsertUrlW(TEXT(URLDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.Url).c_str())); index = 0; while (InsertBoolean(ISINSVN, pBuf.get(), index, filelength, SubStat.bIsSvnItem)); index = 0; while (InsertBooleanW(TEXT(ISINSVN), (wchar_t*)pBuf.get(), index, filelength, SubStat.bIsSvnItem)); index = 0; while (InsertBoolean(NEEDSLOCK, pBuf.get(), index, filelength, SubStat.LockData.NeedsLocks)); index = 0; while (InsertBooleanW(TEXT(NEEDSLOCK), (wchar_t*)pBuf.get(), index, filelength, SubStat.LockData.NeedsLocks)); index = 0; while (InsertBoolean(ISLOCKED, pBuf.get(), index, filelength, SubStat.LockData.IsLocked)); index = 0; while (InsertBooleanW(TEXT(ISLOCKED), (wchar_t*)pBuf.get(), index, filelength, SubStat.LockData.IsLocked)); index = 0; while (InsertDate(LOCKDATE, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKDATE), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKDATEUTC, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKDATEUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKWFMTDEF, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKWFMTDEF), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDate(LOCKWFMTDEFUTC, pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertDateW(TEXT(LOCKWFMTDEFUTC), (wchar_t*)pBuf.get(), index, filelength, maxlength, SubStat.LockData.CreationDate)); index = 0; while (InsertUrl(LOCKOWNER, pBuf.get(), index, filelength, maxlength, SubStat.LockData.Owner)); index = 0; while (InsertUrlW(TEXT(LOCKOWNER), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.LockData.Owner).c_str())); index = 0; while (InsertUrl(LOCKCOMMENT, pBuf.get(), index, filelength, maxlength, SubStat.LockData.Comment)); index = 0; while (InsertUrlW(TEXT(LOCKCOMMENT), (wchar_t*)pBuf.get(), index, filelength, maxlength, Utf8ToWide(SubStat.LockData.Comment).c_str())); CAutoFile hFile = CreateFile(dst, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL); if (!hFile) { _tprintf(L"Unable to open output file '%s' for writing\n", dst); return ERR_OPEN; } size_t filelengthExisting = GetFileSize(hFile, NULL); BOOL sameFileContent = FALSE; if (filelength == filelengthExisting) { DWORD readlengthExisting = 0; auto pBufExisting = std::make_unique<char[]>(filelength); if (!ReadFile(hFile, pBufExisting.get(), (DWORD)filelengthExisting, &readlengthExisting, NULL)) { _tprintf(L"Could not read the file '%s'\n", dst); return ERR_READ; } if (readlengthExisting != filelengthExisting) { _tprintf(L"Could not read the file '%s' to the end!\n", dst); return ERR_READ; } sameFileContent = (memcmp(pBuf.get(), pBufExisting.get(), filelength) == 0); } // The file is only written if its contents would change. // this object prevents the timestamp from changing. if (!sameFileContent) { SetFilePointer(hFile, 0, NULL, FILE_BEGIN); WriteFile(hFile, pBuf.get(), (DWORD)filelength, &readlength, NULL); if (readlength != filelength) { _tprintf(L"Could not write the file '%s' to the end!\n", dst); return ERR_READ; } if (!SetEndOfFile(hFile)) { _tprintf(L"Could not truncate the file '%s' to the end!\n", dst); return ERR_READ; } } return 0; }
PCOMP_CONTEXT mpm_get_completion_context(void) { apr_status_t rv; PCOMP_CONTEXT context = NULL; while (1) { /* Grab a context off the queue */ apr_thread_mutex_lock(qlock); if (qhead) { context = qhead; qhead = qhead->next; if (!qhead) qtail = NULL; } else { ResetEvent(qwait_event); } apr_thread_mutex_unlock(qlock); if (!context) { /* We failed to grab a context off the queue, consider allocating * a new one out of the child pool. There may be up to * (ap_threads_per_child + num_listeners) contexts in the system * at once. */ if (num_completion_contexts >= max_num_completion_contexts) { /* All workers are busy, need to wait for one */ static int reported = 0; if (!reported) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, "Server ran out of threads to serve requests. Consider " "raising the ThreadsPerChild setting"); reported = 1; } /* Wait for a worker to free a context. Once per second, give * the caller a chance to check for shutdown. If the wait * succeeds, get the context off the queue. It must be available, * since there's only one consumer. */ rv = WaitForSingleObject(qwait_event, 1000); if (rv == WAIT_OBJECT_0) continue; else /* Hopefully, WAIT_TIMEOUT */ return NULL; } else { /* Allocate another context. * Note: * Multiple failures in the next two steps will cause the pchild pool * to 'leak' storage. I don't think this is worth fixing... */ apr_allocator_t *allocator; apr_thread_mutex_lock(child_lock); context = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); context->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (context->Overlapped.hEvent == NULL) { /* Hopefully this is a temporary condition ... */ ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_os_error(), ap_server_conf, "mpm_get_completion_context: CreateEvent failed."); apr_thread_mutex_unlock(child_lock); return NULL; } /* Create the tranaction pool */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); rv = apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK,APLOG_WARNING, rv, ap_server_conf, "mpm_get_completion_context: Failed to create the transaction pool."); CloseHandle(context->Overlapped.hEvent); apr_thread_mutex_unlock(child_lock); return NULL; } apr_allocator_owner_set(allocator, context->ptrans); apr_pool_tag(context->ptrans, "transaction"); context->accept_socket = INVALID_SOCKET; context->ba = apr_bucket_alloc_create(context->ptrans); apr_atomic_inc32(&num_completion_contexts); apr_thread_mutex_unlock(child_lock); break; } } else { /* Got a context from the queue */ break; } } return context; }
/*static */ void worker_main(void *arg) { ap_listen_rec *lr, *first_lr, *last_lr = NULL; apr_pool_t *ptrans; apr_allocator_t *allocator; apr_bucket_alloc_t *bucket_alloc; conn_rec *current_conn; apr_status_t stat = APR_EINIT; ap_sb_handle_t *sbh; apr_thread_t *thd = NULL; apr_os_thread_t osthd; int my_worker_num = (int)arg; apr_socket_t *csd = NULL; int requests_this_child = 0; apr_socket_t *sd = NULL; fd_set main_fds; int sockdes; int srv; struct timeval tv; int wouldblock_retry; osthd = apr_os_thread_current(); apr_os_thread_put(&thd, &osthd, pmain); tv.tv_sec = 1; tv.tv_usec = 0; apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&ptrans, pmain, NULL, allocator); apr_allocator_owner_set(allocator, ptrans); apr_pool_tag(ptrans, "transaction"); bucket_alloc = apr_bucket_alloc_create_ex(allocator); atomic_inc (&worker_thread_count); while (!die_now) { /* * (Re)initialize this child to a pre-connection state. */ current_conn = NULL; apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num); clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); } ap_update_child_status_from_indexes(0, my_worker_num, WORKER_READY, (request_rec *) NULL); /* * Wait for an acceptable connection to arrive. */ for (;;) { if (shutdown_pending || restart_pending || (ap_scoreboard_image->servers[0][my_worker_num].status == WORKER_IDLE_KILL)) { DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num); clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); } /* Check the listen queue on all sockets for requests */ memcpy(&main_fds, &listenfds, sizeof(fd_set)); srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); if (srv <= 0) { if (srv < 0) { ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00217) "select() failed on listen socket"); apr_thread_yield(); } continue; } /* remember the last_lr we searched last time around so that we don't end up starving any particular listening socket */ if (last_lr == NULL) { lr = ap_listeners; } else { lr = last_lr->next; if (!lr) lr = ap_listeners; } first_lr = lr; do { apr_os_sock_get(&sockdes, lr->sd); if (FD_ISSET(sockdes, &main_fds)) goto got_listener; lr = lr->next; if (!lr) lr = ap_listeners; } while (lr != first_lr); /* if we get here, something unexpected happened. Go back into the select state and try again. */ continue; got_listener: last_lr = lr; sd = lr->sd; wouldblock_retry = MAX_WB_RETRIES; while (wouldblock_retry) { if ((stat = apr_socket_accept(&csd, sd, ptrans)) == APR_SUCCESS) { break; } else { /* if the error is a wouldblock then maybe we were too quick try to pull the next request from the listen queue. Try a few more times then return to our idle listen state. */ if (!APR_STATUS_IS_EAGAIN(stat)) { break; } if (wouldblock_retry--) { apr_thread_yield(); } } } /* If we got a new socket, set it to non-blocking mode and process it. Otherwise handle the error. */ if (stat == APR_SUCCESS) { apr_socket_opt_set(csd, APR_SO_NONBLOCK, 0); #ifdef DBINFO_ON if (wouldblock_retry < MAX_WB_RETRIES) { retry_success++; avg_retries += (MAX_WB_RETRIES-wouldblock_retry); } #endif break; /* We have a socket ready for reading */ } else { #ifdef DBINFO_ON if (APR_STATUS_IS_EAGAIN(stat)) { would_block++; retry_fail++; } else if ( #else if (APR_STATUS_IS_EAGAIN(stat) || #endif APR_STATUS_IS_ECONNRESET(stat) || APR_STATUS_IS_ETIMEDOUT(stat) || APR_STATUS_IS_EHOSTUNREACH(stat) || APR_STATUS_IS_ENETUNREACH(stat)) { ; } #ifdef USE_WINSOCK else if (APR_STATUS_IS_ENETDOWN(stat)) { /* * When the network layer has been shut down, there * is not much use in simply exiting: the parent * would simply re-create us (and we'd fail again). * Use the CHILDFATAL code to tear the server down. * @@@ Martin's idea for possible improvement: * A different approach would be to define * a new APEXIT_NETDOWN exit code, the reception * of which would make the parent shutdown all * children, then idle-loop until it detected that * the network is up again, and restart the children. * Ben Hyde noted that temporary ENETDOWN situations * occur in mobile IP. */ ap_log_error(APLOG_MARK, APLOG_EMERG, stat, ap_server_conf, APLOGNO(00218) "apr_socket_accept: giving up."); clean_child_exit(APEXIT_CHILDFATAL, my_worker_num, ptrans, bucket_alloc); } #endif else { ap_log_error(APLOG_MARK, APLOG_ERR, stat, ap_server_conf, APLOGNO(00219) "apr_socket_accept: (client socket)"); clean_child_exit(1, my_worker_num, ptrans, bucket_alloc); } } } ap_create_sb_handle(&sbh, ptrans, 0, my_worker_num); /* * We now have a connection, so set it up with the appropriate * socket options, file descriptors, and read/write buffers. */ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_worker_num, sbh, bucket_alloc); if (current_conn) { current_conn->current_thread = thd; ap_process_connection(current_conn, csd); ap_lingering_close(current_conn); } request_count++; } clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); }
conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent) { apr_allocator_t *allocator; apr_status_t status; apr_pool_t *pool; conn_rec *c; void *cfg; module *mpm; ap_assert(master); ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, master, "h2_stream(%ld-%d): create slave", master->id, slave_id); /* We create a pool with its own allocator to be used for * processing a request. This is the only way to have the processing * independant of its parent pool in the sense that it can work in * another thread. Also, the new allocator needs its own mutex to * synchronize sub-pools. */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); status = apr_pool_create_ex(&pool, parent, NULL, allocator); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, status, master, APLOGNO(10004) "h2_session(%ld-%d): create slave pool", master->id, slave_id); return NULL; } apr_allocator_owner_set(allocator, pool); apr_pool_abort_set(abort_on_oom, pool); apr_pool_tag(pool, "h2_slave_conn"); c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec)); if (c == NULL) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master, APLOGNO(02913) "h2_session(%ld-%d): create slave", master->id, slave_id); apr_pool_destroy(pool); return NULL; } memcpy(c, master, sizeof(conn_rec)); c->master = master; c->pool = pool; c->conn_config = ap_create_conn_config(pool); c->notes = apr_table_make(pool, 5); c->input_filters = NULL; c->output_filters = NULL; c->keepalives = 0; #if AP_MODULE_MAGIC_AT_LEAST(20180903, 1) c->filter_conn_ctx = NULL; #endif c->bucket_alloc = apr_bucket_alloc_create(pool); #if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1) c->data_in_input_filters = 0; c->data_in_output_filters = 0; #endif /* prevent mpm_event from making wrong assumptions about this connection, * like e.g. using its socket for an async read check. */ c->clogging_input_filters = 1; c->log = NULL; c->log_id = apr_psprintf(pool, "%ld-%d", master->id, slave_id); c->aborted = 0; /* We cannot install the master connection socket on the slaves, as * modules mess with timeouts/blocking of the socket, with * unwanted side effects to the master connection processing. * Fortunately, since we never use the slave socket, we can just install * a single, process-wide dummy and everyone is happy. */ ap_set_module_config(c->conn_config, &core_module, dummy_socket); /* TODO: these should be unique to this thread */ c->sbh = master->sbh; /* TODO: not all mpm modules have learned about slave connections yet. * copy their config from master to slave. */ if ((mpm = h2_conn_mpm_module()) != NULL) { cfg = ap_get_module_config(master->conn_config, mpm); ap_set_module_config(c->conn_config, mpm, cfg); } ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c, "h2_slave(%s): created", c->log_id); return c; }
BOOL CDiffData::Load() { m_arBaseFile.RemoveAll(); m_arYourFile.RemoveAll(); m_arTheirFile.RemoveAll(); m_YourBaseBoth.Clear(); m_YourBaseLeft.Clear(); m_YourBaseRight.Clear(); m_TheirBaseBoth.Clear(); m_TheirBaseLeft.Clear(); m_TheirBaseRight.Clear(); m_Diff3.Clear(); CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreWS")); CRegDWORD regIgnoreEOL = CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreEOL"), TRUE); CRegDWORD regIgnoreCase = CRegDWORD(_T("Software\\TortoiseMerge\\CaseInsensitive"), FALSE); CRegDWORD regIgnoreComments = CRegDWORD(_T("Software\\TortoiseMerge\\IgnoreComments"), FALSE); DWORD dwIgnoreWS = regIgnoreWS; bool bIgnoreEOL = ((DWORD)regIgnoreEOL)!=0; BOOL bIgnoreCase = ((DWORD)regIgnoreCase)!=0; bool bIgnoreComments = ((DWORD)regIgnoreComments)!=0; // The Subversion diff API only can ignore whitespaces and eol styles. // It also can only handle one-byte charsets. // To ignore case changes or to handle UTF-16 files, we have to // save the original file in UTF-8 and/or the letters changed to lowercase // so the Subversion diff can handle those. CString sConvertedBaseFilename = m_baseFile.GetFilename(); CString sConvertedYourFilename = m_yourFile.GetFilename(); CString sConvertedTheirFilename = m_theirFile.GetFilename(); m_baseFile.StoreFileAttributes(); m_theirFile.StoreFileAttributes(); m_yourFile.StoreFileAttributes(); //m_mergedFile.StoreFileAttributes(); bool bBaseNeedConvert = false; bool bTheirNeedConvert = false; bool bYourNeedConvert = false; bool bBaseIsUtf8 = false; bool bTheirIsUtf8 = false; bool bYourIsUtf8 = false; // in case at least one of the files got converted or is UTF8 // we have to convert all non UTF8 (ASCII) files // otherwise one file might be in ANSI and the other in UTF8 and we'll end up // with lines marked as different throughout the files even though the lines // would show no change at all in the viewer. bool bIsNotUtf8 = false; // Any non UTF8 file ? if (IsBaseFileInUse()) { if (!m_arBaseFile.Load(m_baseFile.GetFilename())) { m_sError = m_arBaseFile.GetErrorString(); return FALSE; } bBaseNeedConvert = bIgnoreCase || bIgnoreComments || (m_arBaseFile.NeedsConversion()) || !m_rx._Empty(); bBaseIsUtf8 = (m_arBaseFile.GetUnicodeType()!=CFileTextLines::ASCII) || bBaseNeedConvert; bIsNotUtf8 |= !bBaseIsUtf8; } if (IsTheirFileInUse()) { // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file // It's a fair guess that the files will be roughly the same size if (!m_arTheirFile.Load(m_theirFile.GetFilename(), m_arBaseFile.GetCount())) { m_sError = m_arTheirFile.GetErrorString(); return FALSE; } bTheirNeedConvert = bIgnoreCase || bIgnoreComments || (m_arTheirFile.NeedsConversion()) || !m_rx._Empty(); bTheirIsUtf8 = (m_arTheirFile.GetUnicodeType()!=CFileTextLines::ASCII) || bTheirNeedConvert; bIsNotUtf8 |= !bTheirIsUtf8; } if (IsYourFileInUse()) { // m_arBaseFile.GetCount() is passed as a hint for the number of lines in this file // It's a fair guess that the files will be roughly the same size if (!m_arYourFile.Load(m_yourFile.GetFilename(), m_arBaseFile.GetCount())) { m_sError = m_arYourFile.GetErrorString(); return FALSE; } bYourNeedConvert = bIgnoreCase || bIgnoreComments || (m_arYourFile.NeedsConversion()) || !m_rx._Empty(); bYourIsUtf8 = (m_arYourFile.GetUnicodeType()!=CFileTextLines::ASCII) || bYourNeedConvert; bIsNotUtf8 |= !bYourIsUtf8; } // convert all files we need to bool bIsUtf8 = bBaseIsUtf8 || bTheirIsUtf8 || bYourIsUtf8; // any file end as UTF8 bBaseNeedConvert |= (IsBaseFileInUse() && !bBaseIsUtf8 && bIsUtf8); if (bBaseNeedConvert) { sConvertedBaseFilename = CTempFiles::Instance().GetTempFilePathString(); m_baseFile.SetConvertedFileName(sConvertedBaseFilename); m_arBaseFile.Save(sConvertedBaseFilename, true, true, 0, bIgnoreCase, m_bBlame , bIgnoreComments, m_CommentLineStart, m_CommentBlockStart, m_CommentBlockEnd , m_rx, m_replacement); } bYourNeedConvert |= (IsYourFileInUse() && !bYourIsUtf8 && bIsUtf8); if (bYourNeedConvert) { sConvertedYourFilename = CTempFiles::Instance().GetTempFilePathString(); m_yourFile.SetConvertedFileName(sConvertedYourFilename); m_arYourFile.Save(sConvertedYourFilename, true, true, 0, bIgnoreCase, m_bBlame , bIgnoreComments, m_CommentLineStart, m_CommentBlockStart, m_CommentBlockEnd , m_rx, m_replacement); } bTheirNeedConvert |= (IsTheirFileInUse() && !bTheirIsUtf8 && bIsUtf8); if (bTheirNeedConvert) { sConvertedTheirFilename = CTempFiles::Instance().GetTempFilePathString(); m_theirFile.SetConvertedFileName(sConvertedTheirFilename); m_arTheirFile.Save(sConvertedTheirFilename, true, true, 0, bIgnoreCase, m_bBlame , bIgnoreComments, m_CommentLineStart, m_CommentBlockStart, m_CommentBlockEnd , m_rx, m_replacement); } // Calculate the number of lines in the largest of the three files int lengthHint = GetLineCount(); try { m_YourBaseBoth.Reserve(lengthHint); m_YourBaseLeft.Reserve(lengthHint); m_YourBaseRight.Reserve(lengthHint); m_TheirBaseBoth.Reserve(lengthHint); m_TheirBaseLeft.Reserve(lengthHint); m_TheirBaseRight.Reserve(lengthHint); } catch (CMemoryException* e) { e->GetErrorMessage(m_sError.GetBuffer(255), 255); m_sError.ReleaseBuffer(); e->Delete(); return FALSE; } apr_pool_t * pool = NULL; apr_pool_create_ex (&pool, NULL, abort_on_pool_failure, NULL); // Is this a two-way diff? if (IsBaseFileInUse() && IsYourFileInUse() && !IsTheirFileInUse()) { if (!DoTwoWayDiff(sConvertedBaseFilename, sConvertedYourFilename, dwIgnoreWS, bIgnoreEOL, pool)) { apr_pool_destroy (pool); // free the allocated memory return FALSE; } } if (IsBaseFileInUse() && IsTheirFileInUse() && !IsYourFileInUse()) { ASSERT(FALSE); } // Is this a three-way diff? if (IsBaseFileInUse() && IsTheirFileInUse() && IsYourFileInUse()) { m_Diff3.Reserve(lengthHint); if (!DoThreeWayDiff(sConvertedBaseFilename, sConvertedYourFilename, sConvertedTheirFilename, dwIgnoreWS, bIgnoreEOL, !!bIgnoreCase, pool)) { apr_pool_destroy (pool); // free the allocated memory return FALSE; } } // free the allocated memory apr_pool_destroy (pool); m_arBaseFile.RemoveAll(); m_arYourFile.RemoveAll(); m_arTheirFile.RemoveAll(); return TRUE; }
static winnt_conn_ctx_t *mpm_get_completion_context(int *timeout) { apr_status_t rv; winnt_conn_ctx_t *context = NULL; *timeout = 0; while (1) { /* Grab a context off the queue */ apr_thread_mutex_lock(qlock); if (qhead) { context = qhead; qhead = qhead->next; if (!qhead) qtail = NULL; } else { ResetEvent(qwait_event); } apr_thread_mutex_unlock(qlock); if (!context) { /* We failed to grab a context off the queue, consider allocating * a new one out of the child pool. There may be up to * (ap_threads_per_child + num_listeners) contexts in the system * at once. */ if (num_completion_contexts >= max_num_completion_contexts) { /* All workers are busy, need to wait for one */ static int reported = 0; if (!reported) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00326) "Server ran out of threads to serve " "requests. Consider raising the " "ThreadsPerChild setting"); reported = 1; } /* Wait for a worker to free a context. Once per second, give * the caller a chance to check for shutdown. If the wait * succeeds, get the context off the queue. It must be * available, since there's only one consumer. */ rv = WaitForSingleObject(qwait_event, 1000); if (rv == WAIT_OBJECT_0) continue; else { if (rv == WAIT_TIMEOUT) { /* somewhat-normal condition where threads are busy */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00327) "mpm_get_completion_context: Failed to get a " "free context within 1 second"); *timeout = 1; } else { /* should be the unexpected, generic WAIT_FAILED */ ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), ap_server_conf, APLOGNO(00328) "mpm_get_completion_context: " "WaitForSingleObject failed to get free context"); } return NULL; } } else { /* Allocate another context. * Note: Multiple failures in the next two steps will cause * the pchild pool to 'leak' storage. I don't think this * is worth fixing... */ apr_allocator_t *allocator; apr_thread_mutex_lock(child_lock); context = (winnt_conn_ctx_t *)apr_pcalloc(pchild, sizeof(winnt_conn_ctx_t)); context->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (context->overlapped.hEvent == NULL) { /* Hopefully this is a temporary condition ... */ ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), ap_server_conf, APLOGNO(00329) "mpm_get_completion_context: " "CreateEvent failed."); apr_thread_mutex_unlock(child_lock); return NULL; } /* Create the transaction pool */ apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); rv = apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00330) "mpm_get_completion_context: Failed " "to create the transaction pool."); CloseHandle(context->overlapped.hEvent); apr_thread_mutex_unlock(child_lock); return NULL; } apr_allocator_owner_set(allocator, context->ptrans); apr_pool_tag(context->ptrans, "transaction"); context->accept_socket = INVALID_SOCKET; context->ba = apr_bucket_alloc_create(context->ptrans); apr_atomic_inc32(&num_completion_contexts); apr_thread_mutex_unlock(child_lock); break; } } else { /* Got a context from the queue */ break; } } return context; }