diff druntime/src/common/core/sync/mutex.d @ 1458:e0b2d67cfe7c

Added druntime (this should be removed once it works).
author Robert Clipsham <robert@octarineparrot.com>
date Tue, 02 Jun 2009 17:43:06 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/druntime/src/common/core/sync/mutex.d	Tue Jun 02 17:43:06 2009 +0100
@@ -0,0 +1,268 @@
+/**
+ * The mutex module provides a primitive for maintaining mutually exclusive
+ * access.
+ *
+ * Copyright: Copyright Sean Kelly 2005 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Sean Kelly
+ *
+ *          Copyright Sean Kelly 2005 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module core.sync.mutex;
+
+
+public import core.sync.exception;
+
+version( Win32 )
+{
+    private import core.sys.windows.windows;
+}
+else version( Posix )
+{
+    private import core.sys.posix.pthread;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Mutex
+//
+// void lock();
+// void unlock();
+// bool tryLock();
+////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * This class represents a general purpose, recursive mutex.
+ */
+class Mutex :
+    Object.Monitor
+{
+    ////////////////////////////////////////////////////////////////////////////
+    // Initialization
+    ////////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Initializes a mutex object.
+     *
+     * Throws:
+     *  SyncException on error.
+     */
+    this()
+    {
+        version( Win32 )
+        {
+            InitializeCriticalSection( &m_hndl );
+        }
+        else version( Posix )
+        {
+            int rc = pthread_mutex_init( &m_hndl, &sm_attr );
+            if( rc )
+                throw new SyncException( "Unable to initialize mutex" );
+        }
+        m_proxy.link = this;
+        // NOTE: With DMD this can be "this.__monitor = &m_proxy".
+        (cast(void**) this)[1] = &m_proxy;
+    }
+
+
+    /**
+     * Initializes a mutex object and sets it as the monitor for o.
+     *
+     * In:
+     *  o must not already have a monitor.
+     */
+    this( Object o )
+    in
+    {
+        // NOTE: With DMD this can be "o.__monitor is null".
+        assert( (cast(void**) o)[1] is null );
+    }
+    body
+    {
+        this();
+        // NOTE: With DMD this can be "o.__monitor = &m_proxy".
+        (cast(void**) o)[1] = &m_proxy;
+    }
+
+
+    ~this()
+    {
+        version( Win32 )
+        {
+            DeleteCriticalSection( &m_hndl );
+        }
+        else version( Posix )
+        {
+            int rc = pthread_mutex_destroy( &m_hndl );
+            assert( !rc, "Unable to destroy mutex" );
+        }
+        (cast(void**) this)[1] = null;
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+    // General Actions
+    ////////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * If this lock is not already held by the caller, the lock is acquired,
+     * then the internal counter is incremented by one.
+     *
+     * Throws:
+     *  SyncException on error.
+     */
+    void lock()
+    {
+        version( Win32 )
+        {
+            EnterCriticalSection( &m_hndl );
+        }
+        else version( Posix )
+        {
+            int rc = pthread_mutex_lock( &m_hndl );
+            if( rc )
+                throw new SyncException( "Unable to lock mutex" );
+        }
+    }
+
+
+    /**
+     * Decrements the internal lock count by one.  If this brings the count to
+     * zero, the lock is released.
+     *
+     * Throws:
+     *  SyncException on error.
+     */
+    void unlock()
+    {
+        version( Win32 )
+        {
+            LeaveCriticalSection( &m_hndl );
+        }
+        else version( Posix )
+        {
+            int rc = pthread_mutex_unlock( &m_hndl );
+            if( rc )
+                throw new SyncException( "Unable to unlock mutex" );
+        }
+    }
+
+
+    /**
+     * If the lock is held by another caller, the method returns.  Otherwise,
+     * the lock is acquired if it is not already held, and then the internal
+     * counter is incremented by one.
+     *
+     * Throws:
+     *  SyncException on error.
+     *
+     * Returns:
+     *  true if the lock was acquired and false if not.
+     */
+    bool tryLock()
+    {
+        version( Win32 )
+        {
+            return TryEnterCriticalSection( &m_hndl ) != 0;
+        }
+        else version( Posix )
+        {
+            return pthread_mutex_trylock( &m_hndl ) == 0;
+        }
+    }
+
+
+    version( Posix )
+    {
+        static this()
+        {
+            int rc = pthread_mutexattr_init( &sm_attr );
+            assert( !rc );
+
+            rc = pthread_mutexattr_settype( &sm_attr, PTHREAD_MUTEX_RECURSIVE );
+            assert( !rc );
+        }
+
+
+        static ~this()
+        {
+            int rc = pthread_mutexattr_destroy( &sm_attr );
+            assert( !rc );
+        }
+    }
+
+
+private:
+    version( Win32 )
+    {
+        CRITICAL_SECTION    m_hndl;
+    }
+    else version( Posix )
+    {
+        __gshared pthread_mutexattr_t  sm_attr;
+
+        pthread_mutex_t     m_hndl;
+    }
+
+    struct MonitorProxy
+    {
+        Object.Monitor link;
+    }
+
+    MonitorProxy            m_proxy;
+
+
+package:
+    version( Posix )
+    {
+        pthread_mutex_t* handleAddr()
+        {
+            return &m_hndl;
+        }
+    }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Unit Tests
+////////////////////////////////////////////////////////////////////////////////
+
+
+version( unittest )
+{
+    private import core.thread;
+
+
+    unittest
+    {
+        auto mutex      = new Mutex;
+        int  numThreads = 10;
+        int  numTries   = 1000;
+        int  lockCount  = 0;
+
+        void testFn()
+        {
+            for( int i = 0; i < numTries; ++i )
+            {
+                synchronized( mutex )
+                {
+                    ++lockCount;
+                }
+            }
+        }
+
+        auto group = new ThreadGroup;
+
+        for( int i = 0; i < numThreads; ++i )
+            group.create( &testFn );
+
+        group.joinAll();
+        assert( lockCount == numThreads * numTries );
+    }
+}