ldc/runtime/internal/critical.c

164 lines
3.6 KiB
C

/*
* Placed into the Public Domain
* written by Walter Bright, Digital Mars
* www.digitalmars.com
*/
/* ================================= 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__ || __FreeBSD__ || (defined(__SVR4) && defined (__sun))
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#if !linux
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#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_NP);
// 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