static void lock_grab(test_mode_e test_mode) { if (test_mode == TEST_PROC) { assert(apr_proc_mutex_lock(proc_mutex) == APR_SUCCESS); } else { assert(apr_global_mutex_lock(global_mutex) == APR_SUCCESS); } }
static int JK_METHOD jk2_mutex_proc_lock(jk_env_t *env, jk_mutex_t *jkMutex) { apr_proc_mutex_t *mutex=(apr_proc_mutex_t *)jkMutex->privateData; apr_status_t st; st=apr_proc_mutex_lock( mutex ); return st; }
static void update_global_snap(global_snapshot *gs, process_stats_t *ps, request_rec *r) { gs->discarded += apr_atomic_read32(&ps->discarded); apr_proc_mutex_lock(ps->mutex); gs->rec_count += ps->count_slot; gs->total_mb += ps->total_kb / 1024.0; gs->total_queuetime_ms += ps->total_queuetime / 1000.0; gs->total_writetime_ms += ps->total_writetime / 1000.0; apr_proc_mutex_unlock(ps->mutex); }
void tee_update_saved_file_stats(tee_saved_request *sr) { apr_proc_mutex_lock(process_stats->mutex); process_stats->count_process++; process_stats->count_slot++; process_stats->total_kb += sr->filesize / 1024; process_stats->total_queuetime += sr->time_dequeued - sr->time_enqueued; if (sr->time_written) { process_stats->total_writetime += sr->time_written - sr->time_dequeued; } apr_proc_mutex_unlock(process_stats->mutex); }
static process_snapshot *get_snapshot(apr_pool_t *p, process_stats_t *s) { process_snapshot *ss = apr_pcalloc(p, sizeof(process_snapshot)); ss->discarded = apr_atomic_read32(&s->discarded); ss->status = apr_atomic_read32(&s->status); ss->queue_len = apr_atomic_read32(&s->queue_len); apr_proc_mutex_lock(s->mutex); ss->count_process = s->count_process; ss->count_slot = s->count_slot; apr_proc_mutex_unlock(s->mutex); return ss; }
static cache * cacheCreate (int maxsize, int timeout, unsigned long hash, request_data *rd) /*{{{ */ { // create pool for cache to live in apr_status_t s; apr_pool_t *p; s = apr_pool_create (&p, (apr_pool_t *) NULL); if (s != APR_SUCCESS) { ap_log_error(APLOG_MARK,LOG_WARNING,0,rd->server,"cacheCreate: could not create memory pool"); raise_exn ((int) &exn_OVERFLOW); } cache *c = (cache *) apr_palloc (p, sizeof (cache)); if (c == NULL) { ap_log_error(APLOG_MARK,LOG_WARNING,0,rd->server,"cacheCreate: could not allocate memory from pool"); raise_exn ((int) &exn_OVERFLOW); } ap_log_error(APLOG_MARK,LOG_DEBUG,0,rd->server,"cacheCreate: 0x%x", (unsigned int) c); c->pool = p; c->hashofname = hash; apr_proc_mutex_lock(rd->ctx->cachelock.plock); unsigned long cachehash = hash % rd->ctx->cachelock.shmsize; c->version = rd->ctx->cachelock.version[cachehash]; apr_proc_mutex_unlock(rd->ctx->cachelock.plock); // setup locks apr_thread_rwlock_create (&(c->rwlock), c->pool); apr_thread_mutex_create (&(c->mutex), APR_THREAD_MUTEX_DEFAULT, c->pool); // setup linked list c->sentinel = (entry *) apr_palloc (c->pool, sizeof (entry)); c->sentinel->up = c->sentinel; c->sentinel->down = c->sentinel; c->sentinel->key = NULL; // c->sentinel->key.hash = 0; c->sentinel->data = NULL; c->sentinel->size = 0; // setup hashtable & binary heap c->htable = (entrytable_hashtable_t *) apr_palloc (c->pool, sizeof (entrytable_hashtable_t) + sizeof(cacheheap_binaryheap_t)); c->heap = (cacheheap_binaryheap_t *) (c->htable + 1); entrytable_init (c->htable); cacheheap_heapinit(c->heap); // calculate size c->size = c->htable->hashTableSize * sizeof (entrytable_hashelement_t); c->maxsize = maxsize; // set timeout scheme c->timeout = timeout; return c; } /*}}} */
static void accept_mutex_on(void) { apr_status_t rv = apr_proc_mutex_lock(accept_mutex); if (rv != APR_SUCCESS) { const char *msg = "couldn't grab the accept mutex"; if (ap_my_generation != ap_scoreboard_image->global->running_generation) { ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg); clean_child_exit(0); } else { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg); exit(APEXIT_CHILDFATAL); } } }
int chxj_cookie_lock(request_rec *r) { mod_chxj_config *dconf; apr_status_t rv; int done_proc = 0; DBG(r, "start chxj_cookie_lock()"); if ((rv = apr_proc_mutex_lock(global_cookie_mutex)) != APR_SUCCESS) { char errstr[255]; ERR(r, "%s:%d apr_proc_mutex_lock failure.(%d:%s)", APLOG_MARK, rv, apr_strerror(rv, errstr, 255)); return 0; } dconf = chxj_get_module_config(r->per_dir_config, &chxj_module); #if defined(USE_MYSQL_COOKIE) if (IS_COOKIE_STORE_MYSQL(dconf->cookie_store_type)) { if (! chxj_cookie_lock_mysql(r, dconf)) { ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_mysql()", APLOG_MARK); return 0; } done_proc = 1; } #endif #if defined(USE_MEMCACHE_COOKIE) if (IS_COOKIE_STORE_MEMCACHE(dconf->cookie_store_type)) { if (! chxj_cookie_lock_memcache(r, dconf)) { ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_memcache()", APLOG_MARK); return 0; } done_proc = 1; } #endif if (!done_proc) { if (! chxj_cookie_lock_dbm(r, dconf)) { ERR(r, "%s:%d end chxj_cookie_lock(): failed: chxj_cookie_lock_dbm()", APLOG_MARK); return 0; } } DBG(r, "end chxj_cookie_lock()"); return 1; }
static void make_child(CuTest *tc, apr_proc_t **proc, apr_pool_t *p) { apr_status_t rv; *proc = apr_pcalloc(p, sizeof(**proc)); /* slight delay to allow things to settle */ apr_sleep (1); rv = apr_proc_fork(*proc, p); if (rv == APR_INCHILD) { int i = 0; /* The parent process has setup all processes to call apr_terminate * at exit. But, that means that all processes must also call * apr_initialize at startup. You cannot have an unequal number * of apr_terminate and apr_initialize calls. If you do, bad things * will happen. In this case, the bad thing is that if the mutex * is a semaphore, it will be destroyed before all of the processes * die. That means that the test will most likely fail. */ apr_initialize(); if (apr_proc_mutex_child_init(&proc_lock, NULL, p)) exit(1); do { if (apr_proc_mutex_lock(proc_lock)) exit(1); i++; *x = increment(*x); if (apr_proc_mutex_unlock(proc_lock)) exit(1); } while (i < MAX_ITER); exit(0); } CuAssert(tc, "fork failed", rv == APR_INPARENT); }
int apsml_cacheFlush (cache * c, request_data *rd, int global) /*{{{ */ { apr_thread_rwlock_wrlock (c->rwlock); if (global) { apr_proc_mutex_lock(rd->ctx->cachelock.plock); unsigned long cachehash = c->hashofname % rd->ctx->cachelock.shmsize; rd->ctx->cachelock.version[cachehash]++; apr_proc_mutex_unlock(rd->ctx->cachelock.plock); } while (c->sentinel->down != c->sentinel) { listremoveitem (c, c->sentinel->down, rd); } if (entrytable_reinit (c->htable) == hash_OUTOFMEM) { apr_thread_rwlock_unlock (c->rwlock); return 0; } c->size = c->htable->hashTableSize * sizeof (entrytable_hashelement_t); apr_thread_rwlock_unlock (c->rwlock); return 1; } /*}}} */
// ML : cache * string -> string_ptr String apsml_cacheGet (Region rAddr, cache *c, String key1, request_data *rd) /*{{{ */ { // ap_log_error(APLOG_MARK, LOG_DEBUG, 0, rd->server, "apsml_cacheGet 1"); // ppCache (c, rd); // keyNhash kn; char *key = &(key1->data); // kn.hash = charhashfunction (kn.key); // ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, // "apsml_cacheGet: key == %s, hash: %i", kn.key, kn.hash); int too_old = 0; apr_thread_rwlock_rdlock (c->rwlock); apr_proc_mutex_lock(rd->ctx->cachelock.plock); unsigned long cachehash = c->hashofname % rd->ctx->cachelock.shmsize; unsigned long cacheversion = rd->ctx->cachelock.version[cachehash]; apr_proc_mutex_unlock(rd->ctx->cachelock.plock); // ap_log_error(APLOG_MARK, LOG_DEBUG, 0, rd->server, // "apsml_cacheGet global version: %d, local version %d", cacheversion, c->version); if (cacheversion != c->version) { apr_thread_rwlock_unlock (c->rwlock); apsml_cacheFlush(c, rd, 0); c->version = cacheversion; return (String) NULL; } entry *entry; // void **entry1 = (void **) &entry; if (entrytable_find (c->htable, key, &entry) == hash_DNE) { entry = NULL; // ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, // "apsml_cacheGet: No such thing"); } if (entry) { // we found an entry // which should be put on top of the list // We require locking on the list // If time is too old then drop the entry time_t ct = time (NULL); apr_thread_mutex_lock (c->mutex); LINKEDLIST_REMOVE (entry); //time_t t = ct < entry->time ? 0 : ct - entry->time; if (entry->timeout) { if (ct > entry->time) { // entry too old too_old = 1; /* ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheGet: Entry too old, ct == %ld, entry->time == %ld", ct, entry->time); */ LINKEDLIST_INSERTOVER (c->sentinel, entry); } else { // keep entry fresh LINKEDLIST_INSERTUNDER (c->sentinel, entry); // ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, // "apsml_cacheGet: Entry fine ct == %i, entry->time == %i", // ct, entry->time); cacheheap_heapchangekey(c->heap, entry->heappos, MAX (ct + entry->timeout, entry->time)); //entry->time = MAX (ct + entry->timeout, entry->time); } } else { LINKEDLIST_INSERTUNDER (c->sentinel, entry); } // ap_log_rerror(APLOG_MARK, LOG_NOTICE, 0, rd->request, "apsml_cacheGetFound: etime: %d, rtime: %d, too_old: %i key: %s, value %d, valuedata: %s", entry->time, time(NULL), too_old, key, entry, entry->data); apr_thread_mutex_unlock (c->mutex); } String s; if (too_old == 0 && entry) { s = convertStringToML (rAddr, entry->data); } else { s = (String) NULL; } apr_thread_rwlock_unlock (c->rwlock); // ap_log_rerror(APLOG_MARK, LOG_NOTICE, 0, rd->request, "apsml_cacheGet: Returning"); return s; } /*}}} */
void child_main(apr_pool_t *pconf) { apr_status_t status; apr_hash_t *ht; ap_listen_rec *lr; HANDLE child_events[2]; HANDLE *child_handles; int listener_started = 0; int threads_created = 0; int watch_thread; int time_remains; int cld; unsigned tid; int rv; int i; apr_pool_create(&pchild, pconf); apr_pool_tag(pchild, "pchild"); ap_run_child_init(pchild, ap_server_conf); ht = apr_hash_make(pchild); /* Initialize the child_events */ max_requests_per_child_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!max_requests_per_child_event) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Child %lu: Failed to create a max_requests event.", my_pid); exit(APEXIT_CHILDINIT); } child_events[0] = exit_event; child_events[1] = max_requests_per_child_event; allowed_globals.jobsemaphore = CreateSemaphore(NULL, 0, 1000000, NULL); apr_thread_mutex_create(&allowed_globals.jobmutex, APR_THREAD_MUTEX_DEFAULT, pchild); /* * Wait until we have permission to start accepting connections. * start_mutex is used to ensure that only one child ever * goes into the listen/accept loop at once. */ status = apr_proc_mutex_lock(start_mutex); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK,APLOG_ERR, status, ap_server_conf, "Child %lu: Failed to acquire the start_mutex. Process will exit.", my_pid); exit(APEXIT_CHILDINIT); } ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Acquired the start mutex.", my_pid); /* * Create the worker thread dispatch IOCompletionPort * on Windows NT/2000 */ if (use_acceptex) { /* Create the worker thread dispatch IOCP */ ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); /* CONCURRENT ACTIVE THREADS */ apr_thread_mutex_create(&qlock, APR_THREAD_MUTEX_DEFAULT, pchild); qwait_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!qwait_event) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Child %lu: Failed to create a qwait event.", my_pid); exit(APEXIT_CHILDINIT); } } /* * Create the pool of worker threads */ ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Starting %d worker threads.", my_pid, ap_threads_per_child); child_handles = (HANDLE) apr_pcalloc(pchild, ap_threads_per_child * sizeof(HANDLE)); apr_thread_mutex_create(&child_lock, APR_THREAD_MUTEX_DEFAULT, pchild); while (1) { for (i = 0; i < ap_threads_per_child; i++) { int *score_idx; int status = ap_scoreboard_image->servers[0][i].status; if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { continue; } ap_update_child_status_from_indexes(0, i, SERVER_STARTING, NULL); child_handles[i] = (HANDLE) _beginthreadex(NULL, (unsigned)ap_thread_stacksize, worker_main, (void *) i, 0, &tid); if (child_handles[i] == 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Child %lu: _beginthreadex failed. Unable to create all worker threads. " "Created %d of the %d threads requested with the ThreadsPerChild configuration directive.", my_pid, threads_created, ap_threads_per_child); ap_signal_parent(SIGNAL_PARENT_SHUTDOWN); goto shutdown; } threads_created++; /* Save the score board index in ht keyed to the thread handle. We need this * when cleaning up threads down below... */ apr_thread_mutex_lock(child_lock); score_idx = apr_pcalloc(pchild, sizeof(int)); *score_idx = i; apr_hash_set(ht, &child_handles[i], sizeof(HANDLE), score_idx); apr_thread_mutex_unlock(child_lock); } /* Start the listener only when workers are available */ if (!listener_started && threads_created) { create_listener_thread(); listener_started = 1; winnt_mpm_state = AP_MPMQ_RUNNING; } if (threads_created == ap_threads_per_child) { break; } /* Check to see if the child has been told to exit */ if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) { break; } /* wait for previous generation to clean up an entry in the scoreboard */ apr_sleep(1 * APR_USEC_PER_SEC); } /* Wait for one of three events: * exit_event: * The exit_event is signaled by the parent process to notify * the child that it is time to exit. * * max_requests_per_child_event: * This event is signaled by the worker threads to indicate that * the process has handled MaxRequestsPerChild connections. * * TIMEOUT: * To do periodic maintenance on the server (check for thread exits, * number of completion contexts, etc.) * * XXX: thread exits *aren't* being checked. * * XXX: other_child - we need the process handles to the other children * in order to map them to apr_proc_other_child_read (which is not * named well, it's more like a_p_o_c_died.) * * XXX: however - if we get a_p_o_c handle inheritance working, and * the parent process creates other children and passes the pipes * to our worker processes, then we have no business doing such * things in the child_main loop, but should happen in master_main. */ while (1) { #if !APR_HAS_OTHER_CHILD rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, INFINITE); cld = rv - WAIT_OBJECT_0; #else rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000); cld = rv - WAIT_OBJECT_0; if (rv == WAIT_TIMEOUT) { apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); } else #endif if (rv == WAIT_FAILED) { /* Something serious is wrong */ ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf, "Child %lu: WAIT_FAILED -- shutting down server", my_pid); break; } else if (cld == 0) { /* Exit event was signaled */ ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Exit event signaled. Child process is ending.", my_pid); break; } else { /* MaxRequestsPerChild event set by the worker threads. * Signal the parent to restart */ ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Process exiting because it reached " "MaxRequestsPerChild. Signaling the parent to " "restart a new child process.", my_pid); ap_signal_parent(SIGNAL_PARENT_RESTART); break; } } /* * Time to shutdown the child process */ shutdown: winnt_mpm_state = AP_MPMQ_STOPPING; /* Setting is_graceful will cause threads handling keep-alive connections * to close the connection after handling the current request. */ is_graceful = 1; /* Close the listening sockets. Note, we must close the listeners * before closing any accept sockets pending in AcceptEx to prevent * memory leaks in the kernel. */ for (lr = ap_listeners; lr ; lr = lr->next) { apr_socket_close(lr->sd); } /* Shutdown listener threads and pending AcceptEx socksts * but allow the worker threads to continue consuming from * the queue of accepted connections. */ shutdown_in_progress = 1; Sleep(1000); /* Tell the worker threads to exit */ workers_may_exit = 1; /* Release the start_mutex to let the new process (in the restart * scenario) a chance to begin accepting and servicing requests */ rv = apr_proc_mutex_unlock(start_mutex); if (rv == APR_SUCCESS) { ap_log_error(APLOG_MARK,APLOG_NOTICE, rv, ap_server_conf, "Child %lu: Released the start mutex", my_pid); } else { ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf, "Child %lu: Failure releasing the start mutex", my_pid); } /* Shutdown the worker threads */ if (!use_acceptex) { for (i = 0; i < threads_created; i++) { add_job(INVALID_SOCKET); } } else { /* Windows NT/2000 */ /* Post worker threads blocked on the ThreadDispatch IOCompletion port */ while (g_blocked_threads > 0) { ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, ap_server_conf, "Child %lu: %d threads blocked on the completion port", my_pid, g_blocked_threads); for (i=g_blocked_threads; i > 0; i--) { PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL); } Sleep(1000); } /* Empty the accept queue of completion contexts */ apr_thread_mutex_lock(qlock); while (qhead) { CloseHandle(qhead->Overlapped.hEvent); closesocket(qhead->accept_socket); qhead = qhead->next; } apr_thread_mutex_unlock(qlock); } /* Give busy threads a chance to service their connections, * (no more than the global server timeout period which * we track in msec remaining). */ watch_thread = 0; time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000)); while (threads_created) { int nFailsafe = MAXIMUM_WAIT_OBJECTS; DWORD dwRet; /* Every time we roll over to wait on the first group * of MAXIMUM_WAIT_OBJECTS threads, take a breather, * and infrequently update the error log. */ if (watch_thread >= threads_created) { if ((time_remains -= 100) < 0) break; /* Every 30 seconds give an update */ if ((time_remains % 30000) == 0) { ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Waiting %d more seconds " "for %d worker threads to finish.", my_pid, time_remains / 1000, threads_created); } /* We'll poll from the top, 10 times per second */ Sleep(100); watch_thread = 0; } /* Fairness, on each iteration we will pick up with the thread * after the one we just removed, even if it's a single thread. * We don't block here. */ dwRet = WaitForMultipleObjects(min(threads_created - watch_thread, MAXIMUM_WAIT_OBJECTS), child_handles + watch_thread, 0, 0); if (dwRet == WAIT_FAILED) { break; } if (dwRet == WAIT_TIMEOUT) { /* none ready */ watch_thread += MAXIMUM_WAIT_OBJECTS; continue; } else if (dwRet >= WAIT_ABANDONED_0) { /* We just got the ownership of the object, which * should happen at most MAXIMUM_WAIT_OBJECTS times. * It does NOT mean that the object is signaled. */ if ((nFailsafe--) < 1) break; } else { watch_thread += (dwRet - WAIT_OBJECT_0); if (watch_thread >= threads_created) break; cleanup_thread(child_handles, &threads_created, watch_thread); } } /* Kill remaining threads off the hard way */ if (threads_created) { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: Terminating %d threads that failed to exit.", my_pid, threads_created); } for (i = 0; i < threads_created; i++) { int *score_idx; TerminateThread(child_handles[i], 1); CloseHandle(child_handles[i]); /* Reset the scoreboard entry for the thread we just whacked */ score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); if (score_idx) { ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); } } ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %lu: All worker threads have exited.", my_pid); CloseHandle(allowed_globals.jobsemaphore); apr_thread_mutex_destroy(allowed_globals.jobmutex); apr_thread_mutex_destroy(child_lock); if (use_acceptex) { apr_thread_mutex_destroy(qlock); CloseHandle(qwait_event); } apr_pool_destroy(pchild); CloseHandle(exit_event); }
void cse_proc_lock() { apr_proc_mutex_lock(g_proc_lock); }