PageRenderTime 23ms CodeModel.GetById 18ms app.highlight 4ms RepoModel.GetById 0ms app.codeStats 0ms

/src/rt/critical.c

http://github.com/AlexeyProkhin/druntime
C | 176 lines | 113 code | 29 blank | 34 comment | 13 complexity | 819be97193b302f76c479144bc8efe81 MD5 | raw file
  1/**
  2 * Implementation of support routines for synchronized blocks.
  3 *
  4 * Copyright: Copyright Digital Mars 2000 - 2010.
  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 - 2010.
 10 * Distributed under the Boost Software License, Version 1.0.
 11 *    (See accompanying file LICENSE_1_0.txt or copy at
 12 *          http://www.boost.org/LICENSE_1_0.txt)
 13 */
 14
 15/* ================================= Win32 ============================ */
 16
 17#if _WIN32
 18
 19#include <windows.h>
 20
 21/******************************************
 22 * Enter/exit critical section.
 23 */
 24
 25/* We don't initialize critical sections unless we actually need them.
 26 * So keep a linked list of the ones we do use, and in the static destructor
 27 * code, walk the list and release them.
 28 */
 29
 30typedef struct D_CRITICAL_SECTION
 31{
 32    struct D_CRITICAL_SECTION *next;
 33    CRITICAL_SECTION cs;
 34} D_CRITICAL_SECTION;
 35
 36static D_CRITICAL_SECTION *dcs_list;
 37static D_CRITICAL_SECTION critical_section;
 38static volatile int inited;
 39
 40void _d_criticalenter(D_CRITICAL_SECTION *dcs)
 41{
 42    if (!dcs->next)
 43    {
 44        EnterCriticalSection(&critical_section.cs);
 45        if (!dcs->next) // if, in the meantime, another thread didn't set it
 46        {
 47            dcs->next = dcs_list;
 48            dcs_list = dcs;
 49            InitializeCriticalSection(&dcs->cs);
 50        }
 51        LeaveCriticalSection(&critical_section.cs);
 52    }
 53    EnterCriticalSection(&dcs->cs);
 54}
 55
 56void _d_criticalexit(D_CRITICAL_SECTION *dcs)
 57{
 58    LeaveCriticalSection(&dcs->cs);
 59}
 60
 61void _STI_critical_init()
 62{
 63    if (!inited)
 64    {   InitializeCriticalSection(&critical_section.cs);
 65        dcs_list = &critical_section;
 66        inited = 1;
 67    }
 68}
 69
 70void _STD_critical_term()
 71{
 72    if (inited)
 73    {   inited = 0;
 74        while (dcs_list)
 75        {
 76            DeleteCriticalSection(&dcs_list->cs);
 77            dcs_list = dcs_list->next;
 78        }
 79    }
 80}
 81
 82#endif
 83
 84/* ================================= linux ============================ */
 85
 86#if linux || __APPLE__ || __FreeBSD__
 87
 88#include <stdio.h>
 89#include <stdlib.h>
 90#include <pthread.h>
 91
 92// PTHREAD_MUTEX_RECURSIVE is the "standard" symbol,
 93// while the _NP version is specific to Linux
 94#if linux
 95#  ifndef PTHREAD_MUTEX_RECURSIVE
 96#    define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
 97#  endif
 98#endif
 99
100/******************************************
101 * Enter/exit critical section.
102 */
103
104/* We don't initialize critical sections unless we actually need them.
105 * So keep a linked list of the ones we do use, and in the static destructor
106 * code, walk the list and release them.
107 */
108
109typedef struct D_CRITICAL_SECTION
110{
111    struct D_CRITICAL_SECTION *next;
112    pthread_mutex_t cs;
113} D_CRITICAL_SECTION;
114
115static D_CRITICAL_SECTION *dcs_list;
116static D_CRITICAL_SECTION critical_section;
117static pthread_mutexattr_t _criticals_attr;
118
119void _STI_critical_init(void);
120void _STD_critical_term(void);
121
122void _d_criticalenter(D_CRITICAL_SECTION *dcs)
123{
124    if (!dcs_list)
125    {   _STI_critical_init();
126        atexit(_STD_critical_term);
127    }
128    //printf("_d_criticalenter(dcs = x%x)\n", dcs);
129    if (!dcs->next)
130    {
131        pthread_mutex_lock(&critical_section.cs);
132        if (!dcs->next) // if, in the meantime, another thread didn't set it
133        {
134            dcs->next = dcs_list;
135            dcs_list = dcs;
136            pthread_mutex_init(&dcs->cs, &_criticals_attr);
137        }
138        pthread_mutex_unlock(&critical_section.cs);
139    }
140    pthread_mutex_lock(&dcs->cs);
141}
142
143void _d_criticalexit(D_CRITICAL_SECTION *dcs)
144{
145    //printf("_d_criticalexit(dcs = x%x)\n", dcs);
146    pthread_mutex_unlock(&dcs->cs);
147}
148
149void _STI_critical_init()
150{
151    if (!dcs_list)
152    {   //printf("_STI_critical_init()\n");
153        pthread_mutexattr_init(&_criticals_attr);
154        pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
155
156        // The global critical section doesn't need to be recursive
157        pthread_mutex_init(&critical_section.cs, 0);
158        dcs_list = &critical_section;
159    }
160}
161
162void _STD_critical_term()
163{
164    if (dcs_list)
165    {   //printf("_STI_critical_term()\n");
166        while (dcs_list)
167        {
168            //printf("\tlooping... %x\n", dcs_list);
169            pthread_mutex_destroy(&dcs_list->cs);
170            dcs_list = dcs_list->next;
171        }
172    }
173}
174
175#endif
176