mirror of
https://github.com/dlang/phobos.git
synced 2025-04-26 21:22:20 +03:00
phobos 0.65
This commit is contained in:
parent
dba8d9bcaa
commit
c7ea30e9a0
31 changed files with 2923 additions and 162 deletions
18
adi.d
18
adi.d
|
@ -42,7 +42,12 @@ extern (C) Array _adReverse(Array a, int szelem)
|
|||
|
||||
tmp = buffer;
|
||||
if (szelem > 16)
|
||||
tmp = (byte*) alloca(szelem);
|
||||
{
|
||||
//version (Win32)
|
||||
tmp = (byte*) alloca(szelem);
|
||||
//else
|
||||
//tmp = new byte[szelem];
|
||||
}
|
||||
|
||||
for (; lo < hi; lo += szelem, hi -= szelem)
|
||||
{
|
||||
|
@ -50,6 +55,17 @@ extern (C) Array _adReverse(Array a, int szelem)
|
|||
memcpy(lo, hi, szelem);
|
||||
memcpy(hi, tmp, szelem);
|
||||
}
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (szelem > 16)
|
||||
// BUG: bad code is generate for delete pointer, tries
|
||||
// to call delclass.
|
||||
//delete tmp;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
|
130
alloca.d
Normal file
130
alloca.d
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*_ _alloca.d
|
||||
* Copyright (C) 1990-2003 by Digital Mars, www.digitalmars.com
|
||||
* All Rights Reserved
|
||||
* Written by Walter Bright
|
||||
*/
|
||||
|
||||
/+
|
||||
#if DOS386
|
||||
extern size_t _x386_break;
|
||||
#else
|
||||
extern size_t _pastdata;
|
||||
#endif
|
||||
+/
|
||||
|
||||
/*******************************************
|
||||
* Allocate data from the caller's stack frame.
|
||||
* This is a 'magic' function that needs help from the compiler to
|
||||
* work right, do not change its name, do not call it from other compilers.
|
||||
* Input:
|
||||
* nbytes number of bytes to allocate
|
||||
* ECX address of variable with # of bytes in locals
|
||||
* This is adjusted upon return to reflect the additional
|
||||
* size of the stack frame.
|
||||
* Returns:
|
||||
* EAX allocated data, null if stack overflows
|
||||
*/
|
||||
|
||||
extern (C) void* __alloca(int nbytes)
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked ;
|
||||
mov EDX,ECX ;
|
||||
mov EAX,4[ESP] ; // get nbytes
|
||||
push EBX ;
|
||||
push EDI ;
|
||||
push ESI ;
|
||||
add EAX,3 ;
|
||||
and EAX,0xFFFFFFFC ; // round up to dword
|
||||
jnz Abegin ;
|
||||
mov EAX,4 ; // allow zero bytes allocation, 0 rounded to dword is 4..
|
||||
Abegin:
|
||||
mov ESI,EAX ; // ESI = nbytes
|
||||
neg EAX ;
|
||||
add EAX,ESP ; // EAX is now what the new ESP will be.
|
||||
jae Aoverflow ;
|
||||
}
|
||||
version (Win32)
|
||||
{
|
||||
asm
|
||||
{
|
||||
// We need to be careful about the guard page
|
||||
// Thus, for every 4k page, touch it to cause the OS to load it in.
|
||||
mov ECX,EAX ; // ECX is new location for stack
|
||||
mov EBX,ESI ; // EBX is size to "grow" stack
|
||||
L1:
|
||||
test [ECX+EBX],EBX ; // bring in page
|
||||
sub EBX,0x1000 ; // next 4K page down
|
||||
jae L1 ; // if more pages
|
||||
test [ECX],EBX ; // bring in last page
|
||||
}
|
||||
}
|
||||
version (DOS386)
|
||||
{
|
||||
asm
|
||||
{
|
||||
// is ESP off bottom?
|
||||
cmp EAX,_x386_break ;
|
||||
jbe Aoverflow ;
|
||||
}
|
||||
}
|
||||
version (Unix)
|
||||
{
|
||||
asm
|
||||
{
|
||||
cmp EAX,_pastdata ;
|
||||
jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX
|
||||
}
|
||||
}
|
||||
asm
|
||||
{
|
||||
// Copy down to [ESP] the temps on the stack.
|
||||
// The number of temps is (EBP - ESP - locals).
|
||||
mov ECX,EBP ;
|
||||
sub ECX,ESP ;
|
||||
sub ECX,[EDX] ; // ECX = number of temps (bytes) to move.
|
||||
add [EDX],ESI ; // adjust locals by nbytes for next call to alloca()
|
||||
mov ESP,EAX ; // Set up new stack pointer.
|
||||
add EAX,ECX ; // Return value = ESP + temps.
|
||||
mov EDI,ESP ; // Destination of copy of temps.
|
||||
add ESI,ESP ; // Source of copy.
|
||||
shr ECX,2 ; // ECX to count of dwords in temps
|
||||
// Always at least 4 (nbytes, EIP, ESI,and EDI).
|
||||
rep ;
|
||||
movsd ;
|
||||
jmp done ;
|
||||
|
||||
Aoverflow:
|
||||
// Overflowed the stack. Return null
|
||||
xor EAX,EAX ;
|
||||
|
||||
done:
|
||||
pop ESI ;
|
||||
pop EDI ;
|
||||
pop EBX ;
|
||||
ret ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
206
cmath.d
Normal file
206
cmath.d
Normal file
|
@ -0,0 +1,206 @@
|
|||
|
||||
// Copyright (C) 2001-2003 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// www.digitalmars.com
|
||||
|
||||
// Runtime support for complex arithmetic code generation
|
||||
|
||||
import math;
|
||||
|
||||
extern (C):
|
||||
|
||||
/****************************
|
||||
* Multiply two complex floating point numbers, x and y.
|
||||
* Input:
|
||||
* x.re ST3
|
||||
* x.im ST2
|
||||
* y.re ST1
|
||||
* y.im ST0
|
||||
* Output:
|
||||
* ST1 real part
|
||||
* ST0 imaginary part
|
||||
*/
|
||||
|
||||
void _Cmul()
|
||||
{
|
||||
// p.re = x.re * y.re - x.im * y.im;
|
||||
// p.im = x.im * y.re + x.re * y.im;
|
||||
asm
|
||||
{ naked ;
|
||||
fld ST(1) ; // x.re
|
||||
fmul ST,ST(4) ; // ST0 = x.re * y.re
|
||||
|
||||
fld ST(1) ; // y.im
|
||||
fmul ST,ST(4) ; // ST0 = x.im * y.im
|
||||
|
||||
fsubp ST(1),ST ; // ST0 = x.re * y.re - x.im * y.im
|
||||
|
||||
fld ST(3) ; // x.im
|
||||
fmul ST,ST(3) ; // ST0 = x.im * y.re
|
||||
|
||||
fld ST(5) ; // x.re
|
||||
fmul ST,ST(3) ; // ST0 = x.re * y.im
|
||||
|
||||
faddp ST(1),ST ; // ST0 = x.im * y.re + x.re * y.im
|
||||
|
||||
fxch ST(4),ST ;
|
||||
fstp ST(0) ;
|
||||
fxch ST(4),ST ;
|
||||
fstp ST(0) ;
|
||||
fstp ST(0) ;
|
||||
fstp ST(0) ;
|
||||
|
||||
ret ;
|
||||
}
|
||||
/+
|
||||
if (isnan(x) && isnan(y))
|
||||
{
|
||||
// Recover infinities that computed as NaN+ iNaN ...
|
||||
int recalc = 0;
|
||||
if ( isinf( a) || isinf( b) )
|
||||
{ // z is infinite
|
||||
// "Box" the infinity and change NaNs in the other factor to 0
|
||||
a = copysignl( isinf( a) ? 1.0 : 0.0, a);
|
||||
b = copysignl( isinf( b) ? 1.0 : 0.0, b);
|
||||
if (isnan( c)) c = copysignl( 0.0, c);
|
||||
if (isnan( d)) d = copysignl( 0.0, d);
|
||||
recalc = 1;
|
||||
}
|
||||
if (isinf(c) || isinf(d))
|
||||
{ // w is infinite
|
||||
// "Box" the infinity and change NaNs in the other factor to 0
|
||||
c = copysignl( isinf( c) ? 1.0 : 0.0, c);
|
||||
d = copysignl( isinf( d) ? 1.0 : 0.0, d);
|
||||
if (isnan( a)) a = copysignl( 0.0, a);
|
||||
if (isnan( b)) b = copysignl( 0.0, b);
|
||||
recalc = 1;
|
||||
}
|
||||
if (!recalc && (isinf(ac) || isinf(bd) ||
|
||||
isinf(ad) || isinf(bc)))
|
||||
{
|
||||
// Recover infinities from overflow by changing NaNs to 0 ...
|
||||
if (isnan( a)) a = copysignl( 0.0, a);
|
||||
if (isnan( b)) b = copysignl( 0.0, b);
|
||||
if (isnan( c)) c = copysignl( 0.0, c);
|
||||
if (isnan( d)) d = copysignl( 0.0, d);
|
||||
recalc = 1;
|
||||
}
|
||||
if (recalc)
|
||||
{
|
||||
x = INFINITY * (a * c - b * d);
|
||||
y = INFINITY * (a * d + b * c);
|
||||
}
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Divide two complex floating point numbers, x / y.
|
||||
* Input:
|
||||
* x.re ST3
|
||||
* x.im ST2
|
||||
* y.re ST1
|
||||
* y.im ST0
|
||||
* Output:
|
||||
* ST1 real part
|
||||
* ST0 imaginary part
|
||||
*/
|
||||
|
||||
creal _Cdiv()
|
||||
{
|
||||
real x_re, x_im;
|
||||
real y_re, y_im;
|
||||
real q_re, q_im;
|
||||
real r;
|
||||
real den;
|
||||
|
||||
asm
|
||||
{
|
||||
fstp y_im ;
|
||||
fstp y_re ;
|
||||
fstp x_im ;
|
||||
fstp x_re ;
|
||||
}
|
||||
|
||||
if (fabs(y_re) < fabs(y_im))
|
||||
{
|
||||
r = y_re / y_im;
|
||||
den = y_im + r * y_re;
|
||||
q_re = (x_re * r + x_im) / den;
|
||||
q_im = (x_im * r - x_re) / den;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = y_im / y_re;
|
||||
den = y_re + r * y_im;
|
||||
q_re = (x_re + r * x_im) / den;
|
||||
q_im = (x_im - r * x_re) / den;
|
||||
}
|
||||
//printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im);
|
||||
/+
|
||||
if (isnan(q_re) && isnan(q_im))
|
||||
{
|
||||
real denom = y_re * y_re + y_im * y_im;
|
||||
|
||||
// non-zero / zero
|
||||
if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im)))
|
||||
{
|
||||
q_re = copysignl(INFINITY, y_re) * x_re;
|
||||
q_im = copysignl(INFINITY, y_re) * x_im;
|
||||
}
|
||||
// infinite / finite
|
||||
else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im))
|
||||
{
|
||||
x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re);
|
||||
x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im);
|
||||
q_re = INFINITY * (x_re * y_re + x_im * y_im);
|
||||
q_im = INFINITY * (x_im * y_re - x_re * y_im);
|
||||
}
|
||||
// finite / infinite
|
||||
else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im))
|
||||
{
|
||||
y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re);
|
||||
y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im);
|
||||
q_re = 0.0 * (x_re * y_re + x_im * y_im);
|
||||
q_im = 0.0 * (x_im * y_re - x_re * y_im);
|
||||
}
|
||||
}
|
||||
+/
|
||||
return q_re + q_im * 1.0i;
|
||||
}
|
||||
|
||||
/****************************
|
||||
* Compare two complex floating point numbers, x and y.
|
||||
* Input:
|
||||
* x.re ST3
|
||||
* x.im ST2
|
||||
* y.re ST1
|
||||
* y.im ST0
|
||||
* Output:
|
||||
* 8087 stack is cleared
|
||||
* flags set
|
||||
*/
|
||||
|
||||
void _Ccmp()
|
||||
{
|
||||
asm
|
||||
{ naked ;
|
||||
fucomp ST(2) ; // compare x.im and y.im
|
||||
fstsw AX ;
|
||||
sahf ;
|
||||
jne L1 ;
|
||||
jp L1 ; // jmp if NAN
|
||||
fucomp ST(2) ; // compare x.re and y.re
|
||||
fstsw AX ;
|
||||
sahf ;
|
||||
fstp ST(0) ; // pop
|
||||
fstp ST(0) ; // pop
|
||||
ret ;
|
||||
|
||||
L1:
|
||||
fstp ST(0) ; // pop
|
||||
fstp ST(0) ; // pop
|
||||
fstp ST(0) ; // pop
|
||||
ret ;
|
||||
}
|
||||
}
|
79
critical.c
79
critical.c
|
@ -1,7 +1,11 @@
|
|||
// Copyright (C) 2000 by Digital Mars
|
||||
// Copyright (C) 2000-2003 by Digital Mars, www.digitalmars.com
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
|
||||
/* ================================= Win32 ============================ */
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/******************************************
|
||||
|
@ -65,3 +69,76 @@ void _STD_critical_term()
|
|||
DeleteCriticalSection(&critical_section.cs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ================================= linux ============================ */
|
||||
|
||||
#if linux
|
||||
|
||||
#include <pthread.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;
|
||||
pthread_mutex_t 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)
|
||||
{
|
||||
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, 0);
|
||||
}
|
||||
pthread_mutex_unlock(&critical_section.cs);
|
||||
}
|
||||
pthread_mutex_lock(&dcs->cs);
|
||||
}
|
||||
|
||||
void _d_criticalexit(D_CRITICAL_SECTION *dcs)
|
||||
{
|
||||
pthread_mutex_unlock(&dcs->cs);
|
||||
}
|
||||
|
||||
void _STI_critical_init()
|
||||
{
|
||||
if (!inited)
|
||||
{ pthread_mutex_init(&critical_section.cs, 0);
|
||||
dcs_list = &critical_section;
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _STD_critical_term()
|
||||
{
|
||||
if (inited)
|
||||
{ inited = 0;
|
||||
while (dcs_list)
|
||||
{
|
||||
pthread_mutex_destroy(&dcs_list->cs);
|
||||
dcs_list = dcs_list->next;
|
||||
}
|
||||
pthread_mutex_destroy(&critical_section.cs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
17
date.d
17
date.d
|
@ -635,15 +635,14 @@ version (Win32)
|
|||
version (linux)
|
||||
{
|
||||
|
||||
import c.time;
|
||||
import c.sys.time;
|
||||
import linux;
|
||||
|
||||
d_time getUTCtime()
|
||||
{ timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
if (gettimeofday(&tv, null))
|
||||
{ // Some error happened - try time() instead
|
||||
return c.time.time(null) * TicksPerSecond;
|
||||
return time(null) * TicksPerSecond;
|
||||
}
|
||||
|
||||
return tv.tv_sec * TicksPerSecond + (tv.tv_usec / (1000000 / TicksPerSecond));
|
||||
|
@ -651,9 +650,9 @@ version (linux)
|
|||
|
||||
d_time getLocalTZA()
|
||||
{
|
||||
time_t t;
|
||||
int t;
|
||||
|
||||
c.time.time(&t);
|
||||
time(&t);
|
||||
localtime(&t); // this will set timezone
|
||||
return -(timezone * TicksPerSecond);
|
||||
}
|
||||
|
@ -664,10 +663,10 @@ version (linux)
|
|||
|
||||
int DaylightSavingTA(d_time dt)
|
||||
{
|
||||
struct tm *tmp;
|
||||
time_t t;
|
||||
tm *tmp;
|
||||
int t;
|
||||
|
||||
t = (time_t) (dt / TicksPerSecond); // BUG: need range check
|
||||
t = (int) (dt / TicksPerSecond); // BUG: need range check
|
||||
tmp = localtime(&t);
|
||||
if (tmp.tm_isdst > 0)
|
||||
// BUG: Assume daylight savings time is plus one hour.
|
||||
|
|
14
dateparse.d
14
dateparse.d
|
@ -24,7 +24,10 @@ struct DateParse
|
|||
{
|
||||
*this = DateParse.init;
|
||||
|
||||
buffer = ((char *)alloca(s.length))[0 .. s.length];
|
||||
//version (Win32)
|
||||
buffer = ((char *)alloca(s.length))[0 .. s.length];
|
||||
//else
|
||||
//buffer = new char[s.length];
|
||||
|
||||
debug(log) printf("DateParse.parse('%.*s')\n", s);
|
||||
if (!parseString(s))
|
||||
|
@ -132,13 +135,15 @@ private:
|
|||
int bi;
|
||||
DP result = DP.err;
|
||||
|
||||
//message(DTEXT("DateParse::nextToken()\n"));
|
||||
//printf("DateParse::nextToken()\n");
|
||||
for (;;)
|
||||
{
|
||||
//message(DTEXT("\t*p = '%c'\n"), *p);
|
||||
assert(si <= s.length);
|
||||
if (si == s.length)
|
||||
return DP.end;
|
||||
{ result = DP.end;
|
||||
goto Lret;
|
||||
}
|
||||
//printf("\ts[%d] = '%c'\n", si, s[si]);
|
||||
switch (s[si])
|
||||
{
|
||||
case ':': result = DP.colon; goto ret_inc;
|
||||
|
@ -233,6 +238,7 @@ private:
|
|||
}
|
||||
}
|
||||
Lret:
|
||||
//printf("-DateParse::nextToken()\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
257
deh.c
257
deh.c
|
@ -1,9 +1,19 @@
|
|||
//
|
||||
// Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
|
||||
// Exception handling support
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ======================== Win32 =============================== */
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#include <excpt.h>
|
||||
#include <windows.h>
|
||||
|
||||
|
@ -393,4 +403,251 @@ void _d_monitor_epilog(void *x, void *y, Object *h)
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ======================== linux =============================== */
|
||||
|
||||
#if linux
|
||||
|
||||
#include "mars.h"
|
||||
|
||||
extern ClassInfo _Class_Exception;
|
||||
|
||||
typedef int (*fp_t)(); // function pointer in ambient memory model
|
||||
|
||||
struct DHandlerInfo
|
||||
{
|
||||
unsigned offset; // offset from function address to start of guarded section
|
||||
int prev_index; // previous table index
|
||||
unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
|
||||
void *finally_code; // pointer to finally code to execute
|
||||
// (!=0 if try-finally)
|
||||
};
|
||||
|
||||
// Address of DHandlerTable, searched for by eh_finddata()
|
||||
|
||||
struct DHandlerTable
|
||||
{
|
||||
void *fptr; // pointer to start of function
|
||||
unsigned espoffset; // offset of ESP from EBP
|
||||
unsigned retoffset; // offset from start of function to return code
|
||||
unsigned nhandlers; // dimension of handler_info[]
|
||||
struct DHandlerInfo handler_info[1];
|
||||
};
|
||||
|
||||
struct DCatchBlock
|
||||
{
|
||||
ClassInfo *type; // catch type
|
||||
unsigned bpoffset; // EBP offset of catch var
|
||||
void *code; // catch handler code
|
||||
};
|
||||
|
||||
// Create one of these for each try-catch
|
||||
struct DCatchInfo
|
||||
{
|
||||
unsigned ncatches; // number of catch blocks
|
||||
struct DCatchBlock catch_block[1]; // data for each catch block
|
||||
};
|
||||
|
||||
// One of these is generated for each function with try-catch or try-finally
|
||||
|
||||
struct FuncTable
|
||||
{
|
||||
void *fptr; // pointer to start of function
|
||||
struct DHandlerTable *handlertable; // eh data for this function
|
||||
unsigned size; // size of function in bytes
|
||||
};
|
||||
|
||||
extern struct FuncTable *table_start;
|
||||
extern struct FuncTable *table_end;
|
||||
|
||||
void terminate()
|
||||
{
|
||||
// _asm
|
||||
// {
|
||||
// hlt
|
||||
// }
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
* Given address that is inside a function,
|
||||
* figure out which function it is in.
|
||||
* Return DHandlerTable if there is one, NULL if not.
|
||||
*/
|
||||
|
||||
struct DHandlerTable *__eh_finddata(void *address)
|
||||
{
|
||||
struct FuncTable *ft;
|
||||
|
||||
for (ft = (struct FuncTable *)table_start;
|
||||
ft < (struct FuncTable *)table_end;
|
||||
ft++)
|
||||
{
|
||||
if (ft->fptr <= address &&
|
||||
address < (void *)((char *)ft->fptr + ft->size))
|
||||
{
|
||||
return ft->handlertable;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
* Given EBP, find return address to caller, and caller's EBP.
|
||||
* Input:
|
||||
* regbp Value of EBP for current function
|
||||
* *pretaddr Return address
|
||||
* Output:
|
||||
* *pretaddr return address to caller
|
||||
* Returns:
|
||||
* caller's EBP
|
||||
*/
|
||||
|
||||
unsigned __eh_find_caller(unsigned regbp, unsigned *pretaddr)
|
||||
{
|
||||
unsigned bp = *(unsigned *)regbp;
|
||||
|
||||
if (bp) // if not end of call chain
|
||||
{
|
||||
// Perform sanity checks on new EBP.
|
||||
// If it is screwed up, terminate() hopefully before we do more damage.
|
||||
if (bp <= regbp)
|
||||
// stack should grow to smaller values
|
||||
terminate();
|
||||
|
||||
*pretaddr = *(unsigned *)(regbp + sizeof(int));
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Throw a D object.
|
||||
*/
|
||||
|
||||
void __stdcall _d_throw(Object *h)
|
||||
{
|
||||
unsigned regebp;
|
||||
|
||||
//printf("_d_throw(h = %p, &h = %p)\n", h, &h);
|
||||
//printf("\tvptr = %p\n", *(void **)h);
|
||||
|
||||
regebp = _EBP;
|
||||
|
||||
while (1) // for each function on the stack
|
||||
{
|
||||
struct DHandlerTable *handler_table;
|
||||
struct FuncTable *pfunc;
|
||||
struct DHandlerInfo *phi;
|
||||
unsigned retaddr;
|
||||
unsigned funcoffset;
|
||||
unsigned spoff;
|
||||
unsigned retoffset;
|
||||
int index;
|
||||
int dim;
|
||||
int ndx;
|
||||
int prev_ndx;
|
||||
|
||||
regebp = __eh_find_caller(regebp,&retaddr);
|
||||
if (!regebp)
|
||||
// if end of call chain
|
||||
break;
|
||||
|
||||
handler_table = __eh_finddata((void *)retaddr); // find static data associated with function
|
||||
if (!handler_table) // if no static data
|
||||
{
|
||||
continue;
|
||||
}
|
||||
funcoffset = (unsigned)handler_table->fptr;
|
||||
spoff = handler_table->espoffset;
|
||||
retoffset = handler_table->retoffset;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("retaddr = x%x\n",(unsigned)retaddr);
|
||||
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
|
||||
regebp,funcoffset,spoff,retoffset);
|
||||
#endif
|
||||
|
||||
// Find start index for retaddr in static data
|
||||
dim = handler_table->nhandlers;
|
||||
index = -1;
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
phi = &handler_table->handler_info[i];
|
||||
|
||||
if ((unsigned)retaddr >= funcoffset + phi->offset)
|
||||
index = i;
|
||||
}
|
||||
|
||||
// walk through handler table, checking each handler
|
||||
// with an index smaller than the current table_index
|
||||
for (ndx = index; ndx != -1; ndx = prev_ndx)
|
||||
{
|
||||
phi = &handler_table->handler_info[ndx];
|
||||
prev_ndx = phi->prev_index;
|
||||
if (phi->cioffset)
|
||||
{
|
||||
// this is a catch handler (no finally)
|
||||
struct DCatchInfo *pci;
|
||||
int ncatches;
|
||||
int i;
|
||||
|
||||
pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
|
||||
ncatches = pci->ncatches;
|
||||
for (i = 0; i < ncatches; i++)
|
||||
{
|
||||
struct DCatchBlock *pcb;
|
||||
ClassInfo *ci = **(ClassInfo ***)h;
|
||||
|
||||
pcb = &pci->catch_block[i];
|
||||
|
||||
if (_d_isbaseof(ci, pcb->type))
|
||||
{ // Matched the catch type, so we've found the handler.
|
||||
|
||||
// Initialize catch variable
|
||||
*(void **)(regebp + (pcb->bpoffset)) = h;
|
||||
|
||||
// Jump to catch block. Does not return.
|
||||
{
|
||||
unsigned catch_esp;
|
||||
fp_t catch_addr;
|
||||
|
||||
catch_addr = (fp_t)(pcb->code);
|
||||
catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
|
||||
_asm
|
||||
{
|
||||
mov EAX,catch_esp
|
||||
mov ECX,catch_addr
|
||||
mov [EAX],ECX
|
||||
mov EBP,regebp
|
||||
mov ESP,EAX // reset stack
|
||||
ret // jump to catch block
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (phi->finally_code)
|
||||
{ // Call finally block
|
||||
// Note that it is unnecessary to adjust the ESP, as the finally block
|
||||
// accesses all items on the stack as relative to EBP.
|
||||
|
||||
void *blockaddr = phi->finally_code;
|
||||
|
||||
_asm
|
||||
{
|
||||
push EBX
|
||||
mov EBX,blockaddr
|
||||
push EBP
|
||||
mov EBP,regebp
|
||||
call EBX
|
||||
pop EBP
|
||||
pop EBX
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
31
dmain2.d
31
dmain2.d
|
@ -4,10 +4,15 @@ import c.stdio;
|
|||
import c.stdlib;
|
||||
import string;
|
||||
|
||||
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 gc_init();
|
||||
extern (C) void gc_term();
|
||||
extern (C) void _minit();
|
||||
extern (C) void _moduleCtor();
|
||||
extern (C) void _moduleDtor();
|
||||
extern (C) void _moduleUnitTests();
|
||||
|
||||
/***********************************
|
||||
|
@ -16,7 +21,7 @@ extern (C) void _moduleUnitTests();
|
|||
int main(char[][] args);
|
||||
|
||||
/***********************************
|
||||
* Called by the C main() function in main.c.
|
||||
* Substitutes for the C main() function.
|
||||
* It's purpose is to wrap the call to the D main()
|
||||
* function and catch any unhandled exceptions.
|
||||
*/
|
||||
|
@ -28,9 +33,20 @@ extern (C) int main(int argc, char **argv)
|
|||
int i;
|
||||
int result;
|
||||
|
||||
gc_init();
|
||||
_minit();
|
||||
am = (char[] *) alloca(argc * (char[]).size);
|
||||
version (linux)
|
||||
{
|
||||
_STI_monitor_staticctor();
|
||||
_STI_critical_init();
|
||||
gc_init();
|
||||
//am = (char[] *) malloc(argc * (char[]).size);
|
||||
am = (char[] *) alloca(argc * (char[]).size);
|
||||
}
|
||||
version (Win32)
|
||||
{
|
||||
gc_init();
|
||||
_minit();
|
||||
am = (char[] *) alloca(argc * (char[]).size);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -55,7 +71,14 @@ extern (C) int main(int argc, char **argv)
|
|||
result = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
_moduleDtor();
|
||||
gc_term();
|
||||
version (linux)
|
||||
{
|
||||
//free(am);
|
||||
_STD_critical_term();
|
||||
_STD_monitor_staticdtor();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
217
file.d
217
file.d
|
@ -36,6 +36,11 @@ class FileError : Error
|
|||
* Basic File operations.
|
||||
*/
|
||||
|
||||
/* =========================== Win32 ======================= */
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
|
||||
import windows;
|
||||
|
||||
/********************************************
|
||||
|
@ -208,3 +213,215 @@ uint getAttributes(char[] name)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* =========================== linux ======================= */
|
||||
|
||||
version (linux)
|
||||
{
|
||||
|
||||
import linux;
|
||||
|
||||
/********************************************
|
||||
* Read a file.
|
||||
* Returns:
|
||||
* array of bytes read
|
||||
*/
|
||||
|
||||
byte[] read(char[] name)
|
||||
{
|
||||
uint size;
|
||||
uint numread;
|
||||
int fd;
|
||||
stat statbuf;
|
||||
byte[] buf;
|
||||
char *namez;
|
||||
|
||||
namez = toStringz(name);
|
||||
//printf("file.read('%s')\n",namez);
|
||||
fd = linux.open(namez, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
//printf("\topen error, errno = %d\n",getErrno());
|
||||
goto err1;
|
||||
}
|
||||
|
||||
//printf("\tfile opened\n");
|
||||
if (linux.fstat(fd, &statbuf))
|
||||
{
|
||||
//printf("\tfstat error, errno = %d\n",getErrno());
|
||||
goto err2;
|
||||
}
|
||||
size = statbuf.st_size;
|
||||
buf = new byte[size];
|
||||
|
||||
numread = linux.read(fd, (char*)buf, size);
|
||||
if (numread != size)
|
||||
{
|
||||
//printf("\tread error, errno = %d\n",getErrno());
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (linux.close(fd) == -1)
|
||||
{
|
||||
//printf("\tclose error, errno = %d\n",getErrno());
|
||||
goto err;
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
err2:
|
||||
linux.close(fd);
|
||||
err:
|
||||
delete buf;
|
||||
|
||||
err1:
|
||||
throw new FileError(name, getErrno());
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Write a file.
|
||||
* Returns:
|
||||
* 0 success
|
||||
*/
|
||||
|
||||
void write(char[] name, byte[] buffer)
|
||||
{
|
||||
int fd;
|
||||
int numwritten;
|
||||
int len;
|
||||
char *namez;
|
||||
|
||||
namez = toStringz(name);
|
||||
fd = linux.open(namez, O_CREAT | O_WRONLY | O_TRUNC, 0660);
|
||||
if (fd == -1)
|
||||
goto err;
|
||||
|
||||
numwritten = linux.write(fd, buffer, len);
|
||||
if (len != numwritten)
|
||||
goto err2;
|
||||
|
||||
if (linux.close(fd) == -1)
|
||||
goto err;
|
||||
|
||||
return;
|
||||
|
||||
err2:
|
||||
linux.close(fd);
|
||||
err:
|
||||
throw new FileError(name, getErrno());
|
||||
}
|
||||
|
||||
|
||||
/*********************************************
|
||||
* Append to a file.
|
||||
*/
|
||||
|
||||
void append(char[] name, byte[] buffer)
|
||||
{
|
||||
int fd;
|
||||
int numwritten;
|
||||
int len;
|
||||
char *namez;
|
||||
|
||||
namez = toStringz(name);
|
||||
fd = linux.open(namez, O_APPEND | O_WRONLY | O_CREAT, 0660);
|
||||
if (fd == -1)
|
||||
goto err;
|
||||
|
||||
numwritten = linux.write(fd, buffer, len);
|
||||
if (len != numwritten)
|
||||
goto err2;
|
||||
|
||||
if (linux.close(fd) == -1)
|
||||
goto err;
|
||||
|
||||
return;
|
||||
|
||||
err2:
|
||||
linux.close(fd);
|
||||
err:
|
||||
throw new FileError(name, getErrno());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************
|
||||
* Rename a file.
|
||||
*/
|
||||
|
||||
void rename(char[] from, char[] to)
|
||||
{
|
||||
char *fromz = toStringz(from);
|
||||
char *toz = toStringz(to);
|
||||
|
||||
if (c.stdio.rename(fromz, toz) == -1)
|
||||
throw new FileError(to, getErrno());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************
|
||||
* Delete a file.
|
||||
*/
|
||||
|
||||
void remove(char[] name)
|
||||
{
|
||||
if (c.stdio.remove(toStringz(name)) == -1)
|
||||
throw new FileError(name, getErrno());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************
|
||||
* Get file size.
|
||||
*/
|
||||
|
||||
uint getSize(char[] name)
|
||||
{
|
||||
uint size;
|
||||
int fd;
|
||||
stat statbuf;
|
||||
char *namez;
|
||||
|
||||
namez = toStringz(name);
|
||||
//printf("file.getSize('%s')\n",namez);
|
||||
fd = linux.open(namez, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
//printf("\topen error, errno = %d\n",getErrno());
|
||||
goto err1;
|
||||
}
|
||||
|
||||
//printf("\tfile opened\n");
|
||||
if (linux.fstat(fd, &statbuf))
|
||||
{
|
||||
//printf("\tfstat error, errno = %d\n",getErrno());
|
||||
goto err2;
|
||||
}
|
||||
size = statbuf.st_size;
|
||||
|
||||
if (linux.close(fd) == -1)
|
||||
{
|
||||
//printf("\tclose error, errno = %d\n",getErrno());
|
||||
goto err;
|
||||
}
|
||||
|
||||
return size;
|
||||
|
||||
err2:
|
||||
linux.close(fd);
|
||||
err:
|
||||
err1:
|
||||
throw new FileError(name, getErrno());
|
||||
}
|
||||
|
||||
|
||||
/***************************************************
|
||||
* Get file attributes.
|
||||
*/
|
||||
|
||||
uint getAttributes(char[] name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
89
gc2/gclinux.d
Normal file
89
gc2/gclinux.d
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
// Copyright (C) 2001-2003 by Digital Mars, www.digitalmars.com
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
|
||||
import linuxextern;
|
||||
|
||||
extern (C)
|
||||
{
|
||||
// from <sys/mman.h>
|
||||
void* mmap(void* addr, uint len, int prot, int flags, int fd, uint offset);
|
||||
int munmap(void* addr, uint len);
|
||||
const void* MAP_FAILED = (void*)-1;
|
||||
|
||||
// from <bits/mman.h>
|
||||
enum { PROT_NONE = 0, PROT_READ = 1, PROT_WRITE = 2, PROT_EXEC = 4 }
|
||||
enum { MAP_SHARED = 1, MAP_PRIVATE = 2, MAP_TYPE = 0x0F,
|
||||
MAP_FIXED = 0x10, MAP_FILE = 0, MAP_ANON = 0x20 }
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Map memory.
|
||||
*/
|
||||
|
||||
void *os_mem_map(uint nbytes)
|
||||
{ void *p;
|
||||
|
||||
//errno = 0;
|
||||
p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
return (p == MAP_FAILED) ? null : p;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Commit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_commit(void *base, uint offset, uint nbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Decommit memory.
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_decommit(void *base, uint offset, uint nbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* Unmap memory allocated with os_mem_map().
|
||||
* Returns:
|
||||
* 0 success
|
||||
* !=0 failure
|
||||
*/
|
||||
|
||||
int os_mem_unmap(void *base, uint nbytes)
|
||||
{
|
||||
return munmap(base, nbytes);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* Determine "bottom" of stack (actually the top on x86 systems).
|
||||
*/
|
||||
|
||||
void *os_query_stackBottom()
|
||||
{
|
||||
return __libc_stack_end;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* Determine base address and size of static data segment.
|
||||
*/
|
||||
|
||||
void os_query_staticdataseg(void **base, uint *nbytes)
|
||||
{
|
||||
*base = (void *)&__data_start;
|
||||
*nbytes = &_end - &__data_start;
|
||||
}
|
68
gc2/gcx.d
68
gc2/gcx.d
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (C) 2001-2002 by Digital Mars
|
||||
// Copyright (C) 2001-2003 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
|
@ -31,11 +31,21 @@ debug (PRINTF) import c.stdio;
|
|||
|
||||
import c.stdlib;
|
||||
import gcbits;
|
||||
import win32;
|
||||
import outofmemory;
|
||||
import gc;
|
||||
import gcstats;
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
import win32;
|
||||
}
|
||||
|
||||
version (linux)
|
||||
{
|
||||
import gclinux;
|
||||
}
|
||||
|
||||
|
||||
version (MULTI_THREADED)
|
||||
{
|
||||
import thread;
|
||||
|
@ -158,7 +168,14 @@ struct GC
|
|||
gcLock = GCLock.classinfo;
|
||||
gcx = (Gcx *)c.stdlib.calloc(1, Gcx.size);
|
||||
gcx.init();
|
||||
setStackBottom(win32.os_query_stackBottom());
|
||||
version (Win32)
|
||||
{
|
||||
setStackBottom(win32.os_query_stackBottom());
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
setStackBottom(gclinux.os_query_stackBottom());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -488,9 +505,11 @@ struct GC
|
|||
void *ptop;
|
||||
uint nbytes;
|
||||
|
||||
//debug(PRINTF) printf("+GC.scanStaticData()\n");
|
||||
os_query_staticdataseg(&pbot, &nbytes);
|
||||
ptop = pbot + nbytes;
|
||||
addRange(pbot, ptop);
|
||||
//debug(PRINTF) printf("-GC.scanStaticData()\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -512,10 +531,12 @@ struct GC
|
|||
|
||||
void addRange(void *pbot, void *ptop) // add range to scan for roots
|
||||
{
|
||||
//debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop);
|
||||
synchronized (gcLock)
|
||||
{
|
||||
gcx.addRange(pbot, ptop);
|
||||
}
|
||||
//debug(PRINTF) printf("-GC.addRange()\n");
|
||||
}
|
||||
|
||||
void removeRange(void *pbot) // remove range
|
||||
|
@ -874,8 +895,8 @@ struct Gcx
|
|||
|
||||
void addRange(void *pbot, void *ptop)
|
||||
{
|
||||
//debug(PRINTF) printf("Thread %x ", pthread_self());
|
||||
//debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
|
||||
debug(PRINTF) printf("Thread %x ", pthread_self());
|
||||
debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
|
||||
if (nranges == rangedim)
|
||||
{
|
||||
uint newdim = rangedim * 2 + 16;
|
||||
|
@ -898,8 +919,8 @@ struct Gcx
|
|||
|
||||
void removeRange(void *pbot)
|
||||
{
|
||||
//debug(PRINTF) printf("Thread %x ", pthread_self());
|
||||
//debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
|
||||
debug(PRINTF) printf("Thread %x ", pthread_self());
|
||||
debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
|
||||
for (uint i = nranges; i--;)
|
||||
{
|
||||
if (ranges[i].pbot == pbot)
|
||||
|
@ -909,7 +930,7 @@ struct Gcx
|
|||
return;
|
||||
}
|
||||
}
|
||||
//debug(PRINTF) printf("Wrong thread\n");
|
||||
debug(PRINTF) printf("Wrong thread\n");
|
||||
|
||||
// This is a fatal error, but ignore it.
|
||||
// The problem is that we can get a Close() call on a thread
|
||||
|
@ -1353,19 +1374,34 @@ struct Gcx
|
|||
|
||||
if (t && t.getState() == Thread.TS.RUNNING)
|
||||
{
|
||||
CONTEXT context;
|
||||
|
||||
if (noStack && threads.length == 1)
|
||||
break;
|
||||
|
||||
context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
|
||||
if (!GetThreadContext(t.hdl, &context))
|
||||
version (Win32)
|
||||
{
|
||||
assert(0);
|
||||
CONTEXT context;
|
||||
|
||||
context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
|
||||
if (!GetThreadContext(t.hdl, &context))
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
debug (PRINTF) printf("mt scan stack bot = %x, top = %x\n", context.Esp, t.stackBottom);
|
||||
mark((void *)context.Esp, t.stackBottom);
|
||||
mark(&context.Edi, &context.Eip);
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
// The registers are already stored in the stack
|
||||
//printf("foo x%x, x%x, isSelf = %d\n", Thread.getESP(), t.stackBottom, t.isSelf());
|
||||
if (t.isSelf())
|
||||
t.stackTop = Thread.getESP();
|
||||
|
||||
version (STACKGROWSDOWN)
|
||||
mark(t.stackTop, t.stackBottom);
|
||||
else
|
||||
mark(t.stackBottom, t.stackTop);
|
||||
}
|
||||
debug (PRINTF) printf("mt scan stack bot = %x, top = %x\n", context.Esp, t.stackBottom);
|
||||
mark((void *)context.Esp, t.stackBottom);
|
||||
mark(&context.Edi, &context.Eip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
gc2/linux.mak
Normal file
50
gc2/linux.mak
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
# makefile to build linux D garbage collector
|
||||
|
||||
DMD=../../dmd
|
||||
#DMD=/dmd/bin/dmd
|
||||
CFLAGS=-g
|
||||
#DFLAGS=-unittest -g -release
|
||||
DFLAGS=-release -O -inline -I..
|
||||
#DFLAGS=-release -inline -O
|
||||
CC=gcc
|
||||
|
||||
OBJS= gc.o gcx.o gcbits.o gclinux.o
|
||||
|
||||
SRC= gc.d gcx.d gcbits.d win32.d gclinux.d testgc.d win32.mak linux.mak
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $*
|
||||
|
||||
.d.o:
|
||||
$(DMD) -c $(DFLAGS) $*
|
||||
|
||||
targets : testgc dmgc.a
|
||||
|
||||
testgc : testgc.o $(OBJS) linux.mak ../phobos.a
|
||||
$(CC) -o $@ testgc.o $(OBJS) ../phobos.a -lpthread -lm -g -Xlinker -M
|
||||
|
||||
testgc.o : testgc.d
|
||||
$(DMD) -c $(DFLAGS) testgc.d
|
||||
|
||||
dmgc.a : $(OBJS) linux.mak
|
||||
ar -r $@ $(OBJS)
|
||||
|
||||
gc.o : gc.d
|
||||
$(DMD) -c $(DFLAGS) gc.d
|
||||
|
||||
gcx.o : gcx.d
|
||||
$(DMD) -c $(DFLAGS) gcx.d
|
||||
|
||||
gcbits.o : gcbits.d
|
||||
$(DMD) -c $(DFLAGS) gcbits.d
|
||||
|
||||
gclinux.o : gclinux.d
|
||||
$(DMD) -c $(DFLAGS) gclinux.d
|
||||
|
||||
zip : $(SRC)
|
||||
rm dmgc.zip
|
||||
zip dmgc $(SRC)
|
||||
|
||||
clean:
|
||||
rm $(OBJS) dmgc.a testgc
|
16
gc2/testgc.d
16
gc2/testgc.d
|
@ -1,5 +1,5 @@
|
|||
|
||||
// Copyright (C) 2001-2002 by Digital Mars
|
||||
// Copyright (C) 2001-2003 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
|
@ -68,10 +68,12 @@ void smoke()
|
|||
|
||||
gc = newGC();
|
||||
deleteGC(gc);
|
||||
printf("smoke.1\n");
|
||||
|
||||
gc = newGC();
|
||||
gc.init();
|
||||
deleteGC(gc);
|
||||
printf("smoke.2\n");
|
||||
|
||||
gc = newGC();
|
||||
gc.init();
|
||||
|
@ -157,11 +159,11 @@ void smoke3()
|
|||
// for (i = 0; i < 1000000; i++)
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
uint size = rand() % 2048;
|
||||
uint size = random.rand() % 2048;
|
||||
p = (int *)gc.malloc(size);
|
||||
memset(p, i, size);
|
||||
|
||||
size = rand() % 2048;
|
||||
size = random.rand() % 2048;
|
||||
p = (int *)gc.realloc(p, size);
|
||||
memset(p, i + 1, size);
|
||||
}
|
||||
|
@ -193,7 +195,7 @@ void smoke4()
|
|||
p = (int *)gc.malloc(size);
|
||||
memset(p, i, size);
|
||||
|
||||
size = rand() % 2048;
|
||||
size = random.rand() % 2048;
|
||||
gc.check(p);
|
||||
p = (int *)gc.realloc(p, size);
|
||||
memset(p, i + 1, size);
|
||||
|
@ -226,8 +228,8 @@ void smoke5(GC *gc)
|
|||
{
|
||||
for (i = 0; i < 2000 /*4000*/; i++)
|
||||
{
|
||||
uint size = (rand() % 2048) + 1;
|
||||
uint index = rand() % SMOKE5_SIZE;
|
||||
uint size = (random.rand() % 2048) + 1;
|
||||
uint index = random.rand() % SMOKE5_SIZE;
|
||||
|
||||
//printf("index = %d, size = %d\n", index, size);
|
||||
p = array[index] - offset[index];
|
||||
|
@ -243,7 +245,7 @@ void smoke5(GC *gc)
|
|||
}
|
||||
array[index] = p;
|
||||
fill(p, index, size);
|
||||
offset[index] = rand() % size;
|
||||
offset[index] = random.rand() % size;
|
||||
array[index] += offset[index];
|
||||
|
||||
//printf("p[0] = %d\n", p[0]);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
# makefile to build D garbage collector under win32
|
||||
|
||||
DMD=..\..\dmd
|
||||
#DMD=\dmd\bin\dmd
|
||||
CFLAGS=-g -mn -6 -r -Igc
|
||||
|
@ -28,7 +30,7 @@ testgc.obj : testgc.d
|
|||
|
||||
OBJS= gc.obj gcx.obj gcbits.obj win32.obj
|
||||
|
||||
SRC= gc.d gcx.d gcbits.d win32.d testgc.d
|
||||
SRC= gc.d gcx.d gcbits.d win32.d gclinux.d testgc.d win32.mak linux.mak
|
||||
|
||||
dmgc.lib : $(OBJS) makefile
|
||||
del dmgc.lib
|
||||
|
@ -39,8 +41,9 @@ gcx.obj : gcx.d
|
|||
gcbits.obj : gcbits.d
|
||||
win32.obj : win32.d
|
||||
|
||||
zip : makefile $(SRC)
|
||||
zip32 -u dmgc makefile $(SRC)
|
||||
zip : $(SRC)
|
||||
del dmgc.zip
|
||||
zip32 dmgc $(SRC)
|
||||
|
||||
clean:
|
||||
del $(OBJS)
|
120
linux.d
Normal file
120
linux.d
Normal file
|
@ -0,0 +1,120 @@
|
|||
|
||||
import linuxextern;
|
||||
|
||||
enum : int
|
||||
{
|
||||
SIGHUP = 1,
|
||||
SIGINT = 2,
|
||||
SIGQUIT = 3,
|
||||
SIGILL = 4,
|
||||
SIGTRAP = 5,
|
||||
SIGABRT = 6,
|
||||
SIGIOT = 6,
|
||||
SIGBUS = 7,
|
||||
SIGFPE = 8,
|
||||
SIGKILL = 9,
|
||||
SIGUSR1 = 10,
|
||||
SIGSEGV = 11,
|
||||
SIGUSR2 = 12,
|
||||
SIGPIPE = 13,
|
||||
SIGALRM = 14,
|
||||
SIGTERM = 15,
|
||||
SIGSTKFLT = 16,
|
||||
SIGCHLD = 17,
|
||||
SIGCONT = 18,
|
||||
SIGSTOP = 19,
|
||||
SIGTSTP = 20,
|
||||
SIGTTIN = 21,
|
||||
SIGTTOU = 22,
|
||||
SIGURG = 23,
|
||||
SIGXCPU = 24,
|
||||
SIGXFSZ = 25,
|
||||
SIGVTALRM = 26,
|
||||
SIGPROF = 27,
|
||||
SIGWINCH = 28,
|
||||
SIGPOLL = 29,
|
||||
SIGIO = 29,
|
||||
SIGPWR = 30,
|
||||
SIGSYS = 31,
|
||||
SIGUNUSED = 31,
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
O_RDONLY = 0,
|
||||
O_WRONLY = 1,
|
||||
O_RDWR = 2,
|
||||
O_CREAT = 0100,
|
||||
O_EXCL = 0200,
|
||||
O_TRUNC = 01000,
|
||||
O_APPEND = 02000,
|
||||
}
|
||||
|
||||
struct stat
|
||||
{
|
||||
ulong st_dev;
|
||||
ushort __pad1;
|
||||
uint st_ino;
|
||||
uint st_mode;
|
||||
uint st_nlink;
|
||||
uint st_uid;
|
||||
uint st_gid;
|
||||
ulong st_rdev;
|
||||
ushort __pad2;
|
||||
int st_size;
|
||||
int st_blksize;
|
||||
int st_blocks;
|
||||
int st_atime;
|
||||
uint __unused1;
|
||||
int st_mtime;
|
||||
uint __unused2;
|
||||
int st_ctime;
|
||||
uint __unused3;
|
||||
uint __unused4;
|
||||
uint __unused5;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(stat.size == 88);
|
||||
}
|
||||
|
||||
|
||||
extern (C)
|
||||
{
|
||||
int open(char*, int, ...);
|
||||
int read(int, void*, int);
|
||||
int write(int, void*, int);
|
||||
int close(int);
|
||||
int lseek(int, int, int);
|
||||
int fstat(int, stat*);
|
||||
int getErrno();
|
||||
}
|
||||
|
||||
struct timeval
|
||||
{
|
||||
int tv_sec;
|
||||
int tv_usec;
|
||||
}
|
||||
|
||||
struct tm
|
||||
{
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
int tm_gmtoff;
|
||||
int tm_zone;
|
||||
}
|
||||
|
||||
extern (C)
|
||||
{
|
||||
int gettimeofday(timeval*, void*);
|
||||
int time(int*);
|
||||
tm *localtime(int*);
|
||||
}
|
305
linux.mak
Normal file
305
linux.mak
Normal file
|
@ -0,0 +1,305 @@
|
|||
# Makefile to build linux D runtime library libphobos.a.
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make unittest
|
||||
# make libphobos.a
|
||||
# Build libphobos.a
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
# make unittest
|
||||
# Build libphobos.a, build and run unit tests
|
||||
|
||||
CFLAGS=-O
|
||||
#CFLAGS=-g
|
||||
DFLAGS=-O -release
|
||||
#DFLAGS=-unittest
|
||||
|
||||
CC=gcc
|
||||
#DMD=/dmd/bin/dmd
|
||||
DMD=../dmd
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $*.cpp
|
||||
|
||||
.d.o:
|
||||
$(DMD) -c $(DFLAGS) $*.d
|
||||
|
||||
.asm.o:
|
||||
$(CC) -c $*.asm
|
||||
|
||||
targets : unittest
|
||||
|
||||
test.o : test.d
|
||||
$(DMD) -c test -g
|
||||
|
||||
test : test.o libphobos.a
|
||||
$(CC) -o $@ test.o libphobos.a -g
|
||||
|
||||
unittest : unittest.o libphobos.a
|
||||
$(CC) -o $@ unittest.o libphobos.a -lpthread -lm -g
|
||||
|
||||
unittest.o : unittest.d
|
||||
$(DMD) -c unittest
|
||||
|
||||
OBJS= assert.o deh2.o switch.o complex.o gcstats.o \
|
||||
critical.o object.o monitor.o arraycat.o invariant.o \
|
||||
dmain2.o outofmemory.o achar.o aaA.o adi.o file.o \
|
||||
compiler.o system.o moduleinit.o \
|
||||
cast.o syserror.o path.o string.o memset.o math.o \
|
||||
outbuffer.o ctype.o regexp.o random.o linux.o \
|
||||
stream.o switcherr.o array.o gc.o adi.o \
|
||||
qsort.o thread.o obj.o \
|
||||
crc32.o conv.o arraycast.o errno.o alloca.o cmath.o \
|
||||
ti_Aa.o ti_Ag.o ti_C.o ti_int.o ti_char.o \
|
||||
ti_wchar.o ti_uint.o ti_short.o ti_ushort.o \
|
||||
ti_byte.o ti_ubyte.o ti_long.o ti_ulong.o ti_ptr.o \
|
||||
ti_float.o ti_double.o ti_real.o ti_delegate.o \
|
||||
date.o dateparse.o llmath.o math2.o \
|
||||
ti_creal.o ti_ireal.o \
|
||||
ti_cfloat.o ti_ifloat.o \
|
||||
ti_cdouble.o ti_idouble.o
|
||||
|
||||
HDR=mars.h
|
||||
|
||||
SRC= mars.h switch.d complex.c critical.c minit.asm \
|
||||
deh.c object.d gc.d math.d c/stdio.d c/stdlib.d time.d monitor.c \
|
||||
arraycat.d string.d windows.d path.d linuxextern.d \
|
||||
invariant.d assert.d regexp.d dmain2.d dateparse.d \
|
||||
outofmemory.d syserror.d \
|
||||
ctype.d achar.d aaA.d adi.d file.d compiler.d system.d \
|
||||
moduleinit.d cast.d math.d qsort.d \
|
||||
outbuffer.d unittest.d stream.d ctype.d random.d adi.d \
|
||||
math2.d thread.d obj.d iunknown.d intrinsic.d time.d memset.d \
|
||||
array.d switcherr.d arraycast.d errno.c alloca.d cmath.d \
|
||||
ti_wchar.d ti_uint.d ti_short.d ti_ushort.d \
|
||||
ti_byte.d ti_ubyte.d ti_long.d ti_ulong.d ti_ptr.d \
|
||||
ti_float.d ti_double.d ti_real.d ti_delegate.d \
|
||||
ti_creal.d ti_ireal.d ti_cfloat.d ti_ifloat.d \
|
||||
ti_cdouble.d ti_idouble.d \
|
||||
ti_Aa.d ti_Ag.d ti_C.d ti_int.d ti_char.d \
|
||||
crc32.d stdint.d conv.d gcstats.d linux.d deh2.d date.d llmath.d \
|
||||
win32.mak linux.mak
|
||||
|
||||
libphobos.a : $(OBJS) gc2/dmgc.a linux.mak
|
||||
ar -r $@ $(OBJS) gc2/gc.o gc2/gcx.o gc2/gcbits.o gc2/gclinux.o
|
||||
|
||||
aaA.o : aaA.d
|
||||
$(DMD) -c $(DFLAGS) aaA.d
|
||||
|
||||
achar.o : achar.d
|
||||
$(DMD) -c $(DFLAGS) achar.d
|
||||
|
||||
adi.o : adi.d
|
||||
$(DMD) -c $(DFLAGS) adi.d
|
||||
|
||||
alloca.o : alloca.d
|
||||
$(DMD) -c $(DFLAGS) alloca.d
|
||||
|
||||
array.o : array.d
|
||||
$(DMD) -c $(DFLAGS) array.d
|
||||
|
||||
arraycast.o : arraycast.d
|
||||
$(DMD) -c $(DFLAGS) arraycast.d
|
||||
|
||||
arraycat.o : arraycat.d
|
||||
$(DMD) -c $(DFLAGS) arraycat.d
|
||||
|
||||
assert.o : assert.d
|
||||
$(DMD) -c $(DFLAGS) assert.d
|
||||
|
||||
cast.o : cast.d
|
||||
$(DMD) -c $(DFLAGS) cast.d
|
||||
|
||||
cmath.o : cmath.d
|
||||
$(DMD) -c $(DFLAGS) cmath.d
|
||||
|
||||
compiler.o : compiler.d
|
||||
$(DMD) -c $(DFLAGS) compiler.d
|
||||
|
||||
complex.o : mars.h complex.c
|
||||
|
||||
conv.o : conv.d
|
||||
$(DMD) -c $(DFLAGS) conv.d
|
||||
|
||||
crc32.o : crc32.d
|
||||
$(DMD) -c $(DFLAGS) crc32.d
|
||||
|
||||
critical.o : mars.h critical.c
|
||||
|
||||
ctype.o : ctype.d
|
||||
$(DMD) -c $(DFLAGS) ctype.d
|
||||
|
||||
dassert.o : mars.h dassert.c
|
||||
|
||||
date.o : dateparse.d date.d
|
||||
$(DMD) -c $(DFLAGS) date.d
|
||||
|
||||
dateparse.o : dateparse.d date.d
|
||||
$(DMD) -c $(DFLAGS) dateparse.d
|
||||
|
||||
deh2.o : deh2.d
|
||||
$(DMD) -c $(DFLAGS) deh2.d
|
||||
|
||||
dmain2.o : dmain2.d
|
||||
$(DMD) -c $(DFLAGS) dmain2.d
|
||||
|
||||
errno.o : errno.c
|
||||
|
||||
file.o : file.d
|
||||
$(DMD) -c $(DFLAGS) file.d
|
||||
|
||||
gc.o : gc.d
|
||||
$(DMD) -c $(DFLAGS) gc.d
|
||||
|
||||
gcstats.o : gcstats.d
|
||||
$(DMD) -c $(DFLAGS) gcstats.d
|
||||
|
||||
invariant.o : invariant.d
|
||||
$(DMD) -c $(DFLAGS) invariant.d
|
||||
|
||||
linux.o : linux.d
|
||||
$(DMD) -c $(DFLAGS) linux.d
|
||||
|
||||
llmath.o : llmath.d
|
||||
$(DMD) -c $(DFLAGS) llmath.d
|
||||
|
||||
math.o : math.d
|
||||
$(DMD) -c $(DFLAGS) math.d
|
||||
|
||||
math2.o : math2.d
|
||||
$(DMD) -c $(DFLAGS) math2.d
|
||||
|
||||
memset.o : memset.d
|
||||
$(DMD) -c $(DFLAGS) memset.d
|
||||
|
||||
moduleinit.o : moduleinit.d
|
||||
$(DMD) -c $(DFLAGS) moduleinit.d
|
||||
|
||||
monitor.o : mars.h monitor.c
|
||||
|
||||
obj.o : obj.d
|
||||
$(DMD) -c $(DFLAGS) obj.d
|
||||
|
||||
object.o : object.d
|
||||
$(DMD) -c $(DFLAGS) object.d
|
||||
|
||||
outbuffer.o : outbuffer.d
|
||||
$(DMD) -c $(DFLAGS) outbuffer.d
|
||||
|
||||
outofmemory.o : outofmemory.d
|
||||
$(DMD) -c $(DFLAGS) outofmemory.d
|
||||
|
||||
path.o : path.d
|
||||
$(DMD) -c $(DFLAGS) path.d
|
||||
|
||||
qsort.o : qsort.d
|
||||
$(DMD) -c $(DFLAGS) qsort.d
|
||||
|
||||
random.o : random.d
|
||||
$(DMD) -c $(DFLAGS) random.d
|
||||
|
||||
regexp.o : regexp.d
|
||||
$(DMD) -c $(DFLAGS) regexp.d
|
||||
|
||||
stream.o : stream.d
|
||||
$(DMD) -c $(DFLAGS) stream.d
|
||||
|
||||
string.o : string.d
|
||||
$(DMD) -c $(DFLAGS) string.d
|
||||
|
||||
switch.o : switch.d
|
||||
$(DMD) -c $(DFLAGS) switch.d
|
||||
|
||||
switcherr.o : switcherr.d
|
||||
$(DMD) -c $(DFLAGS) switcherr.d
|
||||
|
||||
syserror.o : syserror.d
|
||||
$(DMD) -c $(DFLAGS) syserror.d
|
||||
|
||||
system.o : system.d
|
||||
$(DMD) -c $(DFLAGS) system.d
|
||||
|
||||
thread.o : thread.d
|
||||
$(DMD) -c $(DFLAGS) thread.d
|
||||
|
||||
ti_wchar.o : ti_wchar.d
|
||||
$(DMD) -c $(DFLAGS) ti_wchar.d
|
||||
|
||||
ti_uint.o : ti_uint.d
|
||||
$(DMD) -c $(DFLAGS) ti_uint.d
|
||||
|
||||
ti_short.o : ti_short.d
|
||||
$(DMD) -c $(DFLAGS) ti_short.d
|
||||
|
||||
ti_ushort.o : ti_ushort.d
|
||||
$(DMD) -c $(DFLAGS) ti_ushort.d
|
||||
|
||||
ti_byte.o : ti_byte.d
|
||||
$(DMD) -c $(DFLAGS) ti_byte.d
|
||||
|
||||
ti_ubyte.o : ti_ubyte.d
|
||||
$(DMD) -c $(DFLAGS) ti_ubyte.d
|
||||
|
||||
ti_long.o : ti_long.d
|
||||
$(DMD) -c $(DFLAGS) ti_long.d
|
||||
|
||||
ti_ulong.o : ti_ulong.d
|
||||
$(DMD) -c $(DFLAGS) ti_ulong.d
|
||||
|
||||
ti_ptr.o : ti_ptr.d
|
||||
$(DMD) -c $(DFLAGS) ti_ptr.d
|
||||
|
||||
ti_float.o : ti_float.d
|
||||
$(DMD) -c $(DFLAGS) ti_float.d
|
||||
|
||||
ti_double.o : ti_double.d
|
||||
$(DMD) -c $(DFLAGS) ti_double.d
|
||||
|
||||
ti_real.o : ti_real.d
|
||||
$(DMD) -c $(DFLAGS) ti_real.d
|
||||
|
||||
ti_delegate.o : ti_delegate.d
|
||||
$(DMD) -c $(DFLAGS) ti_delegate.d
|
||||
|
||||
ti_creal.o : ti_creal.d
|
||||
$(DMD) -c $(DFLAGS) ti_creal.d
|
||||
|
||||
ti_ireal.o : ti_ireal.d
|
||||
$(DMD) -c $(DFLAGS) ti_ireal.d
|
||||
|
||||
ti_cfloat.o : ti_cfloat.d
|
||||
$(DMD) -c $(DFLAGS) ti_cfloat.d
|
||||
|
||||
ti_ifloat.o : ti_ifloat.d
|
||||
$(DMD) -c $(DFLAGS) ti_ifloat.d
|
||||
|
||||
ti_cdouble.o : ti_cdouble.d
|
||||
$(DMD) -c $(DFLAGS) ti_cdouble.d
|
||||
|
||||
ti_idouble.o : ti_idouble.d
|
||||
$(DMD) -c $(DFLAGS) ti_idouble.d
|
||||
|
||||
ti_Aa.o : ti_Aa.d
|
||||
$(DMD) -c $(DFLAGS) ti_Aa.d
|
||||
|
||||
ti_Ag.o : ti_Ag.d
|
||||
$(DMD) -c $(DFLAGS) ti_Ag.d
|
||||
|
||||
ti_C.o : ti_C.d
|
||||
$(DMD) -c $(DFLAGS) ti_C.d
|
||||
|
||||
ti_char.o : ti_char.d
|
||||
$(DMD) -c $(DFLAGS) ti_char.d
|
||||
|
||||
ti_int.o : ti_int.d
|
||||
$(DMD) -c $(DFLAGS) ti_int.d
|
||||
|
||||
zip : $(SRC)
|
||||
rm phobos.zip
|
||||
zip phobos $(SRC)
|
||||
|
||||
clean:
|
||||
rm $(OBJS)
|
20
linuxextern.d
Normal file
20
linuxextern.d
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
// Copyright (C) 2003 by Digital Mars, www.digitalmars.com
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
|
||||
/* These are all the globals defined by the linux C runtime library.
|
||||
* Put them separate so they'll be externed - do not link in linuxextern.o
|
||||
*/
|
||||
|
||||
extern (C)
|
||||
{
|
||||
void* __libc_stack_end;
|
||||
int __data_start;
|
||||
int _end;
|
||||
int timezone;
|
||||
|
||||
void *_deh_beg;
|
||||
void *_deh_end;
|
||||
}
|
||||
|
224
llmath.d
Normal file
224
llmath.d
Normal file
|
@ -0,0 +1,224 @@
|
|||
// llmath.d
|
||||
// Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com
|
||||
// All Rights Reserved
|
||||
// Written by Walter Bright
|
||||
|
||||
// Compiler runtime support for 64 bit longs
|
||||
|
||||
extern (C):
|
||||
|
||||
|
||||
/***************************************
|
||||
* Unsigned long divide.
|
||||
* Input:
|
||||
* [EDX,EAX],[ECX,EBX]
|
||||
* Output:
|
||||
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
|
||||
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
|
||||
* ESI,EDI destroyed
|
||||
*/
|
||||
|
||||
void __ULDIV__()
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked ;
|
||||
test ECX,ECX ;
|
||||
jz uldiv ;
|
||||
|
||||
push EBP ;
|
||||
|
||||
// left justify [ECX,EBX] and leave count of shifts + 1 in EBP
|
||||
|
||||
mov EBP,1 ; // at least 1 shift
|
||||
test ECX,ECX ; // left justified?
|
||||
js L1 ; // yes
|
||||
jnz L2 ;
|
||||
add EBP,8 ;
|
||||
mov CH,CL ;
|
||||
mov CL,BH ;
|
||||
mov BH,BL ;
|
||||
xor BL,BL ; // [ECX,EBX] <<= 8
|
||||
test ECX,ECX ;
|
||||
js L1 ;
|
||||
even ;
|
||||
L2: inc EBP ; // another shift
|
||||
shl EBX,1 ;
|
||||
rcl ECX,1 ; // [ECX,EBX] <<= 1
|
||||
jno L2 ; // not left justified yet
|
||||
|
||||
L1: mov ESI,ECX ;
|
||||
mov EDI,EBX ; // [ESI,EDI] = divisor
|
||||
|
||||
mov ECX,EDX ;
|
||||
mov EBX,EAX ; // [ECX,EBX] = [EDX,EAX]
|
||||
xor EAX,EAX ;
|
||||
cwd ; // [EDX,EAX] = 0
|
||||
even ;
|
||||
L4: cmp ESI,ECX ; // is [ECX,EBX] > [ESI,EDI]?
|
||||
ja L3 ; // yes
|
||||
jb L5 ; // definitely less than
|
||||
cmp EDI,EBX ; // check low order word
|
||||
ja L3 ;
|
||||
L5: sub EBX,EDI ;
|
||||
sbb ECX,ESI ; // [ECX,EBX] -= [ESI,EDI]
|
||||
stc ; // rotate in a 1
|
||||
L3: rcl EAX,1 ;
|
||||
rcl EDX,1 ; // [EDX,EAX] = ([EDX,EAX] << 1) + C
|
||||
shr ESI,1 ;
|
||||
rcr EDI,1 ; // [ESI,EDI] >>= 1
|
||||
dec EBP ; // control count
|
||||
jne L4 ;
|
||||
pop EBP ;
|
||||
ret ;
|
||||
|
||||
div0: mov EAX,-1 ;
|
||||
cwd ; // quotient is -1
|
||||
// xor ECX,ECX ;
|
||||
// mov EBX,ECX ; // remainder is 0 (ECX and EBX already 0)
|
||||
pop EBP ;
|
||||
ret ;
|
||||
|
||||
uldiv: test EDX,EDX ;
|
||||
jnz D3 ;
|
||||
// Both high words are 0, we can use the DIV instruction
|
||||
div EBX ;
|
||||
mov EBX,EDX ;
|
||||
mov EDX,ECX ; // EDX = ECX = 0
|
||||
ret ;
|
||||
|
||||
even ;
|
||||
D3: // Divide [EDX,EAX] by EBX
|
||||
mov ECX,EAX ;
|
||||
mov EAX,EDX ;
|
||||
xor EDX,EDX ;
|
||||
div EBX ;
|
||||
xchg ECX,EAX ;
|
||||
div EBX ;
|
||||
// ECX,EAX = result
|
||||
// EDX = remainder
|
||||
mov EBX,EDX ;
|
||||
mov EDX,ECX ;
|
||||
xor ECX,ECX ;
|
||||
ret ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************
|
||||
* Signed long divide.
|
||||
* Input:
|
||||
* [EDX,EAX],[ECX,EBX]
|
||||
* Output:
|
||||
* [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
|
||||
* [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
|
||||
* ESI,EDI destroyed
|
||||
*/
|
||||
|
||||
void __LDIV__()
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked ;
|
||||
test EDX,EDX ; // [EDX,EAX] negative?
|
||||
jns L10 ; // no
|
||||
//neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
|
||||
neg EDX ;
|
||||
neg EAX ;
|
||||
sbb EDX,0 ;
|
||||
test ECX,ECX ; // [ECX,EBX] negative?
|
||||
jns L11 ; // no
|
||||
//neg64 ECX,EBX ;
|
||||
neg ECX ;
|
||||
neg EBX ;
|
||||
sbb ECX,0 ;
|
||||
call __ULDIV__ ;
|
||||
//neg64 ECX,EBX ; // remainder same sign as dividend
|
||||
neg ECX ;
|
||||
neg EBX ;
|
||||
sbb ECX,0 ;
|
||||
ret ;
|
||||
|
||||
L11: call __ULDIV__ ;
|
||||
//neg64 ECX,EBX ; // remainder same sign as dividend
|
||||
neg ECX ;
|
||||
neg EBX ;
|
||||
sbb ECX,0 ;
|
||||
//neg64 EDX,EAX ; // quotient is negative
|
||||
neg EDX ;
|
||||
neg EAX ;
|
||||
sbb EDX,0 ;
|
||||
ret ;
|
||||
|
||||
L10: test ECX,ECX ; // [ECX,EBX] negative?
|
||||
jns L12 ; // no (all is positive)
|
||||
//neg64 ECX,EBX ;
|
||||
neg ECX ;
|
||||
neg EBX ;
|
||||
sbb ECX,0 ;
|
||||
call __ULDIV__ ;
|
||||
//neg64 EDX,EAX ; // quotient is negative
|
||||
neg EDX ;
|
||||
neg EAX ;
|
||||
sbb EDX,0 ;
|
||||
ret ;
|
||||
|
||||
L12: jmp __ULDIV__ ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************
|
||||
* Compare [EDX,EAX] with [ECX,EBX]
|
||||
* Signed
|
||||
* Returns result in flags
|
||||
*/
|
||||
|
||||
void __LCMP__()
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked ;
|
||||
cmp EDX,ECX ;
|
||||
jne C1 ;
|
||||
push EDX ;
|
||||
xor EDX,EDX ;
|
||||
cmp EAX,EBX ;
|
||||
jz C2 ;
|
||||
ja C3 ;
|
||||
dec EDX ;
|
||||
pop EDX ;
|
||||
ret ;
|
||||
|
||||
C3: inc EDX ;
|
||||
C2: pop EDX ;
|
||||
C1: ret ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Convert ulong to real
|
||||
|
||||
private real adjust = cast(real)0x800000000000000 * 0x10;
|
||||
|
||||
real __U64_LDBL()
|
||||
{
|
||||
asm
|
||||
{ naked ;
|
||||
push EDX ;
|
||||
push EAX ;
|
||||
and dword ptr 4[ESP], 0x7FFFFFFF ;
|
||||
fild qword ptr [ESP] ;
|
||||
test EDX,EDX ;
|
||||
jns L1 ;
|
||||
fld real ptr adjust ;
|
||||
faddp ST(1), ST ;
|
||||
L1: ;
|
||||
add ESP, 8 ;
|
||||
ret ;
|
||||
}
|
||||
}
|
||||
|
||||
|
9
math2.d
9
math2.d
|
@ -1319,6 +1319,7 @@ unittest
|
|||
|
||||
char[] toString(real x)
|
||||
{
|
||||
// BUG: this code is broken, returning a pointer into the stack
|
||||
char[1024] buffer;
|
||||
char* p = buffer;
|
||||
uint psize = buffer.length;
|
||||
|
@ -1331,6 +1332,7 @@ char[] toString(real x)
|
|||
if (count != -1)
|
||||
break;
|
||||
psize *= 2;
|
||||
p = cast(char*) alloca(psize);
|
||||
}
|
||||
else version(linux)
|
||||
{
|
||||
|
@ -1341,8 +1343,13 @@ char[] toString(real x)
|
|||
psize = count + 1;
|
||||
else
|
||||
break;
|
||||
/+
|
||||
if (p != buffer)
|
||||
c.stdlib.free(p);
|
||||
p = cast(char*) c.stdlib.malloc(psize);
|
||||
+/
|
||||
p = cast(char*) alloca(psize);
|
||||
}
|
||||
p = cast(char*) alloca(psize);
|
||||
}
|
||||
return p[0 .. count];
|
||||
}
|
||||
|
|
62
moduleinit.d
62
moduleinit.d
|
@ -1,4 +1,6 @@
|
|||
|
||||
//debug = 1;
|
||||
|
||||
import object;
|
||||
import c.stdio;
|
||||
import c.stdlib;
|
||||
|
@ -6,7 +8,7 @@ import string;
|
|||
|
||||
enum
|
||||
{ MIctorstart = 1, // we've started constructing it
|
||||
MIctordone = 2, // finished construction
|
||||
MIctordone = 2, // finished construction
|
||||
}
|
||||
|
||||
class ModuleInfo
|
||||
|
@ -30,9 +32,24 @@ class ModuleCtorError : Exception
|
|||
}
|
||||
}
|
||||
|
||||
// This gets initialized by minit.asm
|
||||
|
||||
// Win32: this gets initialized by minit.asm
|
||||
// linux: this gets initialized in _moduleCtor()
|
||||
extern (C) ModuleInfo[] _moduleinfo_array;
|
||||
|
||||
version (linux)
|
||||
{
|
||||
// This linked list is created by a compiler generated function inserted
|
||||
// into the .ctor list by the compiler.
|
||||
struct ModuleReference
|
||||
{
|
||||
ModuleReference* next;
|
||||
ModuleInfo mod;
|
||||
}
|
||||
|
||||
extern (C) ModuleReference *_Dmodule_ref; // start of linked list
|
||||
}
|
||||
|
||||
ModuleInfo[] _moduleinfo_dtors;
|
||||
uint _moduleinfo_dtors_i;
|
||||
|
||||
|
@ -45,23 +62,43 @@ extern (C) int _fatexit(void *);
|
|||
|
||||
extern (C) void _moduleCtor()
|
||||
{
|
||||
// Ensure module destructors also get called on program termination
|
||||
_fatexit(&_moduleDtor);
|
||||
version (linux)
|
||||
{
|
||||
int length = 0;
|
||||
ModuleReference *mr;
|
||||
|
||||
for (mr = _Dmodule_ref; mr; mr = mr.next)
|
||||
length++;
|
||||
_moduleinfo_array = new ModuleInfo[length];
|
||||
length = 0;
|
||||
for (mr = _Dmodule_ref; mr; mr = mr.next)
|
||||
{ _moduleinfo_array[length] = mr.mod;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
// Ensure module destructors also get called on program termination
|
||||
//_fatexit(&_STD_moduleDtor);
|
||||
}
|
||||
|
||||
_moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
|
||||
//printf("_moduleinfo_dtors = x%x\n", (void *)_moduleinfo_dtors);
|
||||
_moduleCtor2(_moduleinfo_array, 0);
|
||||
}
|
||||
|
||||
void _moduleCtor2(ModuleInfo[] mi, int skip)
|
||||
{
|
||||
//printf("_moduleCtor2(): %d modules\n", mi.length);
|
||||
debug printf("_moduleCtor2(): %d modules\n", mi.length);
|
||||
for (uint i = 0; i < mi.length; i++)
|
||||
{
|
||||
ModuleInfo m = mi[i];
|
||||
|
||||
// debug printf("\tmodule[%d] = '%.*s'\n", i, m.name);
|
||||
if (m.flags & MIctordone)
|
||||
continue;
|
||||
//printf("\tmodule[%d] = '%.*s'\n", i, m.name);
|
||||
debug printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
|
||||
|
||||
if (m.ctor || m.dtor)
|
||||
{
|
||||
|
@ -79,6 +116,7 @@ void _moduleCtor2(ModuleInfo[] mi, int skip)
|
|||
m.flags |= MIctordone;
|
||||
|
||||
// Now that construction is done, register the destructor
|
||||
//printf("\tadding module dtor x%x\n", m);
|
||||
assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
|
||||
_moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
|
||||
}
|
||||
|
@ -95,19 +133,23 @@ void _moduleCtor2(ModuleInfo[] mi, int skip)
|
|||
* Destruct the modules.
|
||||
*/
|
||||
|
||||
// Starting the name with "_STD" means under linux a pointer to the
|
||||
// function gets put in the .dtors segment.
|
||||
|
||||
extern (C) void _moduleDtor()
|
||||
{
|
||||
//printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors.length);
|
||||
debug printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
|
||||
for (uint i = _moduleinfo_dtors_i; i-- != 0;)
|
||||
{
|
||||
ModuleInfo m = _moduleinfo_dtors[i];
|
||||
|
||||
//printf("\tmodule[%d] = '%.*s'\n", i, m.name);
|
||||
debug printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
|
||||
if (m.dtor)
|
||||
{
|
||||
(*m.dtor)();
|
||||
}
|
||||
}
|
||||
debug printf("_moduleDtor() done\n");
|
||||
}
|
||||
|
||||
/**********************************
|
||||
|
@ -116,12 +158,12 @@ extern (C) void _moduleDtor()
|
|||
|
||||
extern (C) void _moduleUnitTests()
|
||||
{
|
||||
//printf("_moduleUnitTests()\n");
|
||||
debug printf("_moduleUnitTests()\n");
|
||||
for (uint i = 0; i < _moduleinfo_array.length; i++)
|
||||
{
|
||||
ModuleInfo m = _moduleinfo_array[i];
|
||||
|
||||
//printf("\tmodule[%d] = '%.*s'\n", i, m.name);
|
||||
debug printf("\tmodule[%d] = '%.*s'\n", i, m.name);
|
||||
if (m.unitTest)
|
||||
{
|
||||
(*m.unitTest)();
|
||||
|
|
86
monitor.c
86
monitor.c
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
// Copyright (c) 2000-2002 by Digital Mars
|
||||
// Copyright (c) 2000-2003 by Digital Mars
|
||||
// All Rights Reserved
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
|
@ -10,6 +10,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* =============================== Win32 ============================ */
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mars.h"
|
||||
|
@ -79,3 +84,82 @@ void _d_monitorrelease(Object *h)
|
|||
h->monitor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* =============================== linux ============================ */
|
||||
|
||||
#if linux
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "mars.h"
|
||||
|
||||
static pthread_mutex_t _monitor_critsec;
|
||||
static volatile int inited;
|
||||
|
||||
void _STI_monitor_staticctor()
|
||||
{
|
||||
if (!inited)
|
||||
{ pthread_mutex_init(&_monitor_critsec, 0);
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void _STD_monitor_staticdtor()
|
||||
{
|
||||
if (inited)
|
||||
{ inited = 0;
|
||||
pthread_mutex_destroy(&_monitor_critsec);
|
||||
}
|
||||
}
|
||||
|
||||
void _d_monitorenter(Object *h)
|
||||
{
|
||||
//printf("_d_monitorenter(%p), %p\n", h, h->monitor);
|
||||
if (!h->monitor)
|
||||
{ pthread_mutex_t *cs;
|
||||
|
||||
cs = (pthread_mutex_t *)calloc(sizeof(pthread_mutex_t), 1);
|
||||
assert(cs);
|
||||
pthread_mutex_lock(&_monitor_critsec);
|
||||
if (!h->monitor) // if, in the meantime, another thread didn't set it
|
||||
{
|
||||
h->monitor = (unsigned)cs;
|
||||
pthread_mutex_init(cs, 0);
|
||||
cs = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&_monitor_critsec);
|
||||
if (cs) // if we didn't use it
|
||||
free(cs);
|
||||
}
|
||||
//printf("-_d_monitorenter(%p)\n", h);
|
||||
pthread_mutex_lock((pthread_mutex_t *)h->monitor);
|
||||
//printf("-_d_monitorenter(%p)\n", h);
|
||||
}
|
||||
|
||||
void _d_monitorexit(Object *h)
|
||||
{
|
||||
//printf("+_d_monitorexit(%p)\n", h);
|
||||
assert(h->monitor);
|
||||
pthread_mutex_unlock((pthread_mutex_t *)h->monitor);
|
||||
//printf("-_d_monitorexit(%p)\n", h);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Called by garbage collector when Object is free'd.
|
||||
*/
|
||||
|
||||
void _d_monitorrelease(Object *h)
|
||||
{
|
||||
if (h->monitor)
|
||||
{ pthread_mutex_destroy((pthread_mutex_t *)h->monitor);
|
||||
|
||||
// We can improve this by making a free list of monitors
|
||||
free((void *)h->monitor);
|
||||
|
||||
h->monitor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
15
outbuffer.d
15
outbuffer.d
|
@ -217,6 +217,7 @@ class OutBuffer
|
|||
if (count != -1)
|
||||
break;
|
||||
psize *= 2;
|
||||
p = (char *) alloca(psize); // buffer too small, try again with larger size
|
||||
}
|
||||
version(linux)
|
||||
{
|
||||
|
@ -227,10 +228,22 @@ class OutBuffer
|
|||
psize = count + 1;
|
||||
else
|
||||
break;
|
||||
/+
|
||||
if (p != buffer)
|
||||
c.stdlib.free(p);
|
||||
p = (char *) c.stdlib.malloc(psize); // buffer too small, try again with larger size
|
||||
+/
|
||||
p = (char *) alloca(psize); // buffer too small, try again with larger size
|
||||
}
|
||||
p = (char *) alloca(psize); // buffer too small, try again with larger size
|
||||
}
|
||||
write(p[0 .. count]);
|
||||
/+
|
||||
version (linux)
|
||||
{
|
||||
if (p != buffer)
|
||||
c.stdlib.free(p);
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
|
|
|
@ -10,7 +10,7 @@ class OutOfMemory : Object
|
|||
}
|
||||
}
|
||||
|
||||
extern (C) static void _d_OutOfMemory()
|
||||
extern (C) void _d_OutOfMemory()
|
||||
{
|
||||
throw (OutOfMemory)(void *)OutOfMemory.classinfo.init;
|
||||
}
|
||||
|
|
90
path.d
90
path.d
|
@ -68,19 +68,32 @@ unittest
|
|||
int i;
|
||||
char[] result;
|
||||
|
||||
result = getExt('d:\path\foo.bat');
|
||||
version (Win32)
|
||||
result = getExt('d:\path\foo.bat');
|
||||
version (linux)
|
||||
result = getExt('/path/foo.bat');
|
||||
i = cmp(result, "bat");
|
||||
assert(i == 0);
|
||||
|
||||
result = getExt('d:\path\foo.');
|
||||
version (Win32)
|
||||
result = getExt('d:\path\foo.');
|
||||
version (linux)
|
||||
result = getExt('d/path/foo.');
|
||||
i = cmp(result, "");
|
||||
assert(i == 0);
|
||||
|
||||
result = getExt('d:\path\foo');
|
||||
version (Win32)
|
||||
result = getExt('d:\path\foo');
|
||||
version (linux)
|
||||
result = getExt('d/path/foo');
|
||||
i = cmp(result, "");
|
||||
assert(i == 0);
|
||||
|
||||
result = getExt('d:\path.bar\foo');
|
||||
version (Win32)
|
||||
result = getExt('d:\path.bar\foo');
|
||||
version (linux)
|
||||
result = getExt('/path.bar/foo');
|
||||
|
||||
i = cmp(result, "");
|
||||
assert(i == 0);
|
||||
|
||||
|
@ -125,12 +138,18 @@ unittest
|
|||
int i;
|
||||
char[] result;
|
||||
|
||||
result = getBaseName('d:\path\foo.bat');
|
||||
version (Win32)
|
||||
result = getBaseName('d:\path\foo.bat');
|
||||
version (linux)
|
||||
result = getBaseName('/path/foo.bat');
|
||||
//printf("result = '%.*s'\n", result);
|
||||
i = cmp(result, "foo.bat");
|
||||
assert(i == 0);
|
||||
|
||||
result = getBaseName('a\b');
|
||||
version (Win32)
|
||||
result = getBaseName('a\b');
|
||||
version (linux)
|
||||
result = getBaseName('a/b');
|
||||
i = cmp(result, "b");
|
||||
assert(i == 0);
|
||||
}
|
||||
|
@ -332,19 +351,40 @@ unittest
|
|||
int i;
|
||||
|
||||
p = join("foo", "bar");
|
||||
i = cmp(p, 'foo\bar');
|
||||
version (Win32)
|
||||
i = cmp(p, 'foo\bar');
|
||||
version (linux)
|
||||
i = cmp(p, 'foo/bar');
|
||||
assert(i == 0);
|
||||
|
||||
p = join('foo\', 'bar');
|
||||
i = cmp(p, 'foo\bar');
|
||||
version (Win32)
|
||||
{ p = join('foo\', 'bar');
|
||||
i = cmp(p, 'foo\bar');
|
||||
}
|
||||
version (linux)
|
||||
{ p = join('foo/', 'bar');
|
||||
i = cmp(p, 'foo/bar');
|
||||
}
|
||||
assert(i == 0);
|
||||
|
||||
p = join('foo', '\bar');
|
||||
i = cmp(p, '\bar');
|
||||
version (Win32)
|
||||
{ p = join('foo', '\bar');
|
||||
i = cmp(p, '\bar');
|
||||
}
|
||||
version (linux)
|
||||
{ p = join('foo', '/bar');
|
||||
i = cmp(p, '/bar');
|
||||
}
|
||||
assert(i == 0);
|
||||
|
||||
p = join('foo\', '\bar');
|
||||
i = cmp(p, '\bar');
|
||||
version (Win32)
|
||||
{ p = join('foo\', '\bar');
|
||||
i = cmp(p, '\bar');
|
||||
}
|
||||
version (linux)
|
||||
{ p = join('foo/', '/bar');
|
||||
i = cmp(p, '/bar');
|
||||
}
|
||||
assert(i == 0);
|
||||
|
||||
version(Win32)
|
||||
|
@ -391,15 +431,22 @@ unittest
|
|||
|
||||
int fncharmatch(char c1, char c2)
|
||||
{
|
||||
if (c1 != c2)
|
||||
version (Win32)
|
||||
{
|
||||
if (c1 != c2)
|
||||
{
|
||||
if ('A' <= c1 && c1 <= 'Z')
|
||||
c1 += cast(char)'a' - 'A';
|
||||
if ('A' <= c2 && c2 <= 'Z')
|
||||
c2 += cast(char)'a' - 'A';
|
||||
return c1 == c2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
if ('A' <= c1 && c1 <= 'Z')
|
||||
c1 += cast(char)'a' - 'A';
|
||||
if ('A' <= c2 && c2 <= 'Z')
|
||||
c2 += cast(char)'a' - 'A';
|
||||
return c1 == c2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************
|
||||
|
@ -523,7 +570,10 @@ unittest
|
|||
{
|
||||
debug(path) printf("path.fnmatch.unittest\n");
|
||||
|
||||
assert(fnmatch("foo", "Foo"));
|
||||
version (Win32)
|
||||
assert(fnmatch("foo", "Foo"));
|
||||
version (linux)
|
||||
assert(!fnmatch("foo", "Foo"));
|
||||
assert(fnmatch("foo", "*"));
|
||||
assert(fnmatch("foo.bar", "*"));
|
||||
assert(fnmatch("foo.bar", "*.*"));
|
||||
|
|
7
random.d
7
random.d
|
@ -11,6 +11,11 @@ version (Win32)
|
|||
extern(Windows) int QueryPerformanceCounter(ulong *count);
|
||||
}
|
||||
|
||||
version (linux)
|
||||
{
|
||||
import linux;
|
||||
}
|
||||
|
||||
/* ===================== Random ========================= */
|
||||
|
||||
// BUG: not multithreaded
|
||||
|
@ -75,7 +80,7 @@ static this()
|
|||
// time.h
|
||||
// sys/time.h
|
||||
|
||||
struct timeval tv;
|
||||
timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, null))
|
||||
{ // Some error happened - try time() instead
|
||||
|
|
11
regexp.d
11
regexp.d
|
@ -606,6 +606,7 @@ void printProgram(ubyte[] prog)
|
|||
{
|
||||
printf("%3d: ", pc);
|
||||
|
||||
//printf("prog[pc] = %d, REchar = %d, REnmq = %d\n", prog[pc], REchar, REnmq);
|
||||
switch (prog[pc])
|
||||
{
|
||||
case REchar:
|
||||
|
@ -712,7 +713,9 @@ void printProgram(ubyte[] prog)
|
|||
len = puint[0];
|
||||
n = puint[1];
|
||||
m = puint[2];
|
||||
printf("\tREnm%s len=%d, n=%u, m=%u, pc=>%d\n", (prog[pc] == REnmq) ? "q" : " ", len, n, m, pc + 1 + uint.size * 3 + len);
|
||||
printf("\tREnm%.*s len=%d, n=%u, m=%u, pc=>%d\n",
|
||||
(prog[pc] == REnmq) ? "q" : " ",
|
||||
len, n, m, pc + 1 + uint.size * 3 + len);
|
||||
pc += 1 + uint.size * 3;
|
||||
break;
|
||||
|
||||
|
@ -1085,7 +1088,10 @@ int trymatch(int pc, int pcend)
|
|||
}
|
||||
if (!psave && count < m)
|
||||
{
|
||||
psave = (regmatch_t *)alloca((re_nsub + 1) * regmatch_t.size);
|
||||
//version (Win32)
|
||||
psave = (regmatch_t *)alloca((re_nsub + 1) * regmatch_t.size);
|
||||
//else
|
||||
//psave = new regmatch_t[re_nsub + 1];
|
||||
}
|
||||
if (program[pc] == REnmq) // if minimal munch
|
||||
{
|
||||
|
@ -2007,6 +2013,7 @@ void optimize()
|
|||
prog = buf.toBytes();
|
||||
for (i = 0; 1;)
|
||||
{
|
||||
//printf("\tprog[%d] = %d, %d\n", i, prog[i], REstring);
|
||||
switch (prog[i])
|
||||
{
|
||||
case REend:
|
||||
|
|
226
stream.d
226
stream.d
|
@ -132,25 +132,25 @@ class Stream
|
|||
char[] result;
|
||||
try
|
||||
{
|
||||
char c = getc();
|
||||
char ch = getc();
|
||||
while (readable)
|
||||
{
|
||||
switch (c)
|
||||
switch (ch)
|
||||
{
|
||||
case "\r":
|
||||
{
|
||||
c = getc();
|
||||
if (c != "\n")
|
||||
ungetc(c);
|
||||
ch = getc();
|
||||
if (ch != "\n")
|
||||
ungetc(ch);
|
||||
}
|
||||
|
||||
case "\n":
|
||||
return result;
|
||||
|
||||
default:
|
||||
result ~= c;
|
||||
result ~= ch;
|
||||
}
|
||||
c = getc();
|
||||
ch = getc();
|
||||
}
|
||||
}
|
||||
catch (ReadError e)
|
||||
|
@ -678,7 +678,7 @@ nws:
|
|||
else version (Mac)
|
||||
writeString("\r");
|
||||
+/
|
||||
else // probably *NIX
|
||||
else
|
||||
writeString("\n");
|
||||
}
|
||||
|
||||
|
@ -723,26 +723,38 @@ nws:
|
|||
{
|
||||
version (Win32)
|
||||
{
|
||||
count = _vsnprintf(p, psize, f, args);
|
||||
if (count != -1)
|
||||
break;
|
||||
psize *= 2;
|
||||
count = _vsnprintf(p, psize, f, args);
|
||||
if (count != -1)
|
||||
break;
|
||||
psize *= 2;
|
||||
p = cast(char*) alloca(psize);
|
||||
}
|
||||
else version (linux)
|
||||
{
|
||||
count = vsnprintf(p, psize, f, args);
|
||||
if (count == -1)
|
||||
psize *= 2;
|
||||
else if (count >= psize)
|
||||
psize = count + 1;
|
||||
else
|
||||
break;
|
||||
count = vsnprintf(p, psize, f, args);
|
||||
if (count == -1)
|
||||
psize *= 2;
|
||||
else if (count >= psize)
|
||||
psize = count + 1;
|
||||
else
|
||||
break;
|
||||
/+if (p != buffer)
|
||||
c.stdlib.free(p);
|
||||
p = (char *) c.stdlib.malloc(psize); // buffer too small, try again with larger size
|
||||
+/
|
||||
p = cast(char*) alloca(psize);
|
||||
}
|
||||
else
|
||||
throw new Error("unsupported platform");
|
||||
p = cast(char*) alloca(psize);
|
||||
throw new Error("unsupported platform");
|
||||
}
|
||||
writeString(p[0 .. count]);
|
||||
/+
|
||||
version (linux)
|
||||
{
|
||||
if (p != buffer)
|
||||
c.stdlib.free(p);
|
||||
}
|
||||
+/
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -867,7 +879,17 @@ enum FileMode
|
|||
// just a file on disk
|
||||
class File: Stream
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
import windows;
|
||||
private HANDLE hFile;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
import linux;
|
||||
alias int HANDLE;
|
||||
private HANDLE hFile = -1;
|
||||
}
|
||||
|
||||
// for compatibility with old versions...
|
||||
deprecated enum: FileMode
|
||||
|
@ -876,9 +898,17 @@ class File: Stream
|
|||
towrite = FileMode.Out
|
||||
}
|
||||
|
||||
private HANDLE hFile;
|
||||
|
||||
this() { hFile = null; }
|
||||
this()
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
hFile = null;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
hFile = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// opens existing handle; use with care!
|
||||
this(HANDLE hFile, FileMode mode)
|
||||
|
@ -903,8 +933,10 @@ class File: Stream
|
|||
// opens file in requested mode
|
||||
void open(char[] filename, FileMode mode)
|
||||
{
|
||||
close();
|
||||
int access = 0, share = 0;
|
||||
close();
|
||||
int access = 0, share = 0;
|
||||
version (Win32)
|
||||
{
|
||||
if (mode & FileMode.In)
|
||||
{
|
||||
readable = true;
|
||||
|
@ -921,6 +953,26 @@ class File: Stream
|
|||
null, OPEN_EXISTING, 0, null);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
throw new OpenError("file '" ~ filename ~ "' not found");
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
if (mode & FileMode.In)
|
||||
{
|
||||
readable = true;
|
||||
access = O_RDONLY;
|
||||
share = 0660;
|
||||
}
|
||||
if (mode & FileMode.Out)
|
||||
{
|
||||
writeable = true;
|
||||
access = O_CREAT | O_WRONLY;
|
||||
share = 0660;
|
||||
}
|
||||
seekable = true;
|
||||
hFile = linux.open(toStringz(filename), access, share);
|
||||
if (hFile == -1)
|
||||
throw new OpenError("file '" ~ filename ~ "' not found");
|
||||
}
|
||||
}
|
||||
|
||||
// creates file for writing
|
||||
|
@ -929,8 +981,10 @@ class File: Stream
|
|||
// creates file in requested mode
|
||||
void create(char[] filename, FileMode mode)
|
||||
{
|
||||
close();
|
||||
int access = 0, share = 0;
|
||||
close();
|
||||
int access = 0, share = 0;
|
||||
version (Win32)
|
||||
{
|
||||
if (mode & FileMode.In)
|
||||
{
|
||||
access |= GENERIC_READ;
|
||||
|
@ -947,6 +1001,26 @@ class File: Stream
|
|||
writeable = cast(bit)(mode & FileMode.Out);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
throw new CreateError("unable to create file '" ~ filename ~ "'");
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
if (mode & FileMode.In)
|
||||
{
|
||||
readable = true;
|
||||
access = O_RDONLY;
|
||||
share = 0660;
|
||||
}
|
||||
if (mode & FileMode.Out)
|
||||
{
|
||||
writeable = true;
|
||||
access = O_CREAT | O_WRONLY | O_TRUNC;
|
||||
share = 0660;
|
||||
}
|
||||
seekable = true;
|
||||
hFile = linux.open(toStringz(filename), access, share);
|
||||
if (hFile == -1)
|
||||
throw new OpenError("file '" ~ filename ~ "' not found");
|
||||
}
|
||||
}
|
||||
|
||||
// closes file, if it is open; otherwise, does nothing
|
||||
|
@ -954,9 +1028,17 @@ class File: Stream
|
|||
{
|
||||
if (hFile)
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
hFile = null;
|
||||
readable = writeable = seekable = false;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
linux.close(hFile);
|
||||
hFile = -1;
|
||||
}
|
||||
readable = writeable = seekable = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -968,8 +1050,15 @@ class File: Stream
|
|||
}
|
||||
body
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
ReadFile(hFile, buffer, size, &size, null);
|
||||
return size;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
size = linux.read(hFile, buffer, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
override uint writeBlock(void* buffer, uint size)
|
||||
|
@ -980,8 +1069,15 @@ class File: Stream
|
|||
}
|
||||
body
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
WriteFile(hFile, buffer, size, &size, null);
|
||||
return size;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
size = linux.write(hFile, buffer, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
override ulong seek(long offset, SeekPos rel)
|
||||
|
@ -992,10 +1088,19 @@ class File: Stream
|
|||
}
|
||||
body
|
||||
{
|
||||
version (Win32)
|
||||
{
|
||||
uint result = SetFilePointer(hFile, offset, null, rel);
|
||||
if (result == 0xFFFFFFFF)
|
||||
throw new SeekError("unable to move file pointer");
|
||||
return result;
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
uint result = lseek(hFile, offset, rel);
|
||||
if (result == 0xFFFFFFFF)
|
||||
throw new SeekError("unable to move file pointer");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// OS-specific property, just in case somebody wants
|
||||
|
@ -1014,7 +1119,10 @@ class File: Stream
|
|||
file.writeString("Hello, world!");
|
||||
file.write(i);
|
||||
// string#1 + string#2 + int should give exacly that
|
||||
assert(file.position() == 19 + 13 + 4);
|
||||
version (Win32)
|
||||
assert(file.position() == 19 + 13 + 4);
|
||||
version (linux)
|
||||
assert(file.position() == 18 + 13 + 4);
|
||||
// we must be at the end of file
|
||||
assert(file.eof());
|
||||
file.close();
|
||||
|
@ -1026,12 +1134,18 @@ class File: Stream
|
|||
assert(!string.cmp(file.readLine(), "Testing stream.d:"));
|
||||
// jump over "Hello, "
|
||||
file.seek(7, SeekPos.Current);
|
||||
assert(file.position() == 19 + 7);
|
||||
version (Win32)
|
||||
assert(file.position() == 19 + 7);
|
||||
version (linux)
|
||||
assert(file.position() == 18 + 7);
|
||||
assert(!string.cmp(file.readString(6), "world!"));
|
||||
i = 0; file.read(i);
|
||||
assert(i == 666);
|
||||
// string#1 + string#2 + int should give exacly that
|
||||
assert(file.position() == 19 + 13 + 4);
|
||||
version (Win32)
|
||||
assert(file.position() == 19 + 13 + 4);
|
||||
version (linux)
|
||||
assert(file.position() == 18 + 13 + 4);
|
||||
// we must be at the end of file
|
||||
assert(file.eof());
|
||||
file.close();
|
||||
|
@ -1105,7 +1219,7 @@ class MemoryStream: Stream
|
|||
cur += size;
|
||||
if (cur > len)
|
||||
len = cur;
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
override ulong seek(long offset, SeekPos rel)
|
||||
|
@ -1309,7 +1423,7 @@ class SliceStream : Stream
|
|||
MemoryStream m;
|
||||
SliceStream s;
|
||||
|
||||
m = new MemoryStream ("Hello, world");
|
||||
m = new MemoryStream ((cast(char[])"Hello, world").dup);
|
||||
s = new SliceStream (m, 4, 8);
|
||||
assert (s.size () == 4);
|
||||
assert (s.writeBlock ((char *) "Vroom", 5) == 4);
|
||||
|
@ -1348,22 +1462,36 @@ private bit ishexdigit(char c)
|
|||
return isdigit(c) || (c >= "A" && c <= "F") || (c >= "a" && c <= "f");
|
||||
}
|
||||
|
||||
// API imports
|
||||
private extern(Windows)
|
||||
{
|
||||
private import windows;
|
||||
HANDLE GetStdHandle(DWORD);
|
||||
}
|
||||
|
||||
// standard IO devices
|
||||
File stdin, stdout, stderr;
|
||||
|
||||
static this()
|
||||
version (Win32)
|
||||
{
|
||||
// open standard I/O devices
|
||||
stdin = new File(GetStdHandle(-10), FileMode.In);
|
||||
stdout = new File(GetStdHandle(-11), FileMode.Out);
|
||||
stderr = new File(GetStdHandle(-12), FileMode.Out);
|
||||
// API imports
|
||||
private extern(Windows)
|
||||
{
|
||||
private import windows;
|
||||
HANDLE GetStdHandle(DWORD);
|
||||
}
|
||||
|
||||
static this()
|
||||
{
|
||||
// open standard I/O devices
|
||||
stdin = new File(GetStdHandle(-10), FileMode.In);
|
||||
stdout = new File(GetStdHandle(-11), FileMode.Out);
|
||||
stderr = new File(GetStdHandle(-12), FileMode.Out);
|
||||
}
|
||||
}
|
||||
|
||||
version (linux)
|
||||
{
|
||||
static this()
|
||||
{
|
||||
// open standard I/O devices
|
||||
stdin = new File(0, FileMode.In);
|
||||
stdout = new File(1, FileMode.Out);
|
||||
stderr = new File(2, FileMode.Out);
|
||||
}
|
||||
}
|
||||
|
||||
import string;
|
||||
|
|
193
string.d
193
string.d
|
@ -124,7 +124,29 @@ int icmp(char[] s1, char[] s2)
|
|||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
result = memicmp(s1, s2, len);
|
||||
version (Win32)
|
||||
{
|
||||
result = memicmp(s1, s2, len);
|
||||
}
|
||||
version (linux)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (s1[i] != s2[i])
|
||||
{
|
||||
char c1 = s1[i];
|
||||
char c2 = s2[i];
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += (int)'a' - (int)'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += (int)'a' - (int)'A';
|
||||
result = (int)c1 - (int)c2;
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
result = cast(int)s1.length - cast(int)s2.length;
|
||||
return result;
|
||||
|
@ -303,34 +325,60 @@ int find(char[] s, char[] sub)
|
|||
}
|
||||
body
|
||||
{
|
||||
int imax;
|
||||
char c;
|
||||
int sublength = sub.length;
|
||||
|
||||
if (sub.length == 0)
|
||||
if (sublength == 0)
|
||||
return 0;
|
||||
if (sub.length == 1)
|
||||
|
||||
char c = sub[0];
|
||||
if (sublength == 1)
|
||||
{
|
||||
char *p = memchr(s, sub[0], s.length);
|
||||
char *p = memchr(s, c, s.length);
|
||||
if (p)
|
||||
return p - &s[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
imax = s.length - sub.length + 1;
|
||||
c = sub[0];
|
||||
int imax = s.length - sublength + 1;
|
||||
|
||||
// Remainder of sub[]
|
||||
char *q = &sub[1];
|
||||
sublength--;
|
||||
|
||||
for (int i = 0; i < imax; i++)
|
||||
{
|
||||
if (s[i] == c)
|
||||
{
|
||||
if (memcmp(&s[i + 1], &sub[1], sub.length - 1) == 0)
|
||||
return i;
|
||||
}
|
||||
char *p = memchr(&s[i], c, imax - i);
|
||||
if (!p)
|
||||
break;
|
||||
i = p - &s[0];
|
||||
if (memcmp(p + 1, q, sublength) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(string) printf("string.find.unittest\n");
|
||||
|
||||
int i;
|
||||
|
||||
i = find(null, cast(char[])'a');
|
||||
assert(i == -1);
|
||||
i = find("def", cast(char[])'a');
|
||||
assert(i == -1);
|
||||
i = find("abba", cast(char[])'a');
|
||||
assert(i == 0);
|
||||
i = find("def", cast(char[])'f');
|
||||
assert(i == 2);
|
||||
i = find("dfefffg", 'fff');
|
||||
assert(i == 3);
|
||||
i = find("dfeffgfff", 'fff');
|
||||
assert(i == 6);
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* Find last occurrance of sub in string s.
|
||||
* Return index in s where it is found.
|
||||
|
@ -710,21 +758,87 @@ char[][] split(char[] s, char[] delim)
|
|||
i = 0;
|
||||
if (s.length)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
j = find(s[i .. s.length], delim);
|
||||
if (j == -1)
|
||||
if (delim.length == 1)
|
||||
{ char c = delim[0];
|
||||
uint nwords = 0;
|
||||
char *p = &s[0];
|
||||
char *pend = p + s.length;
|
||||
|
||||
while (true)
|
||||
{
|
||||
words ~= s[i .. s.length];
|
||||
break;
|
||||
nwords++;
|
||||
p = memchr(p, c, pend - p);
|
||||
if (!p)
|
||||
break;
|
||||
p++;
|
||||
if (p == pend)
|
||||
{ nwords++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
words ~= s[i .. i + j];
|
||||
i += j + delim.length;
|
||||
if (i == s.length)
|
||||
words.length = nwords;
|
||||
|
||||
int wordi = 0;
|
||||
i = 0;
|
||||
while (true)
|
||||
{
|
||||
words ~= "";
|
||||
break;
|
||||
p = memchr(&s[i], c, s.length - i);
|
||||
if (!p)
|
||||
{
|
||||
words[wordi] = s[i .. s.length];
|
||||
break;
|
||||
}
|
||||
j = p - &s[0];
|
||||
words[wordi] = s[i .. j];
|
||||
wordi++;
|
||||
i = j + 1;
|
||||
if (i == s.length)
|
||||
{
|
||||
words[wordi] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(wordi + 1 == nwords);
|
||||
}
|
||||
else
|
||||
{ uint nwords = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
nwords++;
|
||||
j = find(s[i .. s.length], delim);
|
||||
if (j == -1)
|
||||
break;
|
||||
i += j + delim.length;
|
||||
if (i == s.length)
|
||||
{ nwords++;
|
||||
break;
|
||||
}
|
||||
assert(i < s.length);
|
||||
}
|
||||
words.length = nwords;
|
||||
|
||||
int wordi = 0;
|
||||
i = 0;
|
||||
while (true)
|
||||
{
|
||||
j = find(s[i .. s.length], delim);
|
||||
if (j == -1)
|
||||
{
|
||||
words[wordi] = s[i .. s.length];
|
||||
break;
|
||||
}
|
||||
words[wordi] = s[i .. i + j];
|
||||
wordi++;
|
||||
i += j + delim.length;
|
||||
if (i == s.length)
|
||||
{
|
||||
words[wordi] = "";
|
||||
break;
|
||||
}
|
||||
assert(i < s.length);
|
||||
}
|
||||
assert(wordi + 1 == nwords);
|
||||
}
|
||||
}
|
||||
return words;
|
||||
|
@ -762,6 +876,34 @@ unittest
|
|||
assert(words.length == 3);
|
||||
i = cmp(words[0], "peter");
|
||||
assert(i == 0);
|
||||
|
||||
char[] s2 = ",,peter,,paul,,jerry,,";
|
||||
|
||||
words = split(s2, ",,");
|
||||
//printf("words.length = %d\n", words.length);
|
||||
assert(words.length == 5);
|
||||
i = cmp(words[0], "");
|
||||
assert(i == 0);
|
||||
i = cmp(words[1], "peter");
|
||||
assert(i == 0);
|
||||
i = cmp(words[2], "paul");
|
||||
assert(i == 0);
|
||||
i = cmp(words[3], "jerry");
|
||||
assert(i == 0);
|
||||
i = cmp(words[4], "");
|
||||
assert(i == 0);
|
||||
|
||||
s2 = s2[0 .. s2.length - 2]; // lop off trailing ',,'
|
||||
words = split(s2, ",,");
|
||||
assert(words.length == 4);
|
||||
i = cmp(words[3], "jerry");
|
||||
assert(i == 0);
|
||||
|
||||
s2 = s2[2 .. s2.length]; // lop off leading ',,'
|
||||
words = split(s2, ",,");
|
||||
assert(words.length == 3);
|
||||
i = cmp(words[0], "peter");
|
||||
assert(i == 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1244,13 +1386,16 @@ char[] translate(char[] s, char[] transtab, char[] delchars)
|
|||
|
||||
deltab[] = false;
|
||||
for (i = 0; i < delchars.length; i++)
|
||||
{
|
||||
deltab[delchars[i]] = true;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < s.length; i++)
|
||||
{
|
||||
if (!deltab[s[i]])
|
||||
count++;
|
||||
//printf("s[%d] = '%c', count = %d\n", i, s[i], count);
|
||||
}
|
||||
|
||||
r = new char[count];
|
||||
|
|
499
thread.d
499
thread.d
|
@ -5,6 +5,11 @@
|
|||
|
||||
//debug=thread;
|
||||
|
||||
/* ================================ Win32 ================================= */
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
|
||||
import windows;
|
||||
|
||||
extern (Windows) alias uint (*stdfp)(void *);
|
||||
|
@ -324,4 +329,498 @@ void *os_query_stackBottom()
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================ linux ================================= */
|
||||
|
||||
version (linux)
|
||||
{
|
||||
|
||||
import linux;
|
||||
import linuxextern;
|
||||
|
||||
alias uint pthread_t;
|
||||
extern (C) alias void (*__sighandler_t)(int);
|
||||
|
||||
struct sigset_t
|
||||
{
|
||||
uint __val[1024 / (8 * uint.size)];
|
||||
}
|
||||
|
||||
struct sigaction_t
|
||||
{
|
||||
__sighandler_t sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void (*sa_restorer)();
|
||||
}
|
||||
|
||||
struct _pthread_fastlock
|
||||
{
|
||||
int __status;
|
||||
int __spinlock;
|
||||
}
|
||||
|
||||
struct sem_t
|
||||
{
|
||||
_pthread_fastlock __sem_lock;
|
||||
int __sem_value;
|
||||
void* __sem_waiting;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(sigset_t.size == 128);
|
||||
assert(sigaction_t.size == 140);
|
||||
assert(sem_t.size == 16);
|
||||
}
|
||||
|
||||
extern (C)
|
||||
{
|
||||
int pthread_create(pthread_t*, void*, void* (*)(void*), void*);
|
||||
int pthread_join(pthread_t, void**);
|
||||
int pthread_kill(pthread_t, int);
|
||||
pthread_t pthread_self();
|
||||
int pthread_equal(pthread_t, pthread_t);
|
||||
int sem_wait(sem_t*);
|
||||
int sem_init(sem_t*, int, uint);
|
||||
int sem_post(sem_t*);
|
||||
int sched_yield();
|
||||
int sigfillset(sigset_t*);
|
||||
int sigdelset(sigset_t*, int);
|
||||
int sigaction(int, sigaction_t*, sigaction_t*);
|
||||
int sigsuspend(sigset_t*);
|
||||
}
|
||||
|
||||
class ThreadError : Error
|
||||
{
|
||||
this(char[] s)
|
||||
{
|
||||
super("Thread error: " ~ s);
|
||||
}
|
||||
}
|
||||
|
||||
class Thread
|
||||
{
|
||||
this()
|
||||
{
|
||||
}
|
||||
|
||||
this(int (*fp)(void *), void *arg)
|
||||
{
|
||||
this.fp = fp;
|
||||
this.arg = arg;
|
||||
}
|
||||
|
||||
this(int delegate() dg)
|
||||
{
|
||||
this.dg = dg;
|
||||
}
|
||||
|
||||
pthread_t id;
|
||||
void* stackBottom;
|
||||
void* stackTop;
|
||||
|
||||
void start()
|
||||
{
|
||||
if (state != TS.INITIAL)
|
||||
error("already started");
|
||||
|
||||
synchronized (threadLock)
|
||||
{
|
||||
for (int i = 0; 1; i++)
|
||||
{
|
||||
if (i == allThreads.length)
|
||||
error("too many threads");
|
||||
if (!allThreads[i])
|
||||
{ allThreads[i] = this;
|
||||
idx = i;
|
||||
if (i >= allThreadsDim)
|
||||
allThreadsDim = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
nthreads++;
|
||||
}
|
||||
|
||||
state = TS.RUNNING;
|
||||
int result;
|
||||
//printf("creating thread x%x\n", this);
|
||||
result = pthread_create(&id, null, &threadstart, this);
|
||||
if (result)
|
||||
{ state = TS.TERMINATED;
|
||||
allThreads[idx] = null;
|
||||
idx = -1;
|
||||
error("failed to start"); // BUG: should report errno
|
||||
}
|
||||
//printf("t = x%x, id = %d\n", this, id);
|
||||
}
|
||||
|
||||
int run()
|
||||
{
|
||||
if (fp)
|
||||
return fp(arg);
|
||||
else if (dg)
|
||||
return dg();
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
if (this === getThis())
|
||||
error("wait on self");
|
||||
if (state == TS.RUNNING)
|
||||
{ int result;
|
||||
void *value;
|
||||
|
||||
result = pthread_join(id, &value);
|
||||
if (result)
|
||||
error("failed to wait");
|
||||
}
|
||||
}
|
||||
|
||||
void wait(uint milliseconds)
|
||||
{
|
||||
wait();
|
||||
/+ not implemented
|
||||
if (this === getThis())
|
||||
error("wait on self");
|
||||
if (state == TS.RUNNING)
|
||||
{ DWORD dw;
|
||||
|
||||
dw = WaitForSingleObject(hdl, milliseconds);
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
enum TS
|
||||
{
|
||||
INITIAL,
|
||||
RUNNING,
|
||||
TERMINATED
|
||||
}
|
||||
|
||||
TS getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
enum PRIORITY
|
||||
{
|
||||
INCREASE,
|
||||
DECREASE,
|
||||
IDLE,
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
void setPriority(PRIORITY p)
|
||||
{
|
||||
/+ not implemented
|
||||
int nPriority;
|
||||
|
||||
switch (p)
|
||||
{
|
||||
case PRIORITY.INCREASE:
|
||||
nPriority = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||
break;
|
||||
case PRIORITY.DECREASE:
|
||||
nPriority = THREAD_PRIORITY_BELOW_NORMAL;
|
||||
break;
|
||||
case PRIORITY.IDLE:
|
||||
nPriority = THREAD_PRIORITY_IDLE;
|
||||
break;
|
||||
case PRIORITY.CRITICAL:
|
||||
nPriority = THREAD_PRIORITY_TIME_CRITICAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SetThreadPriority(hdl, nPriority) == THREAD_PRIORITY_ERROR_RETURN)
|
||||
error("set priority");
|
||||
+/
|
||||
}
|
||||
|
||||
int isSelf()
|
||||
{
|
||||
//printf("id = %d, self = %d\n", id, pthread_self());
|
||||
return pthread_equal(pthread_self(), id);
|
||||
}
|
||||
|
||||
static Thread getThis()
|
||||
{
|
||||
pthread_t id;
|
||||
Thread result;
|
||||
|
||||
//printf("getThis(), allThreadsDim = %d\n", allThreadsDim);
|
||||
synchronized (threadLock)
|
||||
{
|
||||
id = pthread_self();
|
||||
//printf("id = %d\n", id);
|
||||
for (int i = 0; i < allThreadsDim; i++)
|
||||
{
|
||||
Thread t = allThreads[i];
|
||||
//printf("allThreads[%d] = x%x, id = %d\n", i, t, (t ? t.id : 0));
|
||||
if (t && pthread_equal(id, t.id))
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("didn't find it\n");
|
||||
assert(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Thread[] getAll()
|
||||
{
|
||||
return allThreads[0 .. allThreadsDim];
|
||||
}
|
||||
|
||||
void pause()
|
||||
{
|
||||
if (state == TS.RUNNING)
|
||||
{ int result;
|
||||
|
||||
result = pthread_kill(id, SIGUSR1);
|
||||
if (result)
|
||||
error("cannot pause");
|
||||
else
|
||||
sem_wait(&flagSuspend); // wait for acknowledgement
|
||||
}
|
||||
else
|
||||
error("cannot pause");
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (state == TS.RUNNING)
|
||||
{ int result;
|
||||
|
||||
result = pthread_kill(id, SIGUSR2);
|
||||
if (result)
|
||||
error("cannot resume");
|
||||
}
|
||||
else
|
||||
error("cannot resume");
|
||||
}
|
||||
|
||||
static void pauseAll()
|
||||
{
|
||||
if (nthreads > 1)
|
||||
{
|
||||
Thread tthis = getThis();
|
||||
int npause = 0;
|
||||
|
||||
for (int i = 0; i < allThreadsDim; i++)
|
||||
{ Thread t;
|
||||
|
||||
t = allThreads[i];
|
||||
if (t && t !== tthis && t.state == TS.RUNNING)
|
||||
{ int result;
|
||||
|
||||
result = pthread_kill(t.id, SIGUSR1);
|
||||
if (result)
|
||||
getThis().error("cannot pause");
|
||||
else
|
||||
npause++; // count of paused threads
|
||||
}
|
||||
|
||||
// Wait for each paused thread to acknowledge
|
||||
while (npause--)
|
||||
{
|
||||
sem_wait(&flagSuspend);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resumeAll()
|
||||
{
|
||||
if (nthreads > 1)
|
||||
{
|
||||
Thread tthis = getThis();
|
||||
|
||||
for (int i = 0; i < allThreadsDim; i++)
|
||||
{ Thread t;
|
||||
|
||||
t = allThreads[i];
|
||||
if (t && t !== tthis && t.state == TS.RUNNING)
|
||||
t.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void yield()
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
static uint nthreads = 1;
|
||||
|
||||
private:
|
||||
|
||||
static uint allThreadsDim;
|
||||
static Object threadLock;
|
||||
static Thread[/*_POSIX_THREAD_THREADS_MAX*/ 100] allThreads;
|
||||
static sem_t flagSuspend;
|
||||
|
||||
TS state;
|
||||
int idx = -1; // index into allThreads[]
|
||||
int flags = 0;
|
||||
|
||||
int (*fp)(void *);
|
||||
void *arg;
|
||||
|
||||
int delegate() dg;
|
||||
|
||||
void error(char[] msg)
|
||||
{
|
||||
throw new ThreadError(msg);
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
* This is just a wrapper to interface between C rtl and Thread.run().
|
||||
*/
|
||||
|
||||
extern (C) static void *threadstart(void *p)
|
||||
{
|
||||
Thread t = cast(Thread)p;
|
||||
int result;
|
||||
|
||||
debug (thread) printf("Starting thread x%x (%d)\n", t, t.idx);
|
||||
|
||||
// Need to set t.id here, because thread is off and running
|
||||
// before pthread_create() sets it.
|
||||
t.id = pthread_self();
|
||||
|
||||
t.stackBottom = getESP();
|
||||
try
|
||||
{
|
||||
result = t.run();
|
||||
}
|
||||
catch (Object o)
|
||||
{
|
||||
printf("Error: ");
|
||||
o.print();
|
||||
result = 1;
|
||||
}
|
||||
|
||||
debug (thread) printf("Ending thread %d\n", t.idx);
|
||||
t.state = TS.TERMINATED;
|
||||
allThreads[t.idx] = null;
|
||||
t.idx = -1;
|
||||
nthreads--;
|
||||
return (void*)result;
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Create a Thread for global main().
|
||||
*/
|
||||
|
||||
static this()
|
||||
{
|
||||
threadLock = new Object();
|
||||
|
||||
Thread t = new Thread();
|
||||
|
||||
t.state = TS.RUNNING;
|
||||
t.id = pthread_self();
|
||||
t.stackBottom = (void*)__libc_stack_end;
|
||||
synchronized (threadLock)
|
||||
{
|
||||
assert(!allThreads[0]);
|
||||
allThreads[0] = t;
|
||||
allThreadsDim = 1;
|
||||
t.idx = 0;
|
||||
}
|
||||
|
||||
/* Install signal handlers so we can suspend/resume threads
|
||||
*/
|
||||
|
||||
int result;
|
||||
sigaction_t sigact;
|
||||
result = sigfillset(&sigact.sa_mask);
|
||||
if (result)
|
||||
goto Lfail;
|
||||
sigact.sa_handler = pauseHandler;
|
||||
result = sigaction(SIGUSR1, &sigact, null);
|
||||
if (result)
|
||||
goto Lfail;
|
||||
sigact.sa_handler = resumeHandler;
|
||||
result = sigaction(SIGUSR2, &sigact, null);
|
||||
if (result)
|
||||
goto Lfail;
|
||||
|
||||
result = sem_init(&flagSuspend, 0, 0);
|
||||
if (result)
|
||||
goto Lfail;
|
||||
|
||||
return;
|
||||
|
||||
Lfail:
|
||||
getThis().error("cannot initialize threads");
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* This gets called when a thread gets SIGUSR1.
|
||||
*/
|
||||
|
||||
extern (C) static void pauseHandler(int sig)
|
||||
{ int result;
|
||||
|
||||
// Save all registers on the stack so they'll be scanned by the GC
|
||||
asm
|
||||
{
|
||||
pusha ;
|
||||
}
|
||||
|
||||
assert(sig == SIGUSR1);
|
||||
sem_post(&flagSuspend);
|
||||
|
||||
sigset_t sigmask;
|
||||
result = sigfillset(&sigmask);
|
||||
assert(result == 0);
|
||||
result = sigdelset(&sigmask, SIGUSR2);
|
||||
assert(result == 0);
|
||||
|
||||
Thread t = getThis();
|
||||
t.stackTop = getESP();
|
||||
t.flags &= ~1;
|
||||
while (1)
|
||||
{
|
||||
sigsuspend(&sigmask); // suspend until SIGUSR2
|
||||
if (t.flags & 1) // ensure it was resumeHandler()
|
||||
break;
|
||||
}
|
||||
|
||||
// Restore all registers
|
||||
asm
|
||||
{
|
||||
popa ;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* This gets called when a thread gets SIGUSR2.
|
||||
*/
|
||||
|
||||
extern (C) static void resumeHandler(int sig)
|
||||
{
|
||||
Thread t = getThis();
|
||||
|
||||
t.flags |= 1;
|
||||
}
|
||||
|
||||
static void* getESP()
|
||||
{
|
||||
asm
|
||||
{ naked ;
|
||||
mov EAX,ESP ;
|
||||
ret ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -45,5 +45,6 @@ int main(char[][] args)
|
|||
printf("args.length = %d\n", args.length);
|
||||
for (int i = 0; i < args.length; i++)
|
||||
printf("args[%d] = '%s'\n", i, (char *)args[i]);
|
||||
printf("Success\n!");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Makefile to build D runtime library phobos.lib.
|
||||
# Makefile to build D runtime library phobos.lib for Win32
|
||||
# Designed to work with \dm\bin\make.exe
|
||||
# Targets:
|
||||
# make
|
||||
|
@ -68,8 +68,8 @@ OBJS= assert.obj deh.obj switch.obj complex.obj gcstats.obj \
|
|||
|
||||
HDR=mars.h
|
||||
|
||||
SRC= switch.d complex.c critical.c fpu.d \
|
||||
aa.c vaa.c interface.c minit.asm
|
||||
SRC= switch.d complex.c critical.c errno.c alloca.d cmath.d \
|
||||
minit.asm linux.d deh2.d date.d linuxextern.d llmath.d
|
||||
|
||||
SRC2=deh.c object.d gc.d math.d c\stdio.d c\stdlib.d time.d monitor.c arraycat.d \
|
||||
string.d windows.d path.d
|
||||
|
@ -77,7 +77,7 @@ SRC2=deh.c object.d gc.d math.d c\stdio.d c\stdlib.d time.d monitor.c arraycat.d
|
|||
SRC3=invariant.d assert.d RegExp.d dmain2.d dateparse.d \
|
||||
outofmemory.d syserror.d
|
||||
|
||||
SRC4=dchar.d ctype.d achar.d aaA.d adi.d file.d compiler.d system.d \
|
||||
SRC4= ctype.d achar.d aaA.d adi.d file.d compiler.d system.d \
|
||||
moduleinit.d cast.d math.d qsort.d
|
||||
|
||||
SRC5=outbuffer.d unittest.d stream.d ctype.d regexp.d random.d adi.d \
|
||||
|
@ -94,7 +94,7 @@ SRC7=ti_wchar.d ti_uint.d ti_short.d ti_ushort.d \
|
|||
|
||||
SRC8=crc32.d stdint.d conv.d gcstats.d
|
||||
|
||||
phobos.lib : $(OBJS) minit.obj gc2\dmgc.lib makefile
|
||||
phobos.lib : $(OBJS) minit.obj gc2\dmgc.lib win32.mak
|
||||
lib -c phobos.lib $(OBJS) minit.obj gc2\dmgc.lib
|
||||
|
||||
aaA.obj : aaA.d
|
||||
|
@ -131,9 +131,9 @@ ti_C.obj : ti_C.d
|
|||
ti_char.obj : ti_char.d
|
||||
ti_int.obj : ti_int.d
|
||||
|
||||
zip : makefile $(HDR) $(SRC) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) \
|
||||
zip : win32.mak linux.mak $(HDR) $(SRC) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) \
|
||||
$(SRC8)
|
||||
zip32 -u phobos makefile $(HDR)
|
||||
zip32 -u phobos win32.mak linux.mak $(HDR)
|
||||
zip32 -u phobos $(SRC)
|
||||
zip32 -u phobos $(SRC2)
|
||||
zip32 -u phobos $(SRC3)
|
Loading…
Add table
Add a link
Reference in a new issue