diff druntime/src/compiler/dmd/critical.c @ 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/compiler/dmd/critical.c	Tue Jun 02 17:43:06 2009 +0100
@@ -0,0 +1,173 @@
+/**
+ * Implementation of support routines for synchronized blocks.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 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)
+ */
+
+/* ================================= Win32 ============================ */
+
+#if _WIN32
+
+#include <windows.h>
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    CRITICAL_SECTION cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static volatile int inited;
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs->next)
+    {
+        EnterCriticalSection(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            InitializeCriticalSection(&dcs->cs);
+        }
+        LeaveCriticalSection(&critical_section.cs);
+    }
+    EnterCriticalSection(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    LeaveCriticalSection(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!inited)
+    {   InitializeCriticalSection(&critical_section.cs);
+        dcs_list = &critical_section;
+        inited = 1;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (inited)
+    {   inited = 0;
+        while (dcs_list)
+        {
+            DeleteCriticalSection(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
+
+/* ================================= linux ============================ */
+
+#if linux || __APPLE__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+// PTHREAD_MUTEX_RECURSIVE is the "standard" symbol,
+// while the _NP version is specific to Linux
+#ifndef PTHREAD_MUTEX_RECURSIVE
+#    define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    pthread_mutex_t cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static pthread_mutexattr_t _criticals_attr;
+
+void _STI_critical_init(void);
+void _STD_critical_term(void);
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs_list)
+    {   _STI_critical_init();
+        atexit(_STD_critical_term);
+    }
+    //printf("_d_criticalenter(dcs = x%x)\n", dcs);
+    if (!dcs->next)
+    {
+        pthread_mutex_lock(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            pthread_mutex_init(&dcs->cs, &_criticals_attr);
+        }
+        pthread_mutex_unlock(&critical_section.cs);
+    }
+    pthread_mutex_lock(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    //printf("_d_criticalexit(dcs = x%x)\n", dcs);
+    pthread_mutex_unlock(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!dcs_list)
+    {   //printf("_STI_critical_init()\n");
+        pthread_mutexattr_init(&_criticals_attr);
+        pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
+
+        // The global critical section doesn't need to be recursive
+        pthread_mutex_init(&critical_section.cs, 0);
+        dcs_list = &critical_section;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (dcs_list)
+    {   //printf("_STI_critical_term()\n");
+        while (dcs_list)
+        {
+            //printf("\tlooping... %x\n", dcs_list);
+            pthread_mutex_destroy(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
+