diff --git a/adi.d b/adi.d index c09dce75e..f11bc3ebc 100644 --- a/adi.d +++ b/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; } diff --git a/alloca.d b/alloca.d new file mode 100644 index 000000000..f78c8324b --- /dev/null +++ b/alloca.d @@ -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 ; + } +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmath.d b/cmath.d new file mode 100644 index 000000000..15b36533e --- /dev/null +++ b/cmath.d @@ -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 ; + } +} diff --git a/critical.c b/critical.c index 28e2357ba..f9633b2e7 100644 --- a/critical.c +++ b/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 /****************************************** @@ -65,3 +69,76 @@ void _STD_critical_term() DeleteCriticalSection(&critical_section.cs); } } + +#endif + +/* ================================= linux ============================ */ + +#if linux + +#include + +/****************************************** + * 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 + diff --git a/date.d b/date.d index 271bb7162..15d97703b 100644 --- a/date.d +++ b/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. diff --git a/dateparse.d b/dateparse.d index 5c6b4747c..4ba9c17b9 100644 --- a/dateparse.d +++ b/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; } diff --git a/deh.c b/deh.c index 857494472..f25bfbe44 100644 --- a/deh.c +++ b/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 #include #include #include + +/* ======================== Win32 =============================== */ + +#if _WIN32 + #include #include @@ -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 diff --git a/dmain2.d b/dmain2.d index 293bef4bd..1fc43502a 100644 --- a/dmain2.d +++ b/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; } diff --git a/file.d b/file.d index 7548082d7..b254bd5da 100644 --- a/file.d +++ b/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; +} + +} diff --git a/gc2/gclinux.d b/gc2/gclinux.d new file mode 100644 index 000000000..317cf0605 --- /dev/null +++ b/gc2/gclinux.d @@ -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 + 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 + 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; +} diff --git a/gc2/gcx.d b/gc2/gcx.d index 9e6da3459..b153b4370 100644 --- a/gc2/gcx.d +++ b/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); } } } diff --git a/gc2/linux.mak b/gc2/linux.mak new file mode 100644 index 000000000..52d568028 --- /dev/null +++ b/gc2/linux.mak @@ -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 diff --git a/gc2/testgc.d b/gc2/testgc.d index a6b2593d9..0629348cb 100644 --- a/gc2/testgc.d +++ b/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]); diff --git a/gc2/makefile b/gc2/win32.mak similarity index 78% rename from gc2/makefile rename to gc2/win32.mak index 71bd607b0..316c029e8 100644 --- a/gc2/makefile +++ b/gc2/win32.mak @@ -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) diff --git a/linux.d b/linux.d new file mode 100644 index 000000000..1a02c8c1f --- /dev/null +++ b/linux.d @@ -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*); +} diff --git a/linux.mak b/linux.mak new file mode 100644 index 000000000..cc8812219 --- /dev/null +++ b/linux.mak @@ -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) diff --git a/linuxextern.d b/linuxextern.d new file mode 100644 index 000000000..56c2b474e --- /dev/null +++ b/linuxextern.d @@ -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; +} + diff --git a/llmath.d b/llmath.d new file mode 100644 index 000000000..cb3644b14 --- /dev/null +++ b/llmath.d @@ -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 ; + } +} + + diff --git a/math2.d b/math2.d index c58de266f..9c82646fc 100644 --- a/math2.d +++ b/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]; } diff --git a/moduleinit.d b/moduleinit.d index e4db5c015..b693527c2 100644 --- a/moduleinit.d +++ b/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)(); diff --git a/monitor.c b/monitor.c index 1bf6a25f0..2a394624e 100644 --- a/monitor.c +++ b/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 #include #include + +/* =============================== Win32 ============================ */ + +#if _WIN32 + #include #include "mars.h" @@ -79,3 +84,82 @@ void _d_monitorrelease(Object *h) h->monitor = 0; } } + +#endif + +/* =============================== linux ============================ */ + +#if linux + +#include + +#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 diff --git a/outbuffer.d b/outbuffer.d index 87b51aaef..1d5d7740c 100644 --- a/outbuffer.d +++ b/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); + } + +/ } /***************************************** diff --git a/outofmemory.d b/outofmemory.d index ad4b038a6..6762e09a9 100644 --- a/outofmemory.d +++ b/outofmemory.d @@ -10,7 +10,7 @@ class OutOfMemory : Object } } -extern (C) static void _d_OutOfMemory() +extern (C) void _d_OutOfMemory() { throw (OutOfMemory)(void *)OutOfMemory.classinfo.init; } diff --git a/path.d b/path.d index c4c3916ae..f5cf86af5 100644 --- a/path.d +++ b/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", "*.*")); diff --git a/random.d b/random.d index 9f5b69ead..a88af26d1 100644 --- a/random.d +++ b/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 diff --git a/regexp.d b/regexp.d index 77f4224c3..6dc1b4ec8 100644 --- a/regexp.d +++ b/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: diff --git a/stream.d b/stream.d index 58c119b01..1bb047804 100644 --- a/stream.d +++ b/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; diff --git a/string.d b/string.d index 1df2d6590..2a194981e 100644 --- a/string.d +++ b/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]; diff --git a/thread.d b/thread.d index 622827f94..b4f65d0a5 100644 --- a/thread.d +++ b/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 ; + } + } +} + + +} diff --git a/unittest.d b/unittest.d index d081c0869..c944d56f6 100644 --- a/unittest.d +++ b/unittest.d @@ -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; } diff --git a/makefile b/win32.mak similarity index 88% rename from makefile rename to win32.mak index 86509e1d5..3bf49a6d5 100644 --- a/makefile +++ b/win32.mak @@ -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)