You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Aaron Bannert <aa...@clove.org> on 2001/08/29 18:53:42 UTC

[API PROPOSAL] apr_lock.h breakout of functionality, add cond vars

The following is a proposed API change to the apr_lock.h interface. It basicly
breaks out the lock types into the 4 main types, then adds condition variables.
I'd like to stimulate some discussion on this topic, and get some +1's to
proceed with the proposal (or parts of it at least):

- thread mutexes
- proc mutexes
- thread read-write locks
- proc read-write locks
And the new one:
- thread condition variables

The main motivation for this is to get condition variables into APR.
Condition variables must be paired up with a specific type of mutex, and
so would not work with the general apr_lock (at least in no way would it
be intuitive).

Please review this and give me some feedback. I'd like a few +1's before
I start coding up the Unix implementations (I will of course leave the
old functionality in there until we're well sure the new one works).

Here are a few questions I have:

1) Do we also need these? I realize we're using APR_LOCKALL in some places,
but is it really faster to have N*M threads waiting on one lock, or would
it be the same to have N threads in one lock and M threads in another lock?
The functions I'm talking about would be:

   apr_global_mutex_t
   apr_global_rwlock_t


2) Would it be useful to have an apr_proc_mutex_trylock()? Is that even
possible with fcntl, flock, etc?


3) Will we also be needing more widely scoped condition variables?

   apr_proc_cond_t
   apr_global_cond_t



-aaron


Index: apr_lock.h
===================================================================
RCS file: /home/cvspublic/apr/include/apr_lock.h,v
retrieving revision 1.30
diff -u -r1.30 apr_lock.h
--- apr_lock.h	2001/08/17 03:54:04	1.30
+++ apr_lock.h	2001/08/29 16:36:25
@@ -82,6 +82,16 @@
 
 typedef struct apr_lock_t    apr_lock_t;
 
+typedef struct apr_thread_mutex_t apr_thread_mutex_t;
+
+typedef struct apr_proc_mutex_t apr_proc_mutex_t;
+
+typedef struct apr_thread_rwlock_t apr_thread_rwlock_t;
+
+typedef struct apr_proc_rwlock_t apr_proc_rwlock_t;
+
+typedef struct apr_thread_cond_t apr_thread_cond_t;
+
 /*   Function definitions */
 
 /**
@@ -231,6 +241,180 @@
                                              apr_pool_t *pool);
 #endif /* APR_HAS_LOCK_CREATE_NP */
 /** @} */
