apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Greg Ames <grega...@remulak.net>
Subject Re: [PATCH] mod_mem_cache using apr_atomic_dec()
Date Fri, 15 Mar 2002 18:35:13 GMT
Bill Stoddard wrote:

(moved from dev@httpd to dev@apr)

> I hesitate to commit the because I am not sure if apr_atomic_dec will be portable and
> usable on enough OS/hardware combinations. 

as we discussed offline, you're right.  The return value for apr_atomic_dec
isn't defined, but as your code demonstrates, it's very useful for making the
cache more scaleable. 

> If any apr_atomic_* implementations have hardware dependencies (ie, the implementation
> explicitly exploits hardware features via assembly language calls for instance),
> supporting the atomic operations in APR could become a real nightmare.  APR compiled
on
> one machine may not run on another machine even if the OS level of the two machines is
> identical. Most gnarley...

yeah, that's bad for binaries.  Seems like we would want to build them on the
most ancient version of the CPU architecture supported, or have #defines which
"dumb down" your build machine.

> -    if (sconf->lock) {
> -        apr_thread_mutex_lock(sconf->lock);
> -    }
> -    obj->refcount--;
> -    /* If the object is marked for cleanup and the refcount
> -     * has dropped to zero, cleanup the object
> -     */
> -    if ((obj->cleanup) && (!obj->refcount)) {
> -        cleanup_cache_object(obj);
> -    }
> -    if (sconf->lock) {
> -        apr_thread_mutex_unlock(sconf->lock);
> +    if (!apr_atomic_dec(&obj->refcount)) {
> +        if (obj->cleanup) {
> +            cleanup_cache_object(obj);
> +        }

nice...a concise lock free example of the "last guy out the door turns out the
lights" pattern.

However, this code won't work on Linux at the moment.  apr_atomic_dec invokes
the atomic_dec function which doesn't define a return value.  Linux does have an
atomic_dec_and_test which we could use.  But it returns true when the counter
becomes zero; Win32 returns the new value of the counter, so it is false when
the counter becomes zero.  It looks to me like Solaris behaves like Win32; dunno
about Netware.

FreeBSD doesn't seem to have userland atomic functions that return anything.  It
shouldn't be too hard to write an i386 asm function, but FreeBSD runs on other
chip families where I wouldn't feel comfortable with asm.  Perhaps we could
emulate a atomic_dec that tells you when the value reaches zero for non-i386
FreeBSD using a lock, like Ian's existing default functions.

Would it make sense to create another new API, apr_atomic_dec_and_test (or
whatever) which is defined to return something consistant?  I think Bill's code
demonstrates how useful it is to have such a function for reference counting. 
The Linux kernel uses both atomic_dec and atomic_dec_and_test.

We already have a return value from apr_atomic_cas;  I don't know that we need a
return value for the other atomics.

Greg

----------------------------------------------------------------------------

a quick hack to allow apr_atomic_dec to work on Linux for refcounts:

Index: srclib/apr/include/apr_atomic.h
===================================================================
RCS file: /cvs/apache/apr/include/apr_atomic.h,v
retrieving revision 1.15
diff -u -d -b -r1.15 apr_atomic.h
--- apr_atomic.h        2002/03/13 20:39:13     1.15
+++ apr_atomic.h        2002/03/15 17:36:13
@@ -117,6 +117,7 @@
 /**
  * decrement the atomic variable by 1
  * @param mem pointer to the atomic value
+ * @return false (0) if the value became 0; otherwise true
  */
 void apr_atomic_dec(volatile apr_atomic_t *mem);
 
@@ -158,7 +159,7 @@
 #define apr_atomic_t atomic_t
 
 #define apr_atomic_add(mem, val)     atomic_add(val,mem)
-#define apr_atomic_dec(mem)          atomic_dec(mem)
+#define apr_atomic_dec(mem)          !atomic_dec_and_test(mem)
 #define apr_atomic_inc(mem)          atomic_inc(mem)
 #define apr_atomic_set(mem, val)     atomic_set(mem, val)
 #define apr_atomic_read(mem)         atomic_read(mem)

Mime
View raw message