Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
} 
Ejemplo n.º 3
0
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;
}				/*}}} */
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
// 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;
}				/*}}} */
Ejemplo n.º 6
0
// 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;
}				/*}}} */
Ejemplo n.º 7
0
SWITCH_DECLARE(switch_status_t) switch_thread_rwlock_unlock(switch_thread_rwlock_t *rwlock)
{
	return apr_thread_rwlock_unlock(rwlock);
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
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
}
Ejemplo n.º 10
0
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
}
Ejemplo n.º 11
0
// 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;
}				/*}}} */
Ejemplo n.º 12
0
// 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;
}				/*}}} */