On Thu, 9 Feb 2012 05:43:10 -0500
Matthew Mondor <mm_li...@pulsar-zone.net> wrote:

> > I here attach the diff for review, testing and comments.
> 
> Revised diff attached, the error reporting was done with arguments
> reversed, and there was a redundant pthread.h include.

Well, here again another revision, as I wasn't satisfied with the
verbosity of locking errors.
-- 
Matt
diff --git a/src/c/threads/mutex.d b/src/c/threads/mutex.d
index c1c9f1e..f04ffcc 100644
--- a/src/c/threads/mutex.d
+++ b/src/c/threads/mutex.d
@@ -4,6 +4,7 @@
 */
 /*
     Copyright (c) 2003, Juan Jose Garcia Ripoll.
+    Copyright (c) 2012, Matthew Mondor.
 
     ECL is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -29,82 +30,245 @@
  * LOCKS or MUTEX
  */
 
+
 static void
 FEerror_not_a_lock(cl_object lock)
 {
+
         FEwrong_type_argument(@'mp::lock', lock);
 }
 
+cl_object
+mp_recursive_lock_p(cl_object lock)
+{
+       cl_env_ptr env = ecl_process_env();
+       if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       ecl_return1(env, lock->lock.recursive? Ct : Cnil);
+}
+
+cl_object
+mp_lock_name(cl_object lock)
+{
+       cl_env_ptr env = ecl_process_env();
+       if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+        ecl_return1(env, lock->lock.name);
+}
+
+
+/*
+ * New POSIX implementation.  To debug race conditions, let's leave no chances
+ * in the implementation to cause any.  Let's use the POSIX implementation as
+ * directly as possible, and deprecate the race-prone counter/owner API.
+ */
+#ifndef ECL_WINDOWS_THREADS
+
+
+static int initialized = 0;
+
+static pthread_mutexattr_t mutexattr_normal;
+static pthread_mutexattr_t mutexattr_recursive;
+
+
 static void
-FEerror_not_a_recursive_lock(cl_object lock)
+lock_init(void)
 {
-        FEerror("Attempted to recursively lock ~S which is already owned by 
~S",
-                2, lock, lock->lock.holder);
+
+       pthread_mutexattr_init(&mutexattr_normal);
+       pthread_mutexattr_settype(&mutexattr_normal,
+           PTHREAD_MUTEX_ERRORCHECK);
+
+       pthread_mutexattr_init(&mutexattr_recursive);
+       pthread_mutexattr_settype(&mutexattr_recursive,
+           PTHREAD_MUTEX_RECURSIVE);
+
+       initialized = 1;
 }
 
+
 static void
-FEerror_not_owned(cl_object lock)
+FEunknown_lock_error(cl_object lock, cl_object op, cl_object error)
 {
-        FEerror("Attempted to give up lock ~S that is not owned by process ~S",
-                2, lock, mp_current_process());
+
+       FEerror("Error ~A occurred for operation ~A on lock ~A", 3,
+               error, op, lock);
 }
 
 static void
-FEunknown_lock_error(cl_object lock)
+FEerror_deprecated_lock_api(cl_object function, cl_object lock)
 {
-#ifdef ECL_WINDOWS_THREADS
-        FEwin32_error("When acting on lock ~A, got an unexpected error.", 1, 
lock);
-#else
-        FEerror("When acting on lock ~A, got an unexpected error.", 1, lock);
-#endif
+
+       FEerror("Called deprecated function ~A on lock ~A.",
+           2, function, lock);
 }
 
+
 cl_object
 ecl_make_lock(cl_object name, bool recursive)
 {
         cl_env_ptr the_env = ecl_process_env();
        cl_object output = ecl_alloc_object(t_lock);
        ecl_disable_interrupts_env(the_env);
+
+       if (!initialized)
+               lock_init();
+
+       pthread_mutex_init(&output->lock.mutex,
+           (recursive ? &mutexattr_recursive : &mutexattr_normal));
        output->lock.name = name;
-#ifdef ECL_WINDOWS_THREADS
-       output->lock.mutex = CreateMutex(NULL, FALSE, NULL);
-#else
-       {
-        pthread_mutexattr_t mutexattr_recursive[1];
-       pthread_mutexattr_init(mutexattr_recursive);
-       pthread_mutexattr_settype(mutexattr_recursive, PTHREAD_MUTEX_RECURSIVE);
-       pthread_mutex_init(&output->lock.mutex, mutexattr_recursive);
-       }
-#endif
        output->lock.holder = Cnil;
        output->lock.counter = 0;
        output->lock.recursive = recursive;
+
        ecl_set_finalizer_unprotected(output, Ct);
        ecl_enable_interrupts_env(the_env);
         return output;
 }
 
-@(defun mp::make-lock (&key name ((:recursive recursive) Ct))
-@
-       @(return ecl_make_lock(name, !Null(recursive)))
-@)
 
 cl_object
