PageRenderTime 80ms CodeModel.GetById 45ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/rt/critical_.d

http://github.com/AlexeyProkhin/druntime
D | 211 lines | 158 code | 24 blank | 29 comment | 16 complexity | 6c94a848845b192826b97da5ffd92456 MD5 | raw file
  1/**
  2 * Implementation of support routines for synchronized blocks.
  3 *
  4 * Copyright: Copyright Digital Mars 2000 - 2011.
  5 * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
  6 * Authors:   Walter Bright, Sean Kelly
  7 */
  8
  9/*          Copyright Digital Mars 2000 - 2011.
 10 * Distributed under the Boost Software License, Version 1.0.
 11 *    (See accompanying file LICENSE or copy at
 12 *          http://www.boost.org/LICENSE_1_0.txt)
 13 */
 14module rt.critical_;
 15
 16private
 17{
 18    debug(PRINTF) import core.stdc.stdio;
 19    import core.stdc.stdlib;
 20
 21    version( linux )
 22    {
 23        version = USE_PTHREADS;
 24    }
 25    else version( FreeBSD )
 26    {
 27        version = USE_PTHREADS;
 28    }
 29    else version( OSX )
 30    {
 31        version = USE_PTHREADS;
 32    }
 33    else version( Solaris )
 34    {
 35        version = USE_PTHREADS;
 36    }
 37
 38    version( Windows )
 39    {
 40        import core.sys.windows.windows;
 41
 42        /* We don't initialize critical sections unless we actually need them.
 43         * So keep a linked list of the ones we do use, and in the static destructor
 44         * code, walk the list and release them.
 45         */
 46        struct D_CRITICAL_SECTION
 47        {
 48            D_CRITICAL_SECTION *next;
 49            CRITICAL_SECTION cs;
 50        }
 51    }
 52    else version( USE_PTHREADS )
 53    {
 54        import core.sys.posix.pthread;
 55
 56        /* We don't initialize critical sections unless we actually need them.
 57         * So keep a linked list of the ones we do use, and in the static destructor
 58         * code, walk the list and release them.
 59         */
 60        struct D_CRITICAL_SECTION
 61        {
 62            D_CRITICAL_SECTION *next;
 63            pthread_mutex_t cs;
 64        }
 65    }
 66    else
 67    {
 68        static assert(0, "Unsupported platform");
 69    }
 70}
 71
 72
 73/* ================================= Win32 ============================ */
 74
 75version( Windows )
 76{
 77    version (DigitalMars) version (Win32)
 78        pragma(lib, "snn.lib");
 79
 80    /******************************************
 81     * Enter/exit critical section.
 82     */
 83
 84    static __gshared D_CRITICAL_SECTION *dcs_list;
 85    static __gshared D_CRITICAL_SECTION critical_section;
 86    static __gshared int inited;
 87
 88    extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
 89    {
 90        if (!dcs_list)
 91        {
 92            _STI_critical_init();
 93            atexit(&_STD_critical_term);
 94        }
 95        debug(PRINTF) printf("_d_criticalenter(dcs = x%x)\n", dcs);
 96        if (!dcs.next)
 97        {
 98            EnterCriticalSection(&critical_section.cs);
 99            if (!dcs.next) // if, in the meantime, another thread didn't set it
100            {
101                dcs.next = dcs_list;
102                dcs_list = dcs;
103                InitializeCriticalSection(&dcs.cs);
104            }
105            LeaveCriticalSection(&critical_section.cs);
106        }
107        EnterCriticalSection(&dcs.cs);
108    }
109
110    extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
111    {
112        debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
113        LeaveCriticalSection(&dcs.cs);
114    }
115
116    extern (C) void _STI_critical_init()
117    {
118        if (!inited)
119        {
120            debug(PRINTF) printf("_STI_critical_init()\n");
121            InitializeCriticalSection(&critical_section.cs);
122            dcs_list = &critical_section;
123            inited = 1;
124        }
125    }
126
127    extern (C) void _STD_critical_term()
128    {
129        if (inited)
130        {
131            debug(PRINTF) printf("_STI_critical_term()\n");
132            while (dcs_list)
133            {
134                debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
135                DeleteCriticalSection(&dcs_list.cs);
136                dcs_list = dcs_list.next;
137            }
138            inited = 0;
139        }
140    }
141}
142
143/* ================================= linux ============================ */
144
145version( USE_PTHREADS )
146{
147    /******************************************
148     * Enter/exit critical section.
149     */
150
151    static __gshared D_CRITICAL_SECTION *dcs_list;
152    static __gshared D_CRITICAL_SECTION critical_section;
153    static __gshared pthread_mutexattr_t _criticals_attr;
154
155    extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
156    {
157        if (!dcs_list)
158        {
159            _STI_critical_init();
160            atexit(&_STD_critical_term);
161        }
162        debug(PRINTF) printf("_d_criticalenter(dcs = x%x)\n", dcs);
163        if (!dcs.next)
164        {
165            pthread_mutex_lock(&critical_section.cs);
166            if (!dcs.next) // if, in the meantime, another thread didn't set it
167            {
168                dcs.next = dcs_list;
169                dcs_list = dcs;
170                pthread_mutex_init(&dcs.cs, &_criticals_attr);
171            }
172            pthread_mutex_unlock(&critical_section.cs);
173        }
174        pthread_mutex_lock(&dcs.cs);
175    }
176
177    extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
178    {
179        debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
180        pthread_mutex_unlock(&dcs.cs);
181    }
182
183    extern (C) void _STI_critical_init()
184    {
185        if (!dcs_list)
186        {
187            debug(PRINTF) printf("_STI_critical_init()\n");
188            pthread_mutexattr_init(&_criticals_attr);
189            pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
190
191            // The global critical section doesn't need to be recursive
192            pthread_mutex_init(&critical_section.cs, null);
193            dcs_list = &critical_section;
194        }
195    }
196
197    extern (C) void _STD_critical_term()
198    {
199        if (dcs_list)
200        {
201            debug(PRINTF) printf("_STI_critical_term()\n");
202            while (dcs_list)
203            {
204                debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
205                pthread_mutex_destroy(&dcs_list.cs);
206                dcs_list = dcs_list.next;
207            }
208        }
209    }
210}
211