phobos 0.65

This commit is contained in:
Brad Roberts 2007-09-10 02:16:36 +00:00
parent dba8d9bcaa
commit c7ea30e9a0
31 changed files with 2923 additions and 162 deletions

18
adi.d
View file

@ -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
View 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
View 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 ;
}
}

View file

@ -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
View file

@ -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.

View file

@ -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
View file

@ -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

View file

@ -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
View file

@ -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
View 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;
}

View file

@ -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
View 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

View file

@ -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]);

View file

@ -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
View 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
View 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
View 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
View 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 ;
}
}

View file

@ -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];
}

View file

@ -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)();

View file

@ -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

View file

@ -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);
}
+/
}
/*****************************************

View file

@ -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
View file

@ -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", "*.*"));

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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 ;
}
}
}
}

View file

@ -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;
}

View file

@ -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)