Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1274 from MartinNowak/fix14584
Browse files Browse the repository at this point in the history
cleanup and rewrite rt.critical_
  • Loading branch information
MartinNowak committed May 20, 2015
2 parents fe4fe8b + 0b41a62 commit 17ba811
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 563 deletions.
216 changes: 34 additions & 182 deletions src/rt/critical_.d
Expand Up @@ -15,202 +15,54 @@ module rt.critical_;

nothrow:

private
{
debug(PRINTF) import core.stdc.stdio;
import core.stdc.stdlib;

version( CRuntime_Glibc )
{
version = USE_PTHREADS;
}
else version( FreeBSD )
{
version = USE_PTHREADS;
}
else version( OSX )
{
version = USE_PTHREADS;
}
else version( Solaris )
{
version = USE_PTHREADS;
}
else version( CRuntime_Bionic )
{
version = USE_PTHREADS;
}

version( Windows )
{
import core.sys.windows.windows;
import rt.monitor_, core.atomic;

/* 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.
*/
struct D_CRITICAL_SECTION
{
D_CRITICAL_SECTION *next;
CRITICAL_SECTION cs;
}
}
else version( USE_PTHREADS )
{
import core.sys.posix.pthread;

/* 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.
*/
struct D_CRITICAL_SECTION
{
D_CRITICAL_SECTION *next;
pthread_mutex_t cs;
}
}
else
{
static assert(0, "Unsupported platform");
}
extern (C) void _d_critical_init()
{
initMutex(cast(Mutex*)&gcs.mtx);
head = &gcs;
}


/* ================================= Win32 ============================ */

version( Windows )
extern (C) void _d_critical_term()
{
version (CRuntime_DigitalMars)
pragma(lib, "snn.lib");

/******************************************
* Enter/exit critical section.
*/

static __gshared D_CRITICAL_SECTION *dcs_list;
static __gshared D_CRITICAL_SECTION critical_section;
static __gshared int inited;

extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs_list)
{
_STI_critical_init();
atexit(&_STD_critical_term);
}
debug(PRINTF) printf("_d_criticalenter(dcs = x%x)\n", 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);
}

extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
LeaveCriticalSection(&dcs.cs);
}

extern (C) void _STI_critical_init()
{
if (!inited)
{
debug(PRINTF) printf("_STI_critical_init()\n");
InitializeCriticalSection(&critical_section.cs);
dcs_list = &critical_section;
inited = 1;
}
}

extern (C) void _STD_critical_term()
{
if (inited)
{
debug(PRINTF) printf("_STI_critical_term()\n");
while (dcs_list)
{
debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
DeleteCriticalSection(&dcs_list.cs);
dcs_list = dcs_list.next;
}
inited = 0;
}
}
for (auto p = head; p; p = p.next)
destroyMutex(cast(Mutex*)&p.mtx);
}

/* ================================= linux ============================ */

version( USE_PTHREADS )
extern (C) void _d_criticalenter(D_CRITICAL_SECTION* cs)
{
/******************************************
* Enter/exit critical section.
*/

static __gshared D_CRITICAL_SECTION *dcs_list;
static __gshared D_CRITICAL_SECTION critical_section;
static __gshared pthread_mutexattr_t _criticals_attr;
ensureMutex(cast(shared(D_CRITICAL_SECTION*)) cs);
lockMutex(&cs.mtx);
}

extern (C) void _d_criticalenter(D_CRITICAL_SECTION *dcs)
{
if (!dcs_list)
{
_STI_critical_init();
atexit(&_STD_critical_term);
}
debug(PRINTF) 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);
}
extern (C) void _d_criticalexit(D_CRITICAL_SECTION* cs)
{
unlockMutex(&cs.mtx);
}

extern (C) void _d_criticalexit(D_CRITICAL_SECTION *dcs)
{
debug(PRINTF) printf("_d_criticalexit(dcs = x%x)\n", dcs);
pthread_mutex_unlock(&dcs.cs);
}
private:

extern (C) void _STI_critical_init()
{
if (!dcs_list)
{
debug(PRINTF) printf("_STI_critical_init()\n");
pthread_mutexattr_init(&_criticals_attr);
pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
shared D_CRITICAL_SECTION* head;
shared D_CRITICAL_SECTION gcs;

// The global critical section doesn't need to be recursive
pthread_mutex_init(&critical_section.cs, null);
dcs_list = &critical_section;
}
}
struct D_CRITICAL_SECTION
{
D_CRITICAL_SECTION* next;
Mutex mtx;
}

extern (C) void _STD_critical_term()
void ensureMutex(shared(D_CRITICAL_SECTION)* cs)
{
if (atomicLoad!(MemoryOrder.acq)(cs.next) is null)
{
if (dcs_list)
lockMutex(cast(Mutex*)&gcs.mtx);
if (atomicLoad!(MemoryOrder.raw)(cs.next) is null)
{
debug(PRINTF) printf("_STI_critical_term()\n");
while (dcs_list)
{
debug(PRINTF) printf("\tlooping... %x\n", dcs_list);
pthread_mutex_destroy(&dcs_list.cs);
dcs_list = dcs_list.next;
}
initMutex(cast(Mutex*)&cs.mtx);
auto ohead = head;
head = cs;
atomicStore!(MemoryOrder.rel)(cs.next, ohead);
}
unlockMutex(cast(Mutex*)&gcs.mtx);
}
}
20 changes: 10 additions & 10 deletions src/rt/dmain2.d
Expand Up @@ -37,10 +37,10 @@ version (FreeBSD)
import core.stdc.fenv;
}

extern (C) void _STI_monitor_staticctor();
extern (C) void _STD_monitor_staticdtor();
extern (C) void _STI_critical_init();
extern (C) void _STD_critical_term();
extern (C) void _d_monitor_staticctor();
extern (C) void _d_monitor_staticdtor();
extern (C) void _d_critical_init();
extern (C) void _d_critical_term();
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void lifetime_init();
Expand Down Expand Up @@ -159,8 +159,8 @@ extern (C) int rt_init()
rt_init. */
if (atomicOp!"+="(_initCount, 1) > 1) return 1;

_STI_monitor_staticctor();
_STI_critical_init();
_d_monitor_staticctor();
_d_critical_init();

try
{
Expand All @@ -177,8 +177,8 @@ extern (C) int rt_init()
_initCount = 0;
_d_print_throwable(t);
}
_STD_critical_term();
_STD_monitor_staticdtor();
_d_critical_term();
_d_monitor_staticdtor();
return 0;
}

Expand All @@ -205,8 +205,8 @@ extern (C) int rt_term()
}
finally
{
_STD_critical_term();
_STD_monitor_staticdtor();
_d_critical_term();
_d_monitor_staticdtor();
}
return 0;
}
Expand Down

0 comments on commit 17ba811

Please sign in to comment.