+
+
+
+/**
+ * Create and initialize a mutex that can be used to synchronize threads.
+ * @param mutex the memory address where the newly created mutex will be
+ *        stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
+                                                  apr_pool_t *pool);
+/**
+ * Acquire the lock for the given mutex. If the mutex is already locked,
+ * the current thread will be put to sleep until the lock becomes available.
+ * @param mutex the mutex on which to acquire the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex);
+
+/**
+ * Attempt to acquire the lock for the given mutex. If the mutex has already
+ * been acquired, the call returns immediately with APR_EBUSY. Note: it
+ * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine
+ * if the return value was APR_EBUSY, for portability reasons.
+ * @param mutex the mutex on which to attempt the lock acquiring.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex);
+
+/**
+ * Release the lock for the given mutex.
+ * @param mutex the mutex from which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex);
+
+
+/**
+ * Create and initialize a mutex that can be used to synchronize processes.
+ * @param mutex the memory address where the newly created mutex will be
+ *        stored.
+ * @param fname A file name to use if the lock mechanism requires one.  This
+ *        argument should always be provided.  The lock code itself will
+ *        determine if it should be used.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
+                                                const char *fname,
+                                                apr_pool_t *pool);
+/**
+ * Acquire the lock for the given mutex. If the mutex is already locked,
+ * the current thread will be put to sleep until the lock becomes available.
+ * @param mutex the mutex on which to acquire the lock.
+ */
+
+APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_thread_mutex_t *mutex);
+/**
+ * Release the lock for the given mutex.
+ * @param mutex the mutex from which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_thread_mutex_t *mutex);
+
+
+
+/**
+ * Create and initialize a read-write lock that can be used to synchronize
+ * threads.
+ * @param rwlock the memory address where the newly created readwrite lock
+ *        will be stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock,
+                                                   apr_pool_t *pool);
+/**
+ * Acquire a shared-read lock on the given read-write lock. This will allow
+ * multiple threads to enter the same critical section while they have acquired
+ * the read lock.
+ * @param rwlock the read-write lock on which to acquire the shared read.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Acquire an exclusive-write lock on the given read-write lock. This will
+ * allow only one single thread to enter the critical sections. If there
+ * are any threads currently holding thee read-lock, this thread is put to
+ * sleep until it can have exclusive access to the lock.
+ * @param rwlock the read-write lock on which to acquire the exclusive write.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Release either the read or write lock currently held by the calling thread
+ * associated with the given read-write lock.
+ * @param rwlock the read-write lock rom which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock);
+
+/**
+ * Create and initialize a read-write lock that can be used to synchronize
+ * processes.
+ * @param rwlock the memory address where the newly created readwrite lock
+ *        will be stored.
+ * @param fname A file name to use if the lock mechanism requires one.  This
+ *        argument should always be provided.  The lock code itself will
+ *        determine if it should be used.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_create(apr_proc_rwlock_t **rwlock,
+                                                 const char *fname,
+                                                 apr_pool_t *pool);
+
+/**
+ * Acquire a shared-read lock on the given read-write lock. This will allow
+ * multiple threads to enter the same critical section while they have acquired
+ * the read lock.
+ * @param rwlock the read-write lock on which to acquire the shared read.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_rdlock(apr_proc_rwlock_t *rwlock);
+
+/**
+ * Acquire an exclusive-write lock on the given read-write lock. This will
+ * allow only one single thread to enter the critical sections. If there
+ * are any threads currently holding thee read-lock, this thread is put to
+ * sleep until it can have exclusive access to the lock.
+ * @param rwlock the read-write lock on which to acquire the exclusive write.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_wrlock(apr_proc_rwlock_t *rwlock);
+
+/**
+ * Release either the read or write lock currently held by the calling thread
+ * associated with the given read-write lock.
+ * @param rwlock the read-write lock rom which to release the lock.
+ */
+APR_DECLARE(apr_status_t) apr_proc_rwlock_unlock(apr_proc_rwlock_t *rwlock);
+
+
+/**
+ * Create and initialize a condition variable that can be used to signal
+ * and schedule threads in a single process.
+ * @param cond the memory address where the newly created condition variable
+ *        will be stored.
+ * @param pool the pool from which to allocate the mutex.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond,
+                                                 apr_pool_t *pool);
+/**
+ * Put the active calling thread to sleep until signaled to wake up. Each
+ * condition variable must be associated with a mutex, and that mutex must
+ * be locked before  calling this function, or the behavior will be
+ * undefined. As the calling thread is put to sleep, the given mutex
+ * will be simultaneously released; and as this thread wakes up the lock
+ * is again simultaneously acquired.
+ * @param cond the condition variable on which to block.
+ * @param mutex the mutex that must be locked upon entering this function,
+ *        is released while the thread is asleep, and is again acquired before
+ *        returning from this function.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond,
+                                               apr_thread_mutex_t *mutex);
+
+/**
+ * Signals a singla thread, if one exists, that is blocking on the given
+ * condition variable. That thread is then scheduled to wake up and acquire
+ * the associated mutex. Although it is not required, if predictible schedule
+ * is desired, that mutex must be locked while calling this function.
+ * @param cond the condition variable on which to produce the signal.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond);
+/**
+ * Signals all threads blocking on the given condition variable.
+ * Each thread that was signaled is then schedule to wake up and acquire
+ * the associated mutex. This will happen in a serialized manner.
+ * @param cond the condition variable on which to produce the broadcast.
+ */
+APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond);
+
+
 #ifdef __cplusplus
 }
 #endif


