void * APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data) { int i; for (i = 0; i < MAX_COUNTER; i++) { apr_thread_rwlock_wrlock(thread_rwlock); mutex_counter++; apr_thread_rwlock_unlock(thread_rwlock); } return NULL; }
static void *APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data) { int exitLoop = 1; while (1) { apr_thread_rwlock_rdlock(rwlock); if (i == MAX_ITER) exitLoop = 0; apr_thread_rwlock_unlock(rwlock); if (!exitLoop) break; apr_thread_rwlock_wrlock(rwlock); if (i != MAX_ITER) { i++; x++; } apr_thread_rwlock_unlock(rwlock); } return NULL; }
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; } /*}}} */
int test_thread_rwlock(int num_threads) { apr_thread_t *t[MAX_THREADS]; apr_status_t s[MAX_THREADS]; apr_time_t time_start, time_stop; int i; mutex_counter = 0; printf("apr_thread_rwlock_t Tests\n"); printf("%-60s", " Initializing the apr_thread_rwlock_t"); s[0] = apr_thread_rwlock_create(&thread_rwlock, pool); if (s[0] != APR_SUCCESS) { printf("Failed!\n"); return s[0]; } printf("OK\n"); apr_thread_rwlock_wrlock(thread_rwlock); /* set_concurrency(4)? -aaron */ printf(" Starting %d threads ", num_threads); for (i = 0; i < num_threads; ++i) { s[i] = apr_thread_create(&t[i], NULL, thread_rwlock_func, NULL, pool); if (s[i] != APR_SUCCESS) { printf("Failed!\n"); return s[i]; } } printf("OK\n"); time_start = apr_time_now(); apr_thread_rwlock_unlock(thread_rwlock); /* printf("%-60s", " Waiting for threads to exit"); */ for (i = 0; i < num_threads; ++i) { apr_thread_join(&s[i], t[i]); } /* printf("OK\n"); */ time_stop = apr_time_now(); printf("microseconds: %" APR_INT64_T_FMT " usec\n", (time_stop - time_start)); if (mutex_counter != MAX_COUNTER * num_threads) printf("error: counter = %ld\n", mutex_counter); return APR_SUCCESS; }
// ML: string -> cache ptr_option const cache * apsml_cacheFind (char *cacheName, request_data *rd) /*{{{ */ { // ppGlobalCache(rd); apr_thread_rwlock_rdlock (rd->cachetable->rwlock); const cache *c; // void **c1 = (void **) &c; // ap_log_error(APLOG_MARK, LOG_DEBUG, 0, rd->server, "apsml_cacheFind: cacheName == %s", cacheName); // keyNhash kn; // kn.key = cacheName; // kn.hash = charhashfunction (cacheName); if (cachetable_find (rd->cachetable->ht, cacheName, &c) == hash_DNE) { // ap_log_error(APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheFind: cacheName == %s not in main cache", cacheName); c = NULL; } // ap_log_error(APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheFind: 2"); apr_thread_rwlock_unlock (rd->cachetable->rwlock); return c; } /*}}} */
// ML: string * int * int -> cache ptr_option const cache * apsml_cacheCreate (char *key, int maxsize, int timeout, request_data * rd) /*{{{ */ { // keyNhash kn1; // kn1.key = &(cacheName1->data); // kn1.hash = charhashfunction (kn1.key); // char *key = &(cacheName1->data); apr_thread_rwlock_wrlock (rd->cachetable->rwlock); const cache *c; // void **c1 = (void **) &c; // ap_log_error (APLOG_MARK, LOG_DEBUG, 0, rd->server, // "apsml_cacheCreate: cacheName == %s, maxsize == %i, timeout == %i", // &(cacheName1->data), maxsize, timeout); if (cachetable_find (rd->cachetable->ht, key, &c) == hash_DNE) { int size = strlen(key); char *kn = malloc (size+1); // ap_log_error (APLOG_MARK, LOG_DEBUG, 0, rd->server, // "apsml_cacheCreate: malloc 0x%x, length:%d", (unsigned long) kn, size); if (kn == NULL) return NULL; // kn->key = (char *) (kn + 1); // kn->hash = kn1.hash; strncpy (kn, key, size); kn[size] = 0; c = cacheCreate (maxsize, timeout, charhashfunction(kn), rd); cachetable_insert (rd->cachetable->ht, kn, c); } else { ap_log_error (APLOG_MARK, LOG_DEBUG, 0, rd->server, "apsml_cacheCreate: cacheName == %s already exists", key); } // ppGlobalCache(rd); apr_thread_rwlock_unlock (rd->cachetable->rwlock); return c; } /*}}} */
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_unlock(switch_thread_rwlock_t *rwlock) { return apr_thread_rwlock_unlock(rwlock); }
int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p) { apr_pool_t *gPool = (apr_pool_t *)getGlobalPool(); apr_hash_t *statCache = NULL; apr_thread_rwlock_t *rwlock = NULL; NXPathCtx_t pathctx = 0; char *ptr = NULL, *tr; int len = 0, x; char *ppath; char *pinfo; if (ctx == 1) { /* If there isn't a global pool then just stat the file and return */ if (!gPool) { char poolname[50]; if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) { return getstat(ctx, path, buf, requestmap); } setGlobalPool(gPool); apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool")); statCache = apr_hash_make(gPool); apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool); apr_thread_rwlock_create(&rwlock, gPool); apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool); } else { apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool); apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool); } if (!gPool || !statCache || !rwlock) { return getstat(ctx, path, buf, requestmap); } for (x = 0,tr = path;*tr != '\0';tr++,x++) { if (*tr == '\\' || *tr == '/') { ptr = tr; len = x; } if (*tr == ':') { ptr = "\\"; len = x; } } if (ptr) { ppath = apr_pstrndup (p, path, len); strlwr(ppath); if (ptr[1] != '\0') { ptr++; } /* If the path ended in a trailing slash then our result path will be a single slash. To avoid stat'ing the root with a slash, we need to make sure we stat the current directory with a dot */ if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) { pinfo = apr_pstrdup (p, "."); } else { pinfo = apr_pstrdup (p, ptr); } } /* If we have a statCache then try to pull the information from the cache. Otherwise just stat the file and return.*/ if (statCache) { apr_thread_rwlock_rdlock(rwlock); pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING); apr_thread_rwlock_unlock(rwlock); if (pathctx) { return getstat(pathctx, pinfo, buf, requestmap); } else { int err; err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx); if (!err) { apr_thread_rwlock_wrlock(rwlock); apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx); apr_thread_rwlock_unlock(rwlock); return getstat(pathctx, pinfo, buf, requestmap); } } } } return getstat(ctx, path, buf, requestmap); }
static int ip_in_url_test (request_rec *r, apr_sockaddr_t *ip_to_be_test, REMOTE_INFO *p_remote_info, apr_time_t expire_time) { apr_status_t rv; char errmsg_buf[120]; #ifdef DEBUG ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "cur_time: %lld | last_contact_time:" " %lld | last_update_time: %s | expire_time: %lld", apr_time_now (), p_remote_info->last_contact_time, p_remote_info->last_update_time, expire_time); #endif #if APR_HAS_THREADS if (apr_time_now () - p_remote_info->last_contact_time >= expire_time) { /* the ip-list from url is expired */ rv = apr_thread_rwlock_wrlock (p_remote_info->rwlock); if (rv != APR_SUCCESS) { p_remote_info->last_contact_time = apr_time_now (); apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to obtain wrlock: %s", errmsg_buf); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update expired data from remote url," " the ipsubnet-list remains unchanged," " after remote_expire_time next update" " will be invoked by another request"); } else { /* rejudge whether it is necessary to update */ if (apr_time_now () - p_remote_info->last_contact_time >= expire_time) { p_remote_info->last_contact_time = apr_time_now (); if (update_expired_data_from_remote_info (r, p_remote_info) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update expired data from remote url," " the ipsubnet-list remains unchanged," " after remote_expire_time next update will" " be invoked by another request"); } } rv = apr_thread_rwlock_unlock (p_remote_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof(errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to release wrlock: %s", errmsg_buf); } } } rv = apr_thread_rwlock_rdlock (p_remote_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to obtain rdlock: %s", errmsg_buf); } /* check if the request's ip is match one of the ipsubnets * getting from url */ int ret = ip_in_ipsubnet_list_test (ip_to_be_test, p_remote_info->p_ipsubnet_list); rv = apr_thread_rwlock_unlock (p_remote_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to release rdlock: %s", errmsg_buf); } return ret; #else if (apr_time_now () - p_remote_info->last_contact_time >= expire_time) { /* the ip-list from url is expired */ p_remote_info->last_contact_time = apr_time_now (); if (update_expired_data_from_remote_info (r, p_remote_info) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update expired data from remote url," " the ipsubnet-list remains unchanged," " after remote_expire_time next update will" " be invoked by another request"); } } /* check if the request's ip is match one * of the ipsubnets getting from url */ return ip_in_ipsubnet_list_test (ip_to_be_test, p_remote_info->p_ipsubnet_list); #endif }
static int ip_in_local_file_test (request_rec *r, apr_sockaddr_t *ip_to_be_test, LOCAL_FILE_INFO *p_local_file_info) { apr_status_t rv; char errmsg_buf[120]; #if APR_HAS_THREADS rv = apr_thread_rwlock_wrlock (p_local_file_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to obtain wrlock: %s", errmsg_buf); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update from local file, " "the ipsubnet-list remains unchanged," " next update will be invoked by another request"); } else { if (update_expired_data_from_local_file_info (r, p_local_file_info) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update from local file, " "the ipsubnet-list remains unchanged," " next update will be invoked by another request"); } rv = apr_thread_rwlock_unlock (p_local_file_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to release wrlock: %s", errmsg_buf); } } rv = apr_thread_rwlock_rdlock (p_local_file_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to obtain rdlock: %s", errmsg_buf); } /* check if the request's ip is match one of the ipsubnets * getting from local file */ int ret = ip_in_ipsubnet_list_test (ip_to_be_test, p_local_file_info->p_ipsubnet_list); rv = apr_thread_rwlock_unlock (p_local_file_info->rwlock); if (rv != APR_SUCCESS) { apr_strerror (rv, errmsg_buf, sizeof (errmsg_buf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to release rdlock: %s", errmsg_buf); } return ret; #else if (update_expired_data_from_local_file_info (r, p_local_file_info) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "fail to update from local file, " "the ipsubnet-list remains unchanged," " next update will be invoked by another request"); } /* check if the request's ip is match one of the * ipsubnets getting from url */ return ip_in_ipsubnet_list_test (ip_to_be_test, p_local_file_info->p_ipsubnet_list); #endif }
// ML: cache * String * String -> (int * string_ptr) int apsml_cacheSet (int resultPair, Region sAddr, cache * c, int keyValPair, request_data * rd) /*{{{ */ { // allocate new entry and key,value placeholders // ppCache(c, rd); String key1 = (String) elemRecordML (keyValPair, 0); String value1 = (String) elemRecordML (keyValPair, 1); time_t timeout = (time_t) elemRecordML (keyValPair, 2); char *value = &(value1->data); int valuesize = sizeStringDefine(value1); char *key = &(key1->data); int keysize = sizeStringDefine(key1); int size = sizeof (entry) + keysize + 1 + valuesize + 1; entry *newentry = (entry *) malloc (size); // ap_log_error (APLOG_MARK, LOG_DEBUG, 0, rd->server, // "apsml_cacheCreate: malloc 0x%x, length: %d, sizeof(entry): %d, keysize: %d, valuesize: %d, key: %s, val: %s", (unsigned long) newentry, size, sizeof(entry), keysize, valuesize, key, value); if (newentry == NULL) return 0; char *newkey = (char *) (newentry + 1); char *newvalue = newkey + (keysize + 1); // prepare entry by copy data to my space and set pointers strncpy (newkey, key, keysize); newkey[keysize] = 0; strncpy (newvalue, value, valuesize); newvalue[valuesize] = 0; newentry->key = newkey; // newentry->key.hash = charhashfunction (newkey); newentry->data = newvalue; newentry->size = keysize + valuesize + sizeof (entry) + 2; time_t ct = time (NULL); if (timeout && c->timeout) { newentry->timeout = MIN (timeout, c->timeout); } else if (timeout) { newentry->timeout = timeout; } else { newentry->timeout = c->timeout; } newentry->time = ct + newentry->timeout; // We are going in !!! (as we get a writes lock we have // complete control [no more locks]) apr_thread_rwlock_wrlock (c->rwlock); int tmpsize = c->htable->hashTableSize; entry *oldentry = NULL; // void **oldentry1 = (void **) &oldentry; // ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, // "apsml_cacheSet: key %s, hash: %i", key, newentry->key.hash); if (entrytable_find (c->htable, newentry->key, &oldentry) == hash_DNE) { // No old entry with that key if ((newentry->timeout == -1 && cacheheap_heapinsert(c->heap, newentry, (time_t) 0) == heap_OUTOFMEM) || (newentry->timeout && newentry->timeout != (time_t) -1 && cacheheap_heapinsert(c->heap, newentry, newentry->time) == heap_OUTOFMEM)) { ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheSet: pid %d, received heap_OUTOFMEM", rd->ctx->pid); free(newentry); newentry = 0; } if (newentry && entrytable_insert (c->htable, newentry->key, newentry) == hash_OUTOFMEM) { ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheSet: pid %d, received hash_OUTOFMEM", rd->ctx->pid); free (newentry); newentry = 0; } // ppCache(c, rd); oldentry = 0; } else { // Old exists if ((newentry->timeout == (time_t) -1 && cacheheap_heapinsert(c->heap, newentry, (time_t) 0) == heap_OUTOFMEM) || (newentry->timeout && newentry->timeout != (time_t) -1 && cacheheap_heapinsert(c->heap, newentry, newentry->time) == heap_OUTOFMEM)) { ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheSet: pid %d, received heap_OUTOFMEM", rd->ctx->pid); free(newentry); newentry = 0; } if (newentry && entrytable_update (c->htable, newentry->key, newentry) == hash_OUTOFMEM) { ap_log_error (APLOG_MARK, LOG_NOTICE, 0, rd->server, "apsml_cacheSet: pid %d, received hash_OUTOFMEM", rd->ctx->pid); free (newentry); newentry = 0; } } if (newentry) { c->size += newentry->size; c->size += (tmpsize - c->htable->hashTableSize) * sizeof (entrytable_hashelement_t); } // ppCache(c, rd); int too_old = 0; if (oldentry) { // Old entry needs removel // time_t t = (ct - oldentry->time) < 0 ? 0 : ct - oldentry->time; if (oldentry->timeout && ct > oldentry->time) { too_old = 1; second (resultPair) = 0; } else { second (resultPair) = (int) convertStringToML (sAddr, oldentry->data); } listremoveitem (c, oldentry, rd); } if (too_old) oldentry = 0; if (newentry) LINKEDLIST_INSERTUNDER (c->sentinel, newentry); // I think we are done now // ppCache(c, rd); entry *curentry; // ap_log_error(APLOG_MARK, LOG_NOTICE, 0, rd->server, // "apsml_cacheSet: size %d, maxsize = %d, ct: %d", c->size, c->maxsize, ct); while (cacheheap_heapminimal(c->heap, &curentry) != heap_UNDERFLOW) { if (curentry->time < ct) { cacheremoveitem(c, curentry, rd); } else break; } // ppCache(c, rd); if (c->maxsize != -1) { while (c->size > c->maxsize) { curentry = c->sentinel->up; if (curentry == c->sentinel) break; cacheremoveitem (c, curentry, rd); } } apr_thread_rwlock_unlock (c->rwlock); // ppCache(c, rd); if (oldentry && newentry) { first (resultPair) = 1; return resultPair; } second (resultPair) = 0; if (newentry) { first (resultPair) = 2; return resultPair; } first (resultPair) = 0; return resultPair; } /*}}} */
// 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; } /*}}} */