-mp_recursive_lock_p(cl_object lock)
+mp_lock_holder(cl_object lock)
 {
-       cl_env_ptr env = ecl_process_env();
+
        if (type_of(lock) != t_lock)
                FEerror_not_a_lock(lock);
-       ecl_return1(env, lock->lock.recursive? Ct : Cnil);
+       FEerror_deprecated_lock_api(
+           ecl_cstring_to_base_string_or_nil("MP:LOCK-HOLDER"),
+           lock);
 }
 
 cl_object
-mp_lock_name(cl_object lock)
+mp_lock_mine_p(cl_object lock)
+{
+
+       if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       FEerror_deprecated_lock_api(
+           ecl_cstring_to_base_string_or_nil("MP:LOCK-MINE-P"),
+           lock);
+}
+
+cl_object
+mp_lock_count(cl_object lock)
+{
+
+       if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       FEerror_deprecated_lock_api(
+           ecl_cstring_to_base_string_or_nil("MP:LOCK-COUNT"),
+           lock);
+}
+
+cl_object
+mp_lock_count_mine(cl_object lock)
 {
+
+       if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       FEerror_deprecated_lock_api(
+           ecl_cstring_to_base_string_or_nil("MP:LOCK-COUNT-MINE"),
+           lock);
+}
+
+
+/* Now let's deal as directly as possible with mutexes. */
+
+cl_object
+mp_giveup_lock(cl_object lock)
+{
+       int rc;
        cl_env_ptr env = ecl_process_env();
+
        if (type_of(lock) != t_lock)
                FEerror_not_a_lock(lock);
-        ecl_return1(env, lock->lock.name);
+       if ((rc = pthread_mutex_unlock(&lock->lock.mutex)) != 0)
+               FEunknown_lock_error(lock,
+                   ecl_cstring_to_base_string_or_nil("GIVEUP-LOCK"),
+                   ecl_make_int(rc));
+
+        ecl_return1(env, Ct);
+}
+
+cl_object
+mp_get_lock_nowait(cl_object lock)
+{
+       int rc;
+        cl_env_ptr env = ecl_process_env();
+
+        if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       if ((rc = pthread_mutex_trylock(&lock->lock.mutex)) != 0)
+               FEunknown_lock_error(lock,
+                   ecl_cstring_to_base_string_or_nil("GET-LOCK-NOWAIT"),
+                   ecl_make_int(rc));
+
+       ecl_return1(env, lock);
+}
+
+cl_object
+mp_get_lock_wait(cl_object lock)
+{
+       int rc;
+        cl_env_ptr env = ecl_process_env();
+
+        if (type_of(lock) != t_lock)
+               FEerror_not_a_lock(lock);
+       if ((rc = pthread_mutex_lock(&lock->lock.mutex)) != 0)
+               FEunknown_lock_error(lock,
+                   ecl_cstring_to_base_string_or_nil("GET-LOCK-WAIT"),
+                   ecl_make_int(rc));
+
+       ecl_return1(env, lock);
+}
+
+
+#endif /* !ECL_WINDOWS_THREADS */
+
+
+/*
+ * Old Windows implementation left as-is for now, but isolated separately.
+ */
+#ifdef ECL_WINDOWS_THREADS
+
+
+static void
+FEerror_not_a_recursive_lock(cl_object lock)
+{
+        FEerror("Attempted to recursively lock ~S which is already owned by 
~S",
+                2, lock, lock->lock.holder);
+}
+
+static void
+FEerror_not_owned(cl_object lock)
+{
+        FEerror("Attempted to give up lock ~S that is not owned by process ~S",
+                2, lock, mp_current_process());
+}
+
+static void
+FEunknown_lock_error(cl_object lock)
+{
+        FEwin32_error("When acting on lock ~A, got an unexpected error.",
+                     1, lock);
+}
+
+cl_object
+ecl_make_lock(cl_object name, bool recursive)
+{
+        cl_env_ptr the_env = ecl_process_env();
+       cl_object output = ecl_alloc_object(t_lock);
+
+       ecl_disable_interrupts_env(the_env);
+       output->lock.name = name;
+       output->lock.mutex = CreateMutex(NULL, FALSE, NULL);
+       output->lock.holder = Cnil;
+       output->lock.counter = 0;
+       output->lock.recursive = recursive;
+       ecl_set_finalizer_unprotected(output, Ct);
+       ecl_enable_interrupts_env(the_env);
+
+        return output;
 }
 
 cl_object
@@ -158,12 +322,8 @@ mp_giveup_lock(cl_object lock)
                 FEerror_not_owned(lock);
        if (--lock->lock.counter == 0) {
                lock->lock.holder = Cnil;
-#ifdef ECL_WINDOWS_THREADS
                if (ReleaseMutex(lock->lock.mutex) == 0)
                        FEunknown_lock_error(lock);
-#else
-               pthread_mutex_unlock(&lock->lock.mutex);
-#endif
        }
         ecl_return1(env, Ct);
 }