Re: [API PROPOSAL] apr_lock.h breakout of functionality, add cond vars

Posted by Justin Erenkrantz <je...@ebuilt.com>.
On Wed, Aug 29, 2001 at 11:28:04AM -0700, Ryan Bloom wrote:
> We should only keep both API's for the short term.  Any API that we release
> in a beta we need to support forever, so I am VERY much against releasing
> a beta with the old locking API, because it is a very poor API.

I have fundamental questions about the verbosity of the new lock API.
I think Aaron's proposal goes a more bit overboard than we really need.
I'm sure that Aaron and I are just replaying the conversations Manoj 
and yourself had.  

I'll shut up on this now and await the implementation.  -- justin


Re: [API PROPOSAL] apr_lock.h breakout of functionality, add cond vars

Posted by Ryan Bloom <rb...@covalent.net>.
On Wednesday 29 August 2001 11:25, Justin Erenkrantz wrote:
> On Wed, Aug 29, 2001 at 10:50:12AM -0700, Ryan Bloom wrote:
> > My only other comment, is that while doing development, it would be
> > REALLY cool if we could have access to both API's, which should end up
> > pointing to the same implementation.
>
> +1 *if* we keep both APIs.  Otherwise, +0 - I'm not against it, but I'm
> not for it either.  -- justin

We should only keep both API's for the short term.  Any API that we release
in a beta we need to support forever, so I am VERY much against releasing
a beta with the old locking API, because it is a very poor API.

Ryan

______________________________________________________________
Ryan Bloom				rbb@apache.org
Covalent Technologies			rbb@covalent.net
--------------------------------------------------------------

Re: [API PROPOSAL] apr_lock.h breakout of functionality, add cond vars

Posted by Justin Erenkrantz <je...@ebuilt.com>.
On Wed, Aug 29, 2001 at 10:50:12AM -0700, Ryan Bloom wrote:
> My only other comment, is that while doing development, it would be REALLY
> cool if we could have access to both API's, which should end up pointing to 
> the same implementation.

+1 *if* we keep both APIs.  Otherwise, +0 - I'm not against it, but I'm
not for it either.  -- justin


Re: [API PROPOSAL] apr_lock.h breakout of functionality, add cond vars

Posted by Ryan Bloom <rb...@covalent.net>.
On Wednesday 29 August 2001 09:53, Aaron Bannert wrote:

++1.  As I have said all along, the common function for all locks, was
a point of contention between Manoj and I.  I won, but I was wrong.  It's
time to fix that mistake.

> Here are a few questions I have:
>
> 1) Do we also need these? I realize we're using APR_LOCKALL in some places,
> but is it really faster to have N*M threads waiting on one lock, or would
> it be the same to have N threads in one lock and M threads in another lock?
> The functions I'm talking about would be:
>
>    apr_global_mutex_t
>    apr_global_rwlock_t

I don't believe we need these.  I think the LOCK_ALL's that we have now can
all move to proc_locks, in fact.

> 2) Would it be useful to have an apr_proc_mutex_trylock()? Is that even
> possible with fcntl, flock, etc?

If it's possible, it would probably be useful.

> 3) Will we also be needing more widely scoped condition variables?
>
>    apr_proc_cond_t
>    apr_global_cond_t

My gut, is that we won't need them initially, but we should leave that possibility open.

My only other comment, is that while doing development, it would be REALLY
cool if we could have access to both API's, which should end up pointing to 
the same implementation.

Ryan
______________________________________________________________
Ryan Bloom				rbb@apache.org
Covalent Technologies			rbb@covalent.net
--------------------------------------------------------------