@@ -186,7 +346,6 @@ mp_get_lock_nowait(cl_object lock)
          * interrupts. If an interupt happens right after we locked the mutex
          * but before we set count and owner, we are in trouble, since the
          * mutex might be locked. */
-#ifdef ECL_WINDOWS_THREADS
        switch (WaitForSingleObject(lock->lock.mutex, 0)) {
                case WAIT_OBJECT_0:
                         lock->lock.counter++;
@@ -199,18 +358,6 @@ mp_get_lock_nowait(cl_object lock)
                        FEunknown_lock_error(lock);
                         ecl_return1(env, Cnil);
        }
-#else
-        rc = pthread_mutex_trylock(&lock->lock.mutex);
-       if (rc == 0) {
-               lock->lock.counter++;
-               lock->lock.holder = own_process;
-                ecl_return1(env, lock);
-       } else {
-                if (rc != EBUSY)
-                       FEunknown_lock_error(lock);
-                ecl_return1(env, Cnil);
-        }
-#endif
 }
 
 cl_object
@@ -231,7 +378,6 @@ mp_get_lock_wait(cl_object lock)
          * interrupts. If an interupt happens right after we locked the mutex
          * but before we set count and owner, we are in trouble, since the
          * mutex might be locked. */
-#ifdef ECL_WINDOWS_THREADS
        switch (WaitForSingleObject(lock->lock.mutex, INFINITE)) {
                case WAIT_OBJECT_0:
                         lock->lock.counter++;
@@ -244,19 +390,17 @@ mp_get_lock_wait(cl_object lock)
                         FEunknown_lock_error(lock);
                         ecl_return1(env, Cnil);
        }
-#else
-        rc = pthread_mutex_lock(&lock->lock.mutex);
-       if (rc == 0) {
-               lock->lock.counter++;
-               lock->lock.holder = own_process;
-                ecl_return1(env, lock);
-       } else {
-                FEunknown_lock_error(lock);
-                ecl_return1(env, Cnil);
-        }
-#endif
 }
 
+
+#endif /* ECL_WINDOWS_THREADS */
+
+
+@(defun mp::make-lock (&key name ((:recursive recursive) Ct))
+@
+       @(return ecl_make_lock(name, !Null(recursive)))
+@)
+
 @(defun mp::get-lock (lock &optional (wait Ct))
 @
        if (Null(wait))
@@ -264,3 +408,4 @@ mp_get_lock_wait(cl_object lock)
         else
                return mp_get_lock_wait(lock);
 @)
+
diff --git a/src/lsp/mp.lsp b/src/lsp/mp.lsp
index ce0a9c5..38ca207 100644
--- a/src/lsp/mp.lsp
+++ b/src/lsp/mp.lsp
@@ -107,23 +107,33 @@ by ALLOW-WITH-INTERRUPTS."
 (defmacro with-lock ((lock-form &rest options) &body body)
   #-threads
   `(progn ,@body)
-  ;; Why do we need %count? Even if get-lock succeeeds, an interrupt may
-  ;; happen between the end of get-lock and when we save the output of
-  ;; the function. That means we lose the information and ignore that
-  ;; the lock was actually acquired. Furthermore, a lock can be recursive
-  ;; and mp:lock-holder is also not reliable.
-  ;;
-  ;; Next notice how we need to disable interrupts around the body and
-  ;; the get-lock statement, to ensure that the unlocking is done with
-  ;; interrupts disabled.
   #+threads
-  (ext:with-unique-names (lock count)
-    `(let* ((,lock ,lock-form)
-            (,count (mp:lock-count-mine ,lock)))
+  #-windows
+  (ext:with-unique-names (lock)
+    `(let* ((,lock ,lock-form))
        (without-interrupts
            (unwind-protect
                 (with-restored-interrupts
                     (mp::get-lock ,lock)
                   (locally ,@body))
-             (when (> (mp:lock-count-mine ,lock) ,count)
-               (mp::giveup-lock ,lock)))))))
+            (mp::giveup-lock ,lock)))))
+  #+windows
+  (ext:with-unique-names (lock count)
+    ;; Why do we need %count? Even if get-lock succeeeds, an interrupt may
+    ;; happen between the end of get-lock and when we save the output of
+    ;; the function. That means we lose the information and ignore that
+    ;; the lock was actually acquired. Furthermore, a lock can be recursive
+    ;; and mp:lock-holder is also not reliable.
+    ;;
+    ;; Next notice how we need to disable interrupts around the body and
+    ;; the get-lock statement, to ensure that the unlocking is done with
+    ;; interrupts disabled.
+    `(let* ((,lock ,lock-form)
+           (,count (mp:lock-count-mine ,lock)))
+       (without-interrupts
+          (unwind-protect
+               (with-restored-interrupts
+                   (mp::get-lock ,lock)
+                 (locally ,@body))
+            (when (> (mp:lock-count-mine ,lock) ,count)
+              (mp::giveup-lock ,lock)))))))
------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing 
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/
_______________________________________________
Ecls-list mailing list
Ecls-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ecls-list

Reply via email to