diff options
| author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-09 23:56:49 +0100 |
|---|---|---|
| committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-12 23:18:25 +0100 |
| commit | a2e540bf0150b1a2f05924ce6d5210dc0048471d (patch) | |
| tree | b46d2d634704cfea7200180a0d03ddc5303aab0b /libphobos/libdruntime | |
| parent | f4fa0b7d493a4ba217d989d3df75bbe3730874fc (diff) | |
d: Merge dmd, druntime c7902293d7, phobos 03aeafd20
D front-end changes:
- Import dmd v2.110.0-rc.1.
- An error is now given for subtracting pointers of different
types.
D runtime changes:
- Import druntime v2.110.0-rc.1.
Phobos changes:
- Import phobos v2.110.0-rc.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd c7902293d7.
* dmd/VERSION: Bump version to v2.110.0-rc.1.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime c7902293d7.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Rename
core/thread/fiber.d to core/thread/fiber/package.d. Add
core/thread/fiber/base.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 63fdb282f.
gcc/testsuite/ChangeLog:
* gdc.dg/asm3.d: Adjust test.
* gdc.dg/torture/pr96435.d: Adjust test.
Diffstat (limited to 'libphobos/libdruntime')
44 files changed, 1433 insertions, 1069 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index e5884c6a798..b145d1bd659 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -c57da0cf5945cfb45eed06f1fd820435cda3ee3a +c7902293d7df9d02546562cb09fc8439004a70d1 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 7713c8cf5a8..fd117eca202 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -210,7 +210,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/sync/barrier.d core/sync/condition.d core/sync/config.d \ core/sync/event.d core/sync/exception.d core/sync/mutex.d \ core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \ - core/thread/context.d core/thread/fiber.d core/thread/osthread.d \ + core/thread/context.d core/thread/fiber/base.d \ + core/thread/fiber/package.d core/thread/osthread.d \ core/thread/package.d core/thread/threadbase.d \ core/thread/threadgroup.d core/thread/types.d core/time.d \ core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index f4d55523bfa..2d87c8162af 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -234,16 +234,17 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ core/sync/condition.lo core/sync/config.lo core/sync/event.lo \ core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \ core/sync/rwmutex.lo core/sync/semaphore.lo \ - core/thread/context.lo core/thread/fiber.lo \ - core/thread/osthread.lo core/thread/package.lo \ - core/thread/threadbase.lo core/thread/threadgroup.lo \ - core/thread/types.lo core/time.lo core/vararg.lo \ - core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \ - gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \ - gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \ - gcc/sections/elf.lo gcc/sections/macho.lo \ - gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \ - gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \ + core/thread/context.lo core/thread/fiber/base.lo \ + core/thread/fiber/package.lo core/thread/osthread.lo \ + core/thread/package.lo core/thread/threadbase.lo \ + core/thread/threadgroup.lo core/thread/types.lo core/time.lo \ + core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \ + gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \ + gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \ + gcc/sections/common.lo gcc/sections/elf.lo \ + gcc/sections/macho.lo gcc/sections/package.lo \ + gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \ + gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \ gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \ object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \ rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \ @@ -891,7 +892,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/sync/barrier.d core/sync/condition.d core/sync/config.d \ core/sync/event.d core/sync/exception.d core/sync/mutex.d \ core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \ - core/thread/context.d core/thread/fiber.d core/thread/osthread.d \ + core/thread/context.d core/thread/fiber/base.d \ + core/thread/fiber/package.d core/thread/osthread.d \ core/thread/package.d core/thread/threadbase.d \ core/thread/threadgroup.d core/thread/types.d core/time.d \ core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \ @@ -1352,7 +1354,11 @@ core/thread/$(am__dirstamp): @$(MKDIR_P) core/thread @: > core/thread/$(am__dirstamp) core/thread/context.lo: core/thread/$(am__dirstamp) -core/thread/fiber.lo: core/thread/$(am__dirstamp) +core/thread/fiber/$(am__dirstamp): + @$(MKDIR_P) core/thread/fiber + @: > core/thread/fiber/$(am__dirstamp) +core/thread/fiber/base.lo: core/thread/fiber/$(am__dirstamp) +core/thread/fiber/package.lo: core/thread/fiber/$(am__dirstamp) core/thread/osthread.lo: core/thread/$(am__dirstamp) core/thread/package.lo: core/thread/$(am__dirstamp) core/thread/threadbase.lo: core/thread/$(am__dirstamp) @@ -2147,6 +2153,8 @@ mostlyclean-compile: -rm -f core/sys/windows/stdc/*.lo -rm -f core/thread/*.$(OBJEXT) -rm -f core/thread/*.lo + -rm -f core/thread/fiber/*.$(OBJEXT) + -rm -f core/thread/fiber/*.lo -rm -f etc/valgrind/*.$(OBJEXT) -rm -f etc/valgrind/*.lo -rm -f gcc/*.$(OBJEXT) @@ -2312,6 +2320,7 @@ clean-libtool: -rm -rf core/sys/windows/.libs core/sys/windows/_libs -rm -rf core/sys/windows/stdc/.libs core/sys/windows/stdc/_libs -rm -rf core/thread/.libs core/thread/_libs + -rm -rf core/thread/fiber/.libs core/thread/fiber/_libs -rm -rf etc/valgrind/.libs etc/valgrind/_libs -rm -rf gcc/.libs gcc/_libs -rm -rf gcc/sections/.libs gcc/sections/_libs @@ -2478,6 +2487,7 @@ distclean-generic: -rm -f core/sys/windows/$(am__dirstamp) -rm -f core/sys/windows/stdc/$(am__dirstamp) -rm -f core/thread/$(am__dirstamp) + -rm -f core/thread/fiber/$(am__dirstamp) -rm -f etc/valgrind/$(am__dirstamp) -rm -f gcc/$(am__dirstamp) -rm -f gcc/sections/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d index c197262384f..c9bde27da69 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -21,8 +21,12 @@ else version (TVOS) else version (WatchOS) version = Darwin; -debug(trace) import core.stdc.stdio : printf; -debug(info) import core.stdc.stdio : printf; +debug (trace) debug = needPrintf; +debug (info) debug = needPrintf; + +debug (needPrintf) +private int printf(Args...)(scope const char* fmt, scope const Args args) + => __ctfe ? 0 : imported!"core.stdc.stdio".printf(fmt, args); extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name, char* output_buffer, @@ -2128,7 +2132,7 @@ pure @safe: } name = dst[beg .. nameEnd]; - debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr ); + debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.getSlice.ptr ); if ( 'M' == front ) popFront(); // has 'this' pointer diff --git a/libphobos/libdruntime/core/gc/gcinterface.d b/libphobos/libdruntime/core/gc/gcinterface.d index 173e6abecff..c4e78bae782 100644 --- a/libphobos/libdruntime/core/gc/gcinterface.d +++ b/libphobos/libdruntime/core/gc/gcinterface.d @@ -193,28 +193,33 @@ interface GC // ARRAY FUNCTIONS /** - * Get the current used capacity of an array block. Note that this is only - * needed if you are about to change the array used size and need to deal - * with the memory that is about to go away. For appending or shrinking - * arrays that have no destructors, you probably don't need this function. + * Get the current used capacity of an array block. + * + * Note that this is only needed if you are about to change the array used + * size and need to deal with the memory that is about to go away. For + * appending or shrinking arrays that have no destructors, you probably + * don't need this function. + * * Params: * ptr = The pointer to check. This can be an interior pointer, but if it * is beyond the end of the used space, the return value may not be * valid. - * atomic = If true, the value is fetched atomically (for shared arrays) - * Returns: Current array slice, or null if the pointer does not point to a - * valid appendable GC block. + * atomic = The value is fetched atomically (for shared arrays) + * Returns: + * Current array slice, or null if the pointer does not point to a valid + * appendable GC block. */ void[] getArrayUsed(void *ptr, bool atomic = false) nothrow; /** - * Expand the array used size. Used for appending and expanding the length - * of the array slice. If the operation can be performed without - * reallocating, the function succeeds. Newly expanded data is not - * initialized. + * Expand the array used size in place. + * + * Used for appending and expanding the length of the array slice. If the + * operation can be performed without reallocating, the function succeeds. + * Newly expanded data is not initialized. Slices that do not point at + * expandable GC blocks cannot be affected, and this function will always + * return false. * - * slices that do not point at expandable GC blocks cannot be affected, and - * this function will always return false. * Params: * slice = the slice to attempt expanding in place. * newUsed = the size that should be stored as used. @@ -225,37 +230,43 @@ interface GC bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @safe; /** - * Expand the array capacity. Used for reserving space that can be used for - * appending. If the operation can be performed without reallocating, the - * function succeeds. The used size is not changed. + * Expand the array capacity in place. + * + * Used for reserving space that can be used for appending. If the + * operation can be performed without reallocating, the function succeeds. + * The used size is not changed. Slices that do not point at expandable GC + * blocks cannot be affected, and this function will always return zero. * - * slices that do not point at expandable GC blocks cannot be affected, and - * this function will always return zero. * Params: * slice = the slice to attempt reserving capacity for. * request = the requested size to expand to. Includes the existing data. * Passing a value less than the current array size will result in no * changes, but will return the current capacity. - * atomic = if true, the array may be shared between threads, and this - * operation should be done atomically. - * Returns: resulting capacity size, 0 if the operation could not be performed. + * atomic = The array may be shared between threads, and this operation + * should be done atomically. + * + * Returns: + * Resulting capacity size or 0 if the operation could not be performed. */ size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @safe; /** - * Shrink used space of a slice. Unlike the other array functions, the - * array slice passed in is the target slice, and the existing used space - * is passed separately. This is to discourage code that ends up with a - * slice to dangling valid data. + * Shrink used space of a slice in place. + * + * Unlike the other array functions, the array slice passed in is the + * target slice, and the existing used space is passed separately. This is + * to discourage code that ends up with a slice to dangling valid data. + * * If slice.ptr[0 .. existingUsed] does not point to the end of a valid GC * appendable slice, then the operation fails. + * * Params: * slice = The proposed valid slice data. * existingUsed = The amount of data in the block (starting at slice.ptr) * that is currently valid in the array. If this amount does not match * the current used size, the operation fails. - * atomic = If true, the slice may be shared between threads, and the - * operation should be atomic. + * atomic = The slice may be shared between threads, and the operation + * should be atomic. * Returns: true if successful. */ bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow; diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d index 8098597a72a..c9761ece24b 100644 --- a/libphobos/libdruntime/core/internal/array/construction.d +++ b/libphobos/libdruntime/core/internal/array/construction.d @@ -48,7 +48,7 @@ Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* ma import core.stdc.stdint : uintptr_t; debug(PRINTF) import core.stdc.stdio : printf; - debug(PRINTF) printf("_d_arrayctor(from = %p,%d) size = %d\n", from.ptr, from.length, T.sizeof); + debug(PRINTF) printf("_d_arrayctor(from = %p,%zd) size = %zd\n", from.ptr, from.length, T.sizeof); void[] vFrom = (cast(void*) from.ptr)[0..from.length]; void[] vTo = (cast(void*) to.ptr)[0..to.length]; @@ -513,7 +513,7 @@ version (D_ProfileGC) */ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trusted { - debug(PRINTF) printf("_d_newarraymTX(dims.length = %d)\n", dims.length); + debug(PRINTF) printf("_d_newarraymTX(dims.length = %zd)\n", dims.length); if (dims.length == 0) return null; @@ -547,7 +547,7 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust } auto result = __allocateInnerArray(dims); - debug(PRINTF) printf("result = %llx\n", result.ptr); + debug(PRINTF) printf("result = %p\n", result.ptr); return (cast(U*) result.ptr)[0 .. dims[0]]; } diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d index 36cf6891feb..43e50acacb7 100644 --- a/libphobos/libdruntime/core/internal/atomic.d +++ b/libphobos/libdruntime/core/internal/atomic.d @@ -10,7 +10,7 @@ module core.internal.atomic; -import core.atomic : MemoryOrder, has128BitCAS; +import core.atomic : has128BitCAS, MemoryOrder; version (DigitalMars) { @@ -912,7 +912,7 @@ else version (GNU) { static if (GNU_Thread_Model == ThreadModel.Posix) { - import core.sys.posix.pthread; + import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t; alias atomicMutexHandle = pthread_mutex_t; pragma(mangle, "pthread_mutex_init") int fakePureMutexInit(pthread_mutex_t*, pthread_mutexattr_t*); @@ -921,7 +921,7 @@ else version (GNU) } else static if (GNU_Thread_Model == ThreadModel.Win32) { - import core.sys.windows.winbase; + import core.sys.windows.winbase : CRITICAL_SECTION; alias atomicMutexHandle = CRITICAL_SECTION; pragma(mangle, "InitializeCriticalSection") int fakePureMutexInit(CRITICAL_SECTION*); diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d index 76948c8bde8..9d120e576c9 100644 --- a/libphobos/libdruntime/core/internal/dassert.d +++ b/libphobos/libdruntime/core/internal/dassert.d @@ -14,7 +14,7 @@ * * Copyright: D Language Foundation 2018 - 2020 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/dassert.d, _dassert.d) + * Source: $(DRUNTIMESRC core/internal/_dassert.d) * Documentation: https://dlang.org/phobos/core_internal_dassert.html */ module core.internal.dassert; diff --git a/libphobos/libdruntime/core/internal/gc/blkcache.d b/libphobos/libdruntime/core/internal/gc/blkcache.d index 908f66656e1..b141a6959f7 100644 --- a/libphobos/libdruntime/core/internal/gc/blkcache.d +++ b/libphobos/libdruntime/core/internal/gc/blkcache.d @@ -8,6 +8,8 @@ module core.internal.gc.blkcache; import core.memory; import core.attribute; +debug (PRINTF) import core.stdc.stdio : printf; + alias BlkInfo = GC.BlkInfo; alias BlkAttr = GC.BlkAttr; @@ -98,17 +100,17 @@ void processGCMarks(void* data, scope IsMarkedDg isMarked) nothrow // called after the mark routine to eliminate block cache data when it // might be ready to sweep - debug(PRINTF) printf("processing GC Marks, %x\n", cache); + debug(PRINTF) printf("processing GC Marks, %p\n", cache); debug(PRINTF) foreach (i; 0 .. N_CACHE_BLOCKS) { - printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr); + printf("cache entry %d has base ptr %p\tsize %zd\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr); } auto cache_end = cache + N_CACHE_BLOCKS; for (;cache < cache_end; ++cache) { if (cache.base != null && isMarked(cache.base) == IsMarked.no) { - debug(PRINTF) printf("clearing cache entry at %x\n", cache.base); + debug(PRINTF) printf("clearing cache entry at %p\n", cache.base); cache.base = null; // clear that data. } } @@ -250,7 +252,7 @@ debug(PRINTF) printf("CACHE: \n"); foreach (i; 0 .. N_CACHE_BLOCKS) { - printf(" %d\taddr:% .8x\tsize:% .10d\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr); + printf(" %d\taddr:% .8p\tsize:% .10zd\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr); } } } diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d index 6ddd4c1fb60..40e361c50f1 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d @@ -503,7 +503,7 @@ class ConservativeGC : GC assert(size != 0); debug(PRINTF) - printf("GC::malloc(gcx = %p, size = %d bits = %x, ti = %s)\n", gcx, size, bits, debugTypeName(ti).ptr); + printf("GC::malloc(gcx = %p, size = %zd bits = %x, ti = %s)\n", gcx, size, bits, debugTypeName(ti).ptr); assert(gcx); //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self()); @@ -876,7 +876,7 @@ class ConservativeGC : GC // private void freeNoSync(void *p) nothrow @nogc { - debug(PRINTF) printf("Freeing %p\n", cast(size_t) p); + debug(PRINTF) printf("Freeing %#zx\n", cast(size_t) p); assert (p); Pool* pool; @@ -891,7 +891,7 @@ class ConservativeGC : GC pagenum = pool.pagenumOf(p); - debug(PRINTF) printf("pool base = %p, PAGENUM = %d of %d, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]); + debug(PRINTF) printf("pool base = %p, PAGENUM = %zd of %zd, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]); debug(PRINTF) if (pool.isLargeObject) printf("Block size = %d\n", pool.bPageOffsets[pagenum]); bin = pool.pagetable[pagenum]; @@ -1763,7 +1763,7 @@ struct Gcx long apiTime = mallocTime + reallocTime + freeTime + extendTime + otherTime + lockTime; printf("\tGC API: %lld ms\n", toDuration(apiTime).total!"msecs"); - sprintf(apitxt.ptr, " API%5ld ms", toDuration(apiTime).total!"msecs"); + sprintf(apitxt.ptr, " API%5lld ms", toDuration(apiTime).total!"msecs"); } printf("GC summary:%5lld MB,%5lld GC%5lld ms, Pauses%5lld ms <%5lld ms%s\n", @@ -2169,7 +2169,7 @@ struct Gcx */ void* bigAlloc(size_t size, ref size_t alloc_size, uint bits, const TypeInfo ti = null) nothrow { - debug(PRINTF) printf("In bigAlloc. Size: %d\n", size); + debug(PRINTF) printf("In bigAlloc. Size: %zd\n", size); LargeObjectPool* pool; size_t pn; @@ -2233,7 +2233,7 @@ struct Gcx debug(PRINTF) printFreeInfo(&pool.base); auto p = pool.baseAddr + pn * PAGESIZE; - debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %d\n", p, pool.pagetable[pn], npages); + debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %zd\n", p, pool.pagetable[pn], npages); invalidate(p[0 .. size], 0xF1, true); alloc_size = npages * PAGESIZE; //debug(PRINTF) printf("\tp = %p\n", p); @@ -3575,7 +3575,7 @@ Lmark: version (Posix) { - import core.sys.posix.signal; + import core.sys.posix.signal : pthread_sigmask, SIG_BLOCK, SIG_SETMASK, sigfillset, sigset_t; // block all signals, scanBackground inherits this mask. // see https://issues.dlang.org/show_bug.cgi?id=20256 sigset_t new_mask, old_mask; @@ -3659,9 +3659,12 @@ Lmark: if (atomicLoad(busyThreads) == 0) return; - debug(PARALLEL_PRINTF) + version (Posix) debug (PARALLEL_PRINTF) + { + import core.sys.posix.pthread : pthread_self, pthread_t; pthread_t threadId = pthread_self(); - debug(PARALLEL_PRINTF) printf("scanBackground thread %d start\n", threadId); + printf("scanBackground thread %d start\n", threadId); + } ScanRange!precise rng; alias toscan = scanStack!precise; @@ -3677,13 +3680,16 @@ Lmark: busyThreads.atomicOp!"+="(1); if (toscan.popLocked(rng)) { - debug(PARALLEL_PRINTF) printf("scanBackground thread %d scanning range [%p,%lld] from stack\n", threadId, - rng.pbot, cast(long) (rng.ptop - rng.pbot)); + version (Posix) debug (PARALLEL_PRINTF) + { + printf("scanBackground thread %d scanning range [%p,%lld] from stack\n", + threadId, rng.pbot, cast(long) (rng.ptop - rng.pbot)); + } mark!(precise, true, true)(rng); } busyThreads.atomicOp!"-="(1); } - debug(PARALLEL_PRINTF) printf("scanBackground thread %d done\n", threadId); + version (Posix) debug (PARALLEL_PRINTF) printf("scanBackground thread %d done\n", threadId); } } @@ -4203,12 +4209,12 @@ struct Pool debugTypeName(ti).ptr, p, bitmap, cast(ulong)element_size); debug(PRINTF) for (size_t i = 0; i < element_size/((void*).sizeof); i++) - printf("%d", (bitmap[i/(8*size_t.sizeof)] >> (i%(8*size_t.sizeof))) & 1); + printf("%zd", (bitmap[i/(8*size_t.sizeof)] >> (i%(8*size_t.sizeof))) & 1); debug(PRINTF) printf("\n"); if (tocopy * (void*).sizeof < s) // better safe than sorry: if allocated more, assume pointers inside { - debug(PRINTF) printf(" Appending %d pointer bits\n", s/(void*).sizeof - tocopy); + debug(PRINTF) printf(" Appending %zd pointer bits\n", s/(void*).sizeof - tocopy); is_pointer.setRange(offset/(void*).sizeof + tocopy, s/(void*).sizeof - tocopy); } } @@ -4734,7 +4740,7 @@ debug(PRINTF) void printFreeInfo(Pool* pool) nothrow if (pool.pagetable[i] >= Bins.B_FREE) nReallyFree++; } - printf("Pool %p: %d really free, %d supposedly free\n", pool, nReallyFree, pool.freepages); + printf("Pool %p: %d really free, %zd supposedly free\n", pool, nReallyFree, pool.freepages); } debug(PRINTF) @@ -4743,7 +4749,7 @@ void printGCBits(GCBits* bits) for (size_t i = 0; i < bits.nwords; i++) { if (i % 32 == 0) printf("\n\t"); - printf("%x ", bits.data[i]); + printf("%zx ", bits.data[i]); } printf("\n"); } diff --git a/libphobos/libdruntime/core/internal/gc/os.d b/libphobos/libdruntime/core/internal/gc/os.d index 0db1753575b..bde90e95228 100644 --- a/libphobos/libdruntime/core/internal/gc/os.d +++ b/libphobos/libdruntime/core/internal/gc/os.d @@ -33,8 +33,8 @@ else version (Posix) else version (WatchOS) version = Darwin; - import core.sys.posix.sys.mman; import core.stdc.stdlib; + import core.sys.posix.sys.mman : MAP_ANON, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, mmap, munmap, PROT_READ, PROT_WRITE; /// Possible results for the wait_pid() function. @@ -74,9 +74,9 @@ else version (Posix) return ChildStatus.done; } - public import core.sys.posix.unistd: pid_t, fork; - import core.sys.posix.sys.wait: waitpid, WNOHANG; - import core.stdc.errno: errno, EINTR, ECHILD; + public import core.sys.posix.unistd : fork, pid_t; + import core.stdc.errno : ECHILD, EINTR, errno; + import core.sys.posix.sys.wait : waitpid, WNOHANG; //version = GC_Use_Alloc_MMap; } @@ -292,12 +292,18 @@ else version (Posix) { ulong os_physical_mem(bool avail) nothrow @nogc { - import core.sys.posix.unistd; + static import core.sys.posix.unistd; + import core.sys.posix.unistd : _SC_PAGESIZE, _SC_PHYS_PAGES, sysconf; const pageSize = sysconf(_SC_PAGESIZE); - static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms + static if (__traits(compiles, core.sys.posix.unistd._SC_AVPHYS_PAGES)) // not available on all platforms + { + import core.sys.posix.unistd : _SC_AVPHYS_PAGES; const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES; + } else + { const sc = _SC_PHYS_PAGES; + } const pages = sysconf(sc); return pageSize * pages; } diff --git a/libphobos/libdruntime/core/internal/postblit.d b/libphobos/libdruntime/core/internal/postblit.d index ed4ec1b7ff4..3377ba5c3d9 100644 --- a/libphobos/libdruntime/core/internal/postblit.d +++ b/libphobos/libdruntime/core/internal/postblit.d @@ -5,7 +5,7 @@ License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). (See accompanying file LICENSE) - Source: $(DRUNTIMESRC core/_internal/_destruction.d) + Source: $(DRUNTIMESRC core/_internal/_postblit.d) */ module core.internal.postblit; diff --git a/libphobos/libdruntime/core/internal/qsort.d b/libphobos/libdruntime/core/internal/qsort.d index 0040f6b4609..fce1067812c 100644 --- a/libphobos/libdruntime/core/internal/qsort.d +++ b/libphobos/libdruntime/core/internal/qsort.d @@ -12,6 +12,8 @@ module core.internal.qsort; import core.stdc.stdlib; +debug (qsort) import core.stdc.stdio : printf; + version (OSX) version = Darwin; else version (iOS) diff --git a/libphobos/libdruntime/core/internal/string.d b/libphobos/libdruntime/core/internal/string.d index 7bb319ecfa5..e5abce47db8 100644 --- a/libphobos/libdruntime/core/internal/string.d +++ b/libphobos/libdruntime/core/internal/string.d @@ -4,7 +4,7 @@ * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Sean Kelly, Walter Bright - * Source: $(DRUNTIMESRC rt/util/_string.d) + * Source: $(DRUNTIMESRC core/internal/_string.d) */ module core.internal.string; diff --git a/libphobos/libdruntime/core/internal/utf.d b/libphobos/libdruntime/core/internal/utf.d index 9808b9947f5..71c32119473 100644 --- a/libphobos/libdruntime/core/internal/utf.d +++ b/libphobos/libdruntime/core/internal/utf.d @@ -21,6 +21,8 @@ module core.internal.utf; +debug (utf) import core.stdc.stdio : printf; + extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure; /******************************* diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index 182886175a6..dc765e7ecad 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -4,7 +4,7 @@ * Copyright: Copyright Sean Kelly 2005 - 2009. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Sean Kelly - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/runtime.d, _runtime.d) + * Source: $(DRUNTIMESRC core/_runtime.d) * Documentation: https://dlang.org/phobos/core_runtime.html */ @@ -575,7 +575,9 @@ extern (C) UnitTestResult runModuleUnitTests() static if (__traits(compiles, new LibBacktrace(0))) { - import core.sys.posix.signal; // segv handler + // segv handler + import core.sys.posix.signal : SA_RESETHAND, SA_SIGINFO, sigaction, sigaction_t, SIGBUS, sigfillset, siginfo_t, + SIGSEGV; static extern (C) void unittestSegvHandler(int signum, siginfo_t* info, void* ptr) { diff --git a/libphobos/libdruntime/core/stdc/errno.d b/libphobos/libdruntime/core/stdc/errno.d index 0430e6b33e9..db347e404b4 100644 --- a/libphobos/libdruntime/core/stdc/errno.d +++ b/libphobos/libdruntime/core/stdc/errno.d @@ -8,7 +8,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Alex Rønne Petersen - * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/errno.d + * Source: $(DRUNTIMESRC core/stdc/_errno.d) * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d index 8afb68f8585..d3ee2cae8e5 100644 --- a/libphobos/libdruntime/core/stdc/stdio.d +++ b/libphobos/libdruntime/core/stdc/stdio.d @@ -9,7 +9,7 @@ * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen - * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/stdio.d + * Source: $(DRUNTIMESRC core/stdc/_stdio.d) * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/sync/condition.d b/libphobos/libdruntime/core/sync/condition.d index afcfd744f0a..51ab7b5aa31 100644 --- a/libphobos/libdruntime/core/sync/condition.d +++ b/libphobos/libdruntime/core/sync/condition.d @@ -35,10 +35,11 @@ version (Windows) } else version (Posix) { - import core.sync.config; import core.stdc.errno; - import core.sys.posix.pthread; - import core.sys.posix.time; + import core.sync.config; + import core.sys.posix.pthread : pthread_cond_broadcast, pthread_cond_destroy, pthread_cond_init, + pthread_cond_signal, pthread_cond_t, pthread_cond_timedwait, pthread_cond_wait; + import core.sys.posix.time : timespec; } else { @@ -127,8 +128,12 @@ class Condition { m_assocMutex = m; } - static if ( is( typeof( pthread_condattr_setclock ) ) ) + static if ( is( typeof( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) ) { + import core.sys.posix.pthread : pthread_condattr_destroy, pthread_condattr_init, + pthread_condattr_setclock; + import core.sys.posix.sys.types : pthread_condattr_t; + import core.sys.posix.time : CLOCK_MONOTONIC; () @trusted { pthread_condattr_t attr = void; @@ -620,9 +625,9 @@ private: unittest { - import core.thread; import core.sync.mutex; import core.sync.semaphore; + import core.thread; void testNotify() @@ -786,9 +791,9 @@ unittest unittest { - import core.thread; import core.sync.mutex; import core.sync.semaphore; + import core.thread; void testNotify() diff --git a/libphobos/libdruntime/core/sync/config.d b/libphobos/libdruntime/core/sync/config.d index 39f7a8cd769..f68502464e0 100644 --- a/libphobos/libdruntime/core/sync/config.d +++ b/libphobos/libdruntime/core/sync/config.d @@ -18,16 +18,16 @@ module core.sync.config; version (Posix) { - import core.sys.posix.pthread; - import core.sys.posix.time; - import core.sys.posix.sys.time; + import core.sys.posix.sys.time : gettimeofday, timeval; + import core.sys.posix.time : timespec; import core.time; void mktspec( ref timespec t ) nothrow @nogc { - static if ( is (typeof ( pthread_condattr_setclock ) ) ) + static if ( is (typeof ( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) ) { + import core.sys.posix.time : clock_gettime, CLOCK_MONOTONIC; clock_gettime( CLOCK_MONOTONIC, &t ); } else diff --git a/libphobos/libdruntime/core/sync/event.d b/libphobos/libdruntime/core/sync/event.d index 048607f6ed2..6278218f673 100644 --- a/libphobos/libdruntime/core/sync/event.d +++ b/libphobos/libdruntime/core/sync/event.d @@ -20,17 +20,19 @@ version (Windows) } else version (Posix) { - import core.sys.posix.pthread; - import core.sys.posix.sys.types; - import core.sys.posix.time; + import core.sys.posix.pthread : pthread_cond_broadcast, pthread_cond_destroy, pthread_cond_init, + pthread_cond_timedwait, pthread_cond_wait, pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock, + pthread_mutex_unlock; + import core.sys.posix.sys.types : pthread_cond_t, pthread_mutex_t; + import core.sys.posix.time : timespec; } else { static assert(false, "Platform not supported"); } -import core.time; import core.internal.abort : abort; +import core.time; /** * represents an event. Clients of an event are suspended while waiting @@ -105,8 +107,13 @@ nothrow @nogc: return; pthread_mutex_init(cast(pthread_mutex_t*) &m_mutex, null) == 0 || abort("Error: pthread_mutex_init failed."); - static if ( is( typeof( pthread_condattr_setclock ) ) ) + + static if ( is( typeof( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) ) { + import core.sys.posix.pthread : CLOCK_MONOTONIC, pthread_condattr_destroy, pthread_condattr_init, + pthread_condattr_setclock; + import core.sys.posix.sys.types : pthread_condattr_t; + pthread_condattr_t attr = void; pthread_condattr_init(&attr) == 0 || abort("Error: pthread_condattr_init failed."); @@ -320,7 +327,8 @@ private: unittest { - import core.thread, core.atomic; + import core.atomic; + import core.thread; scope event = new Event(true, false); int numThreads = 10; diff --git a/libphobos/libdruntime/core/sync/mutex.d b/libphobos/libdruntime/core/sync/mutex.d index 5f547cd04ef..8993f85071b 100644 --- a/libphobos/libdruntime/core/sync/mutex.d +++ b/libphobos/libdruntime/core/sync/mutex.d @@ -26,7 +26,10 @@ version (Windows) } else version (Posix) { - import core.sys.posix.pthread; + import core.sys.posix.pthread : pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock, + PTHREAD_MUTEX_RECURSIVE, pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutexattr_destroy, + pthread_mutexattr_init, pthread_mutexattr_settype; + import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t; } else { @@ -344,8 +347,8 @@ unittest // Test @nogc usage. @system @nogc nothrow unittest { - import core.stdc.stdlib : malloc, free; import core.lifetime : emplace; + import core.stdc.stdlib : free, malloc; auto mtx = cast(shared Mutex) malloc(__traits(classInstanceSize, Mutex)); emplace(mtx); diff --git a/libphobos/libdruntime/core/sync/rwmutex.d b/libphobos/libdruntime/core/sync/rwmutex.d index 07c5bdbe360..cb581621ec5 100644 --- a/libphobos/libdruntime/core/sync/rwmutex.d +++ b/libphobos/libdruntime/core/sync/rwmutex.d @@ -21,11 +21,6 @@ import core.sync.condition; import core.sync.mutex; import core.memory; -version (Posix) -{ - import core.sys.posix.pthread; -} - //////////////////////////////////////////////////////////////////////////////// // ReadWriteMutex diff --git a/libphobos/libdruntime/core/sync/semaphore.d b/libphobos/libdruntime/core/sync/semaphore.d index cf2bddbf106..a4dae042ee3 100644 --- a/libphobos/libdruntime/core/sync/semaphore.d +++ b/libphobos/libdruntime/core/sync/semaphore.d @@ -37,17 +37,18 @@ version (Windows) } else version (Darwin) { - import core.sync.config; import core.stdc.errno; - import core.sys.posix.time; - import core.sys.darwin.mach.semaphore; + import core.sync.config; + import core.sys.darwin.mach.kern_return : KERN_ABORTED, KERN_OPERATION_TIMED_OUT; + import core.sys.darwin.mach.semaphore : mach_task_self, mach_timespec_t, semaphore_create, semaphore_destroy, + semaphore_signal, semaphore_t, semaphore_timedwait, semaphore_wait, SYNC_POLICY_FIFO; } else version (Posix) { - import core.sync.config; import core.stdc.errno; - import core.sys.posix.pthread; - import core.sys.posix.semaphore; + import core.sync.config; + import core.sys.posix.semaphore : sem_destroy, sem_init, sem_post, sem_t, sem_timedwait, sem_trywait, sem_wait; + import core.sys.posix.time : clock_gettime, CLOCK_REALTIME, timespec; } else { @@ -253,8 +254,6 @@ class Semaphore } else version (Posix) { - import core.sys.posix.time : clock_gettime, CLOCK_REALTIME; - timespec t = void; clock_gettime( CLOCK_REALTIME, &t ); mvtspec( t, period ); @@ -364,7 +363,8 @@ protected: unittest { - import core.thread, core.atomic; + import core.atomic; + import core.thread; void testWait() { diff --git a/libphobos/libdruntime/core/sys/darwin/mach/stab.d b/libphobos/libdruntime/core/sys/darwin/mach/stab.d index ecdb4560a68..7125cf28143 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/stab.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/stab.d @@ -24,7 +24,7 @@ * * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Mathias 'Geod24' Lang - * Source: $(DRUNTIMESRC core/sys/darwin/mach/_nlist.d) + * Source: $(DRUNTIMESRC core/sys/darwin/mach/_stab.d) */ module core.sys.darwin.mach.stab; diff --git a/libphobos/libdruntime/core/sys/linux/sys/procfs.d b/libphobos/libdruntime/core/sys/linux/sys/procfs.d index 6a113e172dc..ceea5223ed3 100644 --- a/libphobos/libdruntime/core/sys/linux/sys/procfs.d +++ b/libphobos/libdruntime/core/sys/linux/sys/procfs.d @@ -7,9 +7,8 @@ module core.sys.linux.sys.procfs; +version (linux): + import core.sys.posix.sys.types : pid_t; -version (linux) -{ - alias lwpid_t = pid_t; -} +alias lwpid_t = pid_t; diff --git a/libphobos/libdruntime/core/sys/posix/spawn.d b/libphobos/libdruntime/core/sys/posix/spawn.d index 789053396f0..081270b42c5 100644 --- a/libphobos/libdruntime/core/sys/posix/spawn.d +++ b/libphobos/libdruntime/core/sys/posix/spawn.d @@ -4,7 +4,7 @@ * Copyright: Copyright (C) 2018 by The D Language Foundation, All Rights Reserved * Authors: Petar Kirov * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/sys/posix/spawn.d, _spawn.d) + * Source: $(DRUNTIMESRC core/sys/posix/_spawn.d) * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition */ module core.sys.posix.spawn; diff --git a/libphobos/libdruntime/core/sys/posix/stdc/time.d b/libphobos/libdruntime/core/sys/posix/stdc/time.d index d48a0ea3eda..c5a2e1b7182 100644 --- a/libphobos/libdruntime/core/sys/posix/stdc/time.d +++ b/libphobos/libdruntime/core/sys/posix/stdc/time.d @@ -9,7 +9,7 @@ * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen - * Source: $(DRUNTIMESRC core/stdc/_time.d) + * Source: $(DRUNTIMESRC core/sys/posix/stdc/_time.d) * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/sys/windows/dbghelp.d b/libphobos/libdruntime/core/sys/windows/dbghelp.d index 55fbc56a754..fb6fb668672 100644 --- a/libphobos/libdruntime/core/sys/windows/dbghelp.d +++ b/libphobos/libdruntime/core/sys/windows/dbghelp.d @@ -6,7 +6,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Benjamin Thaut, Sean Kelly - * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d) + * Source: $(DRUNTIMESRC core/sys/windows/_dbghelp.d) */ module core.sys.windows.dbghelp; diff --git a/libphobos/libdruntime/core/sys/windows/stdc/time.d b/libphobos/libdruntime/core/sys/windows/stdc/time.d index 97eb4bf1e11..407b92c20a6 100644 --- a/libphobos/libdruntime/core/sys/windows/stdc/time.d +++ b/libphobos/libdruntime/core/sys/windows/stdc/time.d @@ -9,7 +9,7 @@ * (See accompanying file LICENSE) * Authors: Sean Kelly, * Alex Rønne Petersen - * Source: $(DRUNTIMESRC core/stdc/_time.d) + * Source: $(DRUNTIMESRC core/sys/windows/stdc/_time.d) * Standards: ISO/IEC 9899:1999 (E) */ diff --git a/libphobos/libdruntime/core/thread/fiber/base.d b/libphobos/libdruntime/core/thread/fiber/base.d new file mode 100644 index 00000000000..2afc2690261 --- /dev/null +++ b/libphobos/libdruntime/core/thread/fiber/base.d @@ -0,0 +1,1091 @@ +/** + * Base fiber module provides OS-indepedent part of lightweight threads aka fibers. + * + * Copyright: Copyright Sean Kelly 2005 - 2012. + * License: Distributed under the + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + * (See accompanying file LICENSE) + * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak + * Source: $(DRUNTIMESRC core/thread/fiber/base.d) + */ + +/* NOTE: This file has been patched from the original DMD distribution to + * work with the GDC compiler. + */ +module core.thread.fiber.base; + +package: +version (GNU) + import gcc.config; + +import core.thread.fiber; +import core.thread.threadbase; +import core.thread.threadgroup; +import core.thread.types; +import core.thread.context; + +import core.memory : pageSize; + +package +{ + import core.atomic : atomicStore, cas, MemoryOrder; + import core.exception : onOutOfMemoryError; + import core.stdc.stdlib : abort; + + extern (C) void fiber_entryPoint() nothrow + { + FiberBase obj = FiberBase.getThis(); + assert( obj ); + + assert( ThreadBase.getThis().m_curr is obj.m_ctxt ); + atomicStore!(MemoryOrder.raw)(*cast(shared)&ThreadBase.getThis().m_lock, false); + obj.m_ctxt.tstack = obj.m_ctxt.bstack; + obj.m_state = FiberBase.State.EXEC; + + try + { + obj.run(); + } + catch ( Throwable t ) + { + obj.m_unhandled = t; + } + + static if ( __traits( compiles, ucontext_t ) ) + obj.m_ucur = &obj.m_utxt; + + obj.m_state = Fiber.State.TERM; + obj.switchOut(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Fiber +/////////////////////////////////////////////////////////////////////////////// +/* + * Documentation of Fiber internals: + * + * The main routines to implement when porting Fibers to new architectures are + * fiber_switchContext and initStack. Some version constants have to be defined + * for the new platform as well, search for "Fiber Platform Detection and Memory Allocation". + * + * Fibers are based on a concept called 'Context'. A Context describes the execution + * state of a Fiber or main thread which is fully described by the stack, some + * registers and a return address at which the Fiber/Thread should continue executing. + * Please note that not only each Fiber has a Context, but each thread also has got a + * Context which describes the threads stack and state. If you call Fiber fib; fib.call + * the first time in a thread you switch from Threads Context into the Fibers Context. + * If you call fib.yield in that Fiber you switch out of the Fibers context and back + * into the Thread Context. (However, this is not always the case. You can call a Fiber + * from within another Fiber, then you switch Contexts between the Fibers and the Thread + * Context is not involved) + * + * In all current implementations the registers and the return address are actually + * saved on a Contexts stack. + * + * The fiber_switchContext routine has got two parameters: + * void** a: This is the _location_ where we have to store the current stack pointer, + * the stack pointer of the currently executing Context (Fiber or Thread). + * void* b: This is the pointer to the stack of the Context which we want to switch into. + * Note that we get the same pointer here as the one we stored into the void** a + * in a previous call to fiber_switchContext. + * + * In the simplest case, a fiber_switchContext rountine looks like this: + * fiber_switchContext: + * push {return Address} + * push {registers} + * copy {stack pointer} into {location pointed to by a} + * //We have now switch to the stack of a different Context! + * copy {b} into {stack pointer} + * pop {registers} + * pop {return Address} + * jump to {return Address} + * + * The GC uses the value returned in parameter a to scan the Fibers stack. It scans from + * the stack base to that value. As the GC dislikes false pointers we can actually optimize + * this a little: By storing registers which can not contain references to memory managed + * by the GC outside of the region marked by the stack base pointer and the stack pointer + * saved in fiber_switchContext we can prevent the GC from scanning them. + * Such registers are usually floating point registers and the return address. In order to + * implement this, we return a modified stack pointer from fiber_switchContext. However, + * we have to remember that when we restore the registers from the stack! + * + * --------------------------- <= Stack Base + * | Frame | <= Many other stack frames + * | Frame | + * |-------------------------| <= The last stack frame. This one is created by fiber_switchContext + * | registers with pointers | + * | | <= Stack pointer. GC stops scanning here + * | return address | + * |floating point registers | + * --------------------------- <= Real Stack End + * + * fiber_switchContext: + * push {registers with pointers} + * copy {stack pointer} into {location pointed to by a} + * push {return Address} + * push {Floating point registers} + * //We have now switch to the stack of a different Context! + * copy {b} into {stack pointer} + * //We now have to adjust the stack pointer to point to 'Real Stack End' so we can pop + * //the FP registers + * //+ or - depends on if your stack grows downwards or upwards + * {stack pointer} = {stack pointer} +- ({FPRegisters}.sizeof + {return address}.sizeof} + * pop {Floating point registers} + * pop {return Address} + * pop {registers with pointers} + * jump to {return Address} + * + * So the question now is which registers need to be saved? This depends on the specific + * architecture ABI of course, but here are some general guidelines: + * - If a register is callee-save (if the callee modifies the register it must saved and + * restored by the callee) it needs to be saved/restored in switchContext + * - If a register is caller-save it needn't be saved/restored. (Calling fiber_switchContext + * is a function call and the compiler therefore already must save these registers before + * calling fiber_switchContext) + * - Argument registers used for passing parameters to functions needn't be saved/restored + * - The return register needn't be saved/restored (fiber_switchContext hasn't got a return type) + * - All scratch registers needn't be saved/restored + * - The link register usually needn't be saved/restored (but sometimes it must be cleared - + * see below for details) + * - The frame pointer register - if it exists - is usually callee-save + * - All current implementations do not save control registers + * + * What happens on the first switch into a Fiber? We never saved a state for this fiber before, + * but the initial state is prepared in the initStack routine. (This routine will also be called + * when a Fiber is being resetted). initStack must produce exactly the same stack layout as the + * part of fiber_switchContext which saves the registers. Pay special attention to set the stack + * pointer correctly if you use the GC optimization mentioned before. the return Address saved in + * initStack must be the address of fiber_entrypoint. + * + * There's now a small but important difference between the first context switch into a fiber and + * further context switches. On the first switch, Fiber.call is used and the returnAddress in + * fiber_switchContext will point to fiber_entrypoint. The important thing here is that this jump + * is a _function call_, we call fiber_entrypoint by jumping before it's function prologue. On later + * calls, the user used yield() in a function, and therefore the return address points into a user + * function, after the yield call. So here the jump in fiber_switchContext is a _function return_, + * not a function call! + * + * The most important result of this is that on entering a function, i.e. fiber_entrypoint, we + * would have to provide a return address / set the link register once fiber_entrypoint + * returns. Now fiber_entrypoint does never return and therefore the actual value of the return + * address / link register is never read/used and therefore doesn't matter. When fiber_switchContext + * performs a _function return_ the value in the link register doesn't matter either. + * However, the link register will still be saved to the stack in fiber_entrypoint and some + * exception handling / stack unwinding code might read it from this stack location and crash. + * The exact solution depends on your architecture, but see the ARM implementation for a way + * to deal with this issue. + * + * The ARM implementation is meant to be used as a kind of documented example implementation. + * Look there for a concrete example. + * + * FIXME: fiber_entrypoint might benefit from a @noreturn attribute, but D doesn't have one. + */ + +/** + * This class provides a cooperative concurrency mechanism integrated with the + * threading and garbage collection functionality. Calling a fiber may be + * considered a blocking operation that returns when the fiber yields (via + * Fiber.yield()). Execution occurs within the context of the calling thread + * so synchronization is not necessary to guarantee memory visibility so long + * as the same thread calls the fiber each time. Please note that there is no + * requirement that a fiber be bound to one specific thread. Rather, fibers + * may be freely passed between threads so long as they are not currently + * executing. Like threads, a new fiber thread may be created using either + * derivation or composition, as in the following example. + * + * Warning: + * Status registers are not saved by the current implementations. This means + * floating point exception status bits (overflow, divide by 0), rounding mode + * and similar stuff is set per-thread, not per Fiber! + * + * Warning: + * On ARM FPU registers are not saved if druntime was compiled as ARM_SoftFloat. + * If such a build is used on a ARM_SoftFP system which actually has got a FPU + * and other libraries are using the FPU registers (other code is compiled + * as ARM_SoftFP) this can cause problems. Druntime must be compiled as + * ARM_SoftFP in this case. + * + * Authors: Based on a design by Mikola Lysenko. + */ +class FiberBase +{ + /** + * Initializes a fiber object which is associated with a static + * D function. + * + * Params: + * fn = The fiber function. + * sz = The stack size for this fiber. + * guardPageSize = size of the guard page to trap fiber's stack + * overflows. Beware that using this will increase + * the number of mmaped regions on platforms using mmap + * so an OS-imposed limit may be hit. + * + * In: + * fn must not be null. + */ + this( void function() fn, size_t sz, size_t guardPageSize ) nothrow + in + { + assert( fn ); + } + do + { + allocStack( sz, guardPageSize ); + reset( fn ); + } + + + /** + * Initializes a fiber object which is associated with a dynamic + * D function. + * + * Params: + * dg = The fiber function. + * sz = The stack size for this fiber. + * guardPageSize = size of the guard page to trap fiber's stack + * overflows. Beware that using this will increase + * the number of mmaped regions on platforms using mmap + * so an OS-imposed limit may be hit. + * + * In: + * dg must not be null. + */ + this( void delegate() dg, size_t sz, size_t guardPageSize ) nothrow + { + allocStack( sz, guardPageSize ); + reset( cast(void delegate() const) dg ); + } + + + /** + * Cleans up any remaining resources used by this object. + */ + ~this() nothrow @nogc + { + // NOTE: A live reference to this object will exist on its associated + // stack from the first time its call() method has been called + // until its execution completes with State.TERM. Thus, the only + // times this dtor should be called are either if the fiber has + // terminated (and therefore has no active stack) or if the user + // explicitly deletes this object. The latter case is an error + // but is not easily tested for, since State.HOLD may imply that + // the fiber was just created but has never been run. There is + // not a compelling case to create a State.INIT just to offer a + // means of ensuring the user isn't violating this object's + // contract, so for now this requirement will be enforced by + // documentation only. + freeStack(); + } + + + /////////////////////////////////////////////////////////////////////////// + // General Actions + /////////////////////////////////////////////////////////////////////////// + + + /** + * Transfers execution to this fiber object. The calling context will be + * suspended until the fiber calls Fiber.yield() or until it terminates + * via an unhandled exception. + * + * Params: + * rethrow = Rethrow any unhandled exception which may have caused this + * fiber to terminate. + * + * In: + * This fiber must be in state HOLD. + * + * Throws: + * Any exception not handled by the joined thread. + * + * Returns: + * Any exception not handled by this fiber if rethrow = false, null + * otherwise. + */ + // Not marked with any attributes, even though `nothrow @nogc` works + // because it calls arbitrary user code. Most of the implementation + // is already `@nogc nothrow`, but in order for `Fiber.call` to + // propagate the attributes of the user's function, the Fiber + // class needs to be templated. + final Throwable call( Rethrow rethrow = Rethrow.yes ) + { + return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no); + } + + /// ditto + final Throwable call( Rethrow rethrow )() + { + callImpl(); + if ( m_unhandled ) + { + Throwable t = m_unhandled; + m_unhandled = null; + static if ( rethrow ) + throw t; + else + return t; + } + return null; + } + + private void callImpl() nothrow @nogc + in + { + assert( m_state == State.HOLD ); + } + do + { + FiberBase cur = getThis(); + + static if ( __traits( compiles, ucontext_t ) ) + m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt; + + setThis( this ); + this.switchIn(); + setThis( cur ); + + static if ( __traits( compiles, ucontext_t ) ) + m_ucur = null; + + // NOTE: If the fiber has terminated then the stack pointers must be + // reset. This ensures that the stack for this fiber is not + // scanned if the fiber has terminated. This is necessary to + // prevent any references lingering on the stack from delaying + // the collection of otherwise dead objects. The most notable + // being the current object, which is referenced at the top of + // fiber_entryPoint. + if ( m_state == State.TERM ) + { + m_ctxt.tstack = m_ctxt.bstack; + } + } + + /// Flag to control rethrow behavior of $(D $(LREF call)) + enum Rethrow : bool { no, yes } + + /** + * Resets this fiber so that it may be re-used, optionally with a + * new function/delegate. This routine should only be called for + * fibers that have terminated, as doing otherwise could result in + * scope-dependent functionality that is not executed. + * Stack-based classes, for example, may not be cleaned up + * properly if a fiber is reset before it has terminated. + * + * In: + * This fiber must be in state TERM or HOLD. + */ + final void reset() nothrow @nogc + in + { + assert( m_state == State.TERM || m_state == State.HOLD ); + } + do + { + m_ctxt.tstack = m_ctxt.bstack; + m_state = State.HOLD; + initStack(); + m_unhandled = null; + } + + /// ditto + final void reset( void function() fn ) nothrow @nogc + { + reset(); + m_call = fn; + } + + /// ditto + final void reset( void delegate() dg ) nothrow @nogc + { + reset(); + m_call = dg; + } + + /////////////////////////////////////////////////////////////////////////// + // General Properties + /////////////////////////////////////////////////////////////////////////// + + + /// A fiber may occupy one of three states: HOLD, EXEC, and TERM. + enum State + { + /** The HOLD state applies to any fiber that is suspended and ready to + be called. */ + HOLD, + /** The EXEC state will be set for any fiber that is currently + executing. */ + EXEC, + /** The TERM state is set when a fiber terminates. Once a fiber + terminates, it must be reset before it may be called again. */ + TERM + } + + + /** + * Gets the current state of this fiber. + * + * Returns: + * The state of this fiber as an enumerated value. + */ + final @property State state() const @safe pure nothrow @nogc + { + return m_state; + } + + + /////////////////////////////////////////////////////////////////////////// + // Actions on Calling Fiber + /////////////////////////////////////////////////////////////////////////// + + + /** + * Forces a context switch to occur away from the calling fiber. + */ + static void yield() nothrow @nogc + { + FiberBase cur = getThis(); + assert( cur, "Fiber.yield() called with no active fiber" ); + assert( cur.m_state == State.EXEC ); + + static if ( __traits( compiles, ucontext_t ) ) + cur.m_ucur = &cur.m_utxt; + + cur.m_state = State.HOLD; + cur.switchOut(); + cur.m_state = State.EXEC; + } + + + /** + * Forces a context switch to occur away from the calling fiber and then + * throws obj in the calling fiber. + * + * Params: + * t = The object to throw. + * + * In: + * t must not be null. + */ + static void yieldAndThrow( Throwable t ) nothrow @nogc + in + { + assert( t ); + } + do + { + FiberBase cur = getThis(); + assert( cur, "Fiber.yield() called with no active fiber" ); + assert( cur.m_state == State.EXEC ); + + static if ( __traits( compiles, ucontext_t ) ) + cur.m_ucur = &cur.m_utxt; + + cur.m_unhandled = t; + cur.m_state = State.HOLD; + cur.switchOut(); + cur.m_state = State.EXEC; + } + + + /////////////////////////////////////////////////////////////////////////// + // Fiber Accessors + /////////////////////////////////////////////////////////////////////////// + + + /** + * Provides a reference to the calling fiber or null if no fiber is + * currently active. + * + * Returns: + * The fiber object representing the calling fiber or null if no fiber + * is currently active within this thread. The result of deleting this object is undefined. + */ + static FiberBase getThis() @safe nothrow @nogc + { + version (GNU) pragma(inline, false); + return sm_this; + } + + +private: + + // + // Fiber entry point. Invokes the function or delegate passed on + // construction (if any). + // + final void run() + { + m_call(); + } + + // + // Standard fiber data + // + Callable m_call; + bool m_isRunning; + Throwable m_unhandled; + State m_state; + + +protected: + /////////////////////////////////////////////////////////////////////////// + // Stack Management + /////////////////////////////////////////////////////////////////////////// + + + // + // Allocate a new stack for this fiber. + // + abstract void allocStack( size_t sz, size_t guardPageSize ) nothrow; + + + // + // Free this fiber's stack. + // + abstract void freeStack() nothrow @nogc; + + + // + // Initialize the allocated stack. + // Look above the definition of 'class Fiber' for some information about the implementation of this routine + // + abstract void initStack() nothrow @nogc; + + + StackContext* m_ctxt; + size_t m_size; + void* m_pmem; + + static if ( __traits( compiles, ucontext_t ) ) + { + // NOTE: The static ucontext instance is used to represent the context + // of the executing thread. + static ucontext_t sm_utxt = void; + ucontext_t m_utxt = void; + package ucontext_t* m_ucur = null; + } + else static if (GNU_Enable_CET) + { + // When libphobos was built with --enable-cet, these fields need to + // always be present in the Fiber class layout. + import core.sys.posix.ucontext; + static ucontext_t sm_utxt = void; + ucontext_t m_utxt = void; + package ucontext_t* m_ucur = null; + } + + +private: + /////////////////////////////////////////////////////////////////////////// + // Storage of Active Fiber + /////////////////////////////////////////////////////////////////////////// + + + // + // Sets a thread-local reference to the current fiber object. + // + static void setThis( FiberBase f ) nothrow @nogc + { + sm_this = f; + } + + static FiberBase sm_this; + + +private: + /////////////////////////////////////////////////////////////////////////// + // Context Switching + /////////////////////////////////////////////////////////////////////////// + + + // + // Switches into the stack held by this fiber. + // + final void switchIn() nothrow @nogc + { + ThreadBase tobj = ThreadBase.getThis(); + void** oldp = &tobj.m_curr.tstack; + void* newp = m_ctxt.tstack; + + // NOTE: The order of operations here is very important. The current + // stack top must be stored before m_lock is set, and pushContext + // must not be called until after m_lock is set. This process + // is intended to prevent a race condition with the suspend + // mechanism used for garbage collection. If it is not followed, + // a badly timed collection could cause the GC to scan from the + // bottom of one stack to the top of another, or to miss scanning + // a stack that still contains valid data. The old stack pointer + // oldp will be set again before the context switch to guarantee + // that it points to exactly the correct stack location so the + // successive pop operations will succeed. + *oldp = getStackTop(); + atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); + tobj.pushContext( m_ctxt ); + + fiber_switchContext( oldp, newp ); + + // NOTE: As above, these operations must be performed in a strict order + // to prevent Bad Things from happening. + tobj.popContext(); + atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); + tobj.m_curr.tstack = tobj.m_curr.bstack; + } + + + // + // Switches out of the current stack and into the enclosing stack. + // + final void switchOut() nothrow @nogc + { + ThreadBase tobj = ThreadBase.getThis(); + void** oldp = &m_ctxt.tstack; + void* newp = tobj.m_curr.within.tstack; + + // NOTE: The order of operations here is very important. The current + // stack top must be stored before m_lock is set, and pushContext + // must not be called until after m_lock is set. This process + // is intended to prevent a race condition with the suspend + // mechanism used for garbage collection. If it is not followed, + // a badly timed collection could cause the GC to scan from the + // bottom of one stack to the top of another, or to miss scanning + // a stack that still contains valid data. The old stack pointer + // oldp will be set again before the context switch to guarantee + // that it points to exactly the correct stack location so the + // successive pop operations will succeed. + *oldp = getStackTop(); + atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); + + fiber_switchContext( oldp, newp ); + + // NOTE: As above, these operations must be performed in a strict order + // to prevent Bad Things from happening. + // NOTE: If use of this fiber is multiplexed across threads, the thread + // executing here may be different from the one above, so get the + // current thread handle before unlocking, etc. + tobj = ThreadBase.getThis(); + atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); + tobj.m_curr.tstack = tobj.m_curr.bstack; + } +} + +/// +unittest { + int counter; + + class DerivedFiber : Fiber + { + this() + { + super( &run ); + } + + private : + void run() + { + counter += 2; + } + } + + void fiberFunc() + { + counter += 4; + Fiber.yield(); + counter += 8; + } + + // create instances of each type + Fiber derived = new DerivedFiber(); + Fiber composed = new Fiber( &fiberFunc ); + + assert( counter == 0 ); + + derived.call(); + assert( counter == 2, "Derived fiber increment." ); + + composed.call(); + assert( counter == 6, "First composed fiber increment." ); + + counter += 16; + assert( counter == 22, "Calling context increment." ); + + composed.call(); + assert( counter == 30, "Second composed fiber increment." ); + + // since each fiber has run to completion, each should have state TERM + assert( derived.state == Fiber.State.TERM ); + assert( composed.state == Fiber.State.TERM ); +} + +version (unittest) +{ + import core.thread.fiber: Fiber; +} + +version (CoreUnittest) +{ + class TestFiber : Fiber + { + this() + { + super(&run); + } + + void run() + { + foreach (i; 0 .. 1000) + { + sum += i; + Fiber.yield(); + } + } + + enum expSum = 1000 * 999 / 2; + size_t sum; + } + + void runTen() + { + TestFiber[10] fibs; + foreach (ref fib; fibs) + fib = new TestFiber(); + + bool cont; + do { + cont = false; + foreach (fib; fibs) { + if (fib.state == Fiber.State.HOLD) + { + fib.call(); + cont |= fib.state != Fiber.State.TERM; + } + } + } while (cont); + + foreach (fib; fibs) + { + assert(fib.sum == TestFiber.expSum); + } + } +} + + +// Single thread running separate fibers +unittest +{ + runTen(); +} + + +// Multiple threads running separate fibers +unittest +{ + auto group = new ThreadGroup(); + foreach (_; 0 .. 4) + { + group.create(&runTen); + } + group.joinAll(); +} + + +// Multiple threads running shared fibers +version (PPC) version = UnsafeFiberMigration; +version (PPC64) version = UnsafeFiberMigration; +version (OSX) +{ + version (X86) version = UnsafeFiberMigration; + version (X86_64) version = UnsafeFiberMigration; + version (AArch64) version = UnsafeFiberMigration; +} + +version (UnsafeFiberMigration) +{ + // XBUG: core.thread fibers are supposed to be safe to migrate across + // threads, however, there is a problem: GCC always assumes that the + // address of thread-local variables don't change while on a given stack. + // In consequence, migrating fibers between threads currently is an unsafe + // thing to do, and will break on some targets (possibly PR26461). +} +else +{ + version = FiberMigrationUnittest; +} + +version (FiberMigrationUnittest) +unittest +{ + shared bool[10] locks; + TestFiber[10] fibs; + + void runShared() + { + bool cont; + do { + cont = false; + foreach (idx; 0 .. 10) + { + if (cas(&locks[idx], false, true)) + { + if (fibs[idx].state == Fiber.State.HOLD) + { + fibs[idx].call(); + cont |= fibs[idx].state != Fiber.State.TERM; + } + locks[idx] = false; + } + else + { + cont = true; + } + } + } while (cont); + } + + foreach (ref fib; fibs) + { + fib = new TestFiber(); + } + + auto group = new ThreadGroup(); + foreach (_; 0 .. 4) + { + group.create(&runShared); + } + group.joinAll(); + + foreach (fib; fibs) + { + assert(fib.sum == TestFiber.expSum); + } +} + + +// Test exception handling inside fibers. +unittest +{ + enum MSG = "Test message."; + string caughtMsg; + (new Fiber({ + try + { + throw new Exception(MSG); + } + catch (Exception e) + { + caughtMsg = e.msg; + } + })).call(); + assert(caughtMsg == MSG); +} + + +unittest +{ + int x = 0; + + (new Fiber({ + x++; + })).call(); + assert( x == 1 ); +} + +nothrow unittest +{ + new Fiber({}).call!(Fiber.Rethrow.no)(); +} + +unittest +{ + new Fiber({}).call(Fiber.Rethrow.yes); + new Fiber({}).call(Fiber.Rethrow.no); +} + +unittest +{ + enum MSG = "Test message."; + + try + { + (new Fiber(function() { + throw new Exception( MSG ); + })).call(); + assert( false, "Expected rethrown exception." ); + } + catch ( Throwable t ) + { + assert( t.msg == MSG ); + } +} + +// Test exception chaining when switching contexts in finally blocks. +unittest +{ + static void throwAndYield(string msg) { + try { + throw new Exception(msg); + } finally { + Fiber.yield(); + } + } + + static void fiber(string name) { + try { + try { + throwAndYield(name ~ ".1"); + } finally { + throwAndYield(name ~ ".2"); + } + } catch (Exception e) { + assert(e.msg == name ~ ".1"); + assert(e.next); + assert(e.next.msg == name ~ ".2"); + assert(!e.next.next); + } + } + + auto first = new Fiber(() => fiber("first")); + auto second = new Fiber(() => fiber("second")); + first.call(); + second.call(); + first.call(); + second.call(); + first.call(); + second.call(); + assert(first.state == Fiber.State.TERM); + assert(second.state == Fiber.State.TERM); +} + +// Test Fiber resetting +unittest +{ + static string method; + + static void foo() + { + method = "foo"; + } + + void bar() + { + method = "bar"; + } + + static void expect(Fiber fib, string s) + { + assert(fib.state == Fiber.State.HOLD); + fib.call(); + assert(fib.state == Fiber.State.TERM); + assert(method == s); method = null; + } + auto fib = new Fiber(&foo); + expect(fib, "foo"); + + fib.reset(); + expect(fib, "foo"); + + fib.reset(&foo); + expect(fib, "foo"); + + fib.reset(&bar); + expect(fib, "bar"); + + fib.reset(function void(){method = "function";}); + expect(fib, "function"); + + fib.reset(delegate void(){method = "delegate";}); + expect(fib, "delegate"); +} + +// Test unsafe reset in hold state +unittest +{ + auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096); + foreach (_; 0 .. 10) + { + fib.call(); + assert(fib.state == Fiber.State.HOLD); + fib.reset(); + } +} + +// stress testing GC stack scanning +unittest +{ + import core.memory; + import core.thread.osthread : Thread; + import core.time : dur; + + static void unreferencedThreadObject() + { + static void sleep() { Thread.sleep(dur!"msecs"(100)); } + auto thread = new Thread(&sleep).start(); + } + unreferencedThreadObject(); + GC.collect(); + + static class Foo + { + this(int value) + { + _value = value; + } + + int bar() + { + return _value; + } + + int _value; + } + + static void collect() + { + auto foo = new Foo(2); + assert(foo.bar() == 2); + GC.collect(); + Fiber.yield(); + GC.collect(); + assert(foo.bar() == 2); + } + + auto fiber = new Fiber(&collect); + + fiber.call(); + GC.collect(); + fiber.call(); + + // thread reference + auto foo = new Foo(2); + + void collect2() + { + assert(foo.bar() == 2); + GC.collect(); + Fiber.yield(); + GC.collect(); + assert(foo.bar() == 2); + } + + fiber = new Fiber(&collect2); + + fiber.call(); + GC.collect(); + fiber.call(); + + static void recurse(size_t cnt) + { + --cnt; + Fiber.yield(); + if (cnt) + { + auto fib = new Fiber(() { recurse(cnt); }); + fib.call(); + GC.collect(); + fib.call(); + } + } + fiber = new Fiber(() { recurse(20); }); + fiber.call(); +} diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber/package.d index e02733bd970..d10a25d683c 100644 --- a/libphobos/libdruntime/core/thread/fiber.d +++ b/libphobos/libdruntime/core/thread/fiber/package.d @@ -1,12 +1,12 @@ /** - * The fiber module provides OS-indepedent lightweight threads aka fibers. + * The fiber module provides lightweight threads aka fibers. * * Copyright: Copyright Sean Kelly 2005 - 2012. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak - * Source: $(DRUNTIMESRC core/thread/fiber.d) + * Source: $(DRUNTIMESRC core/thread/fiber/package.d) */ /* NOTE: This file has been patched from the original DMD distribution to @@ -14,10 +14,11 @@ */ module core.thread.fiber; +import core.thread.context; +import core.thread.fiber.base : fiber_entryPoint, FiberBase; import core.thread.threadbase; import core.thread.threadgroup; import core.thread.types; -import core.thread.context; import core.memory : pageSize; @@ -28,7 +29,6 @@ import core.memory : pageSize; version (GNU) { import gcc.builtins; - import gcc.config; version (GNU_StackGrowsDown) version = StackGrowsDown; } @@ -40,12 +40,12 @@ else version (Windows) { - import core.stdc.stdlib : malloc, free; + import core.stdc.stdlib : free, malloc; import core.sys.windows.winbase; import core.sys.windows.winnt; } -private +package { version (D_InlineAsm_X86) { @@ -208,7 +208,7 @@ private // a version identifier. Please note that this is considered // an obsolescent feature according to the POSIX spec, so a // custom solution is still preferred. - import core.sys.posix.ucontext; + import core.sys.posix.ucontext : getcontext, makecontext, MINSIGSTKSZ, swapcontext, ucontext_t; } } } @@ -217,46 +217,20 @@ private // Fiber Entry Point and Context Switch /////////////////////////////////////////////////////////////////////////////// -private +package { import core.atomic : atomicStore, cas, MemoryOrder; import core.exception : onOutOfMemoryError; import core.stdc.stdlib : abort; - extern (C) void fiber_entryPoint() nothrow + // Look above the definition of 'class Fiber' for some information about the implementation of this routine + version (AsmExternal) { - Fiber obj = Fiber.getThis(); - assert( obj ); - - assert( ThreadBase.getThis().m_curr is obj.m_ctxt ); - atomicStore!(MemoryOrder.raw)(*cast(shared)&ThreadBase.getThis().m_lock, false); - obj.m_ctxt.tstack = obj.m_ctxt.bstack; - obj.m_state = Fiber.State.EXEC; - - try - { - obj.run(); - } - catch ( Throwable t ) - { - obj.m_unhandled = t; - } - - static if ( __traits( compiles, ucontext_t ) ) - obj.m_ucur = &obj.m_utxt; - - obj.m_state = Fiber.State.TERM; - obj.switchOut(); + extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc; + version (AArch64) + extern (C) void fiber_trampoline() nothrow; } - - // Look above the definition of 'class Fiber' for some information about the implementation of this routine - version (AsmExternal) - { - extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc; - version (AArch64) - extern (C) void fiber_trampoline() nothrow; - } - else + else extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc { // NOTE: The data pushed and popped in this routine must match the @@ -602,7 +576,7 @@ private * * Authors: Based on a design by Mikola Lysenko. */ -class Fiber +class Fiber : FiberBase { /////////////////////////////////////////////////////////////////////////// // Initialization @@ -644,14 +618,8 @@ class Fiber */ this( void function() fn, size_t sz = pageSize * defaultStackPages, size_t guardPageSize = pageSize ) nothrow - in - { - assert( fn ); - } - do { - allocStack( sz, guardPageSize ); - reset( fn ); + super( fn, sz, guardPageSize ); } @@ -673,238 +641,7 @@ class Fiber this( void delegate() dg, size_t sz = pageSize * defaultStackPages, size_t guardPageSize = pageSize ) nothrow { - allocStack( sz, guardPageSize ); - reset( cast(void delegate() const) dg ); - } - - - /** - * Cleans up any remaining resources used by this object. - */ - ~this() nothrow @nogc - { - // NOTE: A live reference to this object will exist on its associated - // stack from the first time its call() method has been called - // until its execution completes with State.TERM. Thus, the only - // times this dtor should be called are either if the fiber has - // terminated (and therefore has no active stack) or if the user - // explicitly deletes this object. The latter case is an error - // but is not easily tested for, since State.HOLD may imply that - // the fiber was just created but has never been run. There is - // not a compelling case to create a State.INIT just to offer a - // means of ensuring the user isn't violating this object's - // contract, so for now this requirement will be enforced by - // documentation only. - freeStack(); - } - - - /////////////////////////////////////////////////////////////////////////// - // General Actions - /////////////////////////////////////////////////////////////////////////// - - - /** - * Transfers execution to this fiber object. The calling context will be - * suspended until the fiber calls Fiber.yield() or until it terminates - * via an unhandled exception. - * - * Params: - * rethrow = Rethrow any unhandled exception which may have caused this - * fiber to terminate. - * - * In: - * This fiber must be in state HOLD. - * - * Throws: - * Any exception not handled by the joined thread. - * - * Returns: - * Any exception not handled by this fiber if rethrow = false, null - * otherwise. - */ - // Not marked with any attributes, even though `nothrow @nogc` works - // because it calls arbitrary user code. Most of the implementation - // is already `@nogc nothrow`, but in order for `Fiber.call` to - // propagate the attributes of the user's function, the Fiber - // class needs to be templated. - final Throwable call( Rethrow rethrow = Rethrow.yes ) - { - return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no); - } - - /// ditto - final Throwable call( Rethrow rethrow )() - { - callImpl(); - if ( m_unhandled ) - { - Throwable t = m_unhandled; - m_unhandled = null; - static if ( rethrow ) - throw t; - else - return t; - } - return null; - } - - private void callImpl() nothrow @nogc - in - { - assert( m_state == State.HOLD ); - } - do - { - Fiber cur = getThis(); - - static if ( __traits( compiles, ucontext_t ) ) - m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt; - - setThis( this ); - this.switchIn(); - setThis( cur ); - - static if ( __traits( compiles, ucontext_t ) ) - m_ucur = null; - - // NOTE: If the fiber has terminated then the stack pointers must be - // reset. This ensures that the stack for this fiber is not - // scanned if the fiber has terminated. This is necessary to - // prevent any references lingering on the stack from delaying - // the collection of otherwise dead objects. The most notable - // being the current object, which is referenced at the top of - // fiber_entryPoint. - if ( m_state == State.TERM ) - { - m_ctxt.tstack = m_ctxt.bstack; - } - } - - /// Flag to control rethrow behavior of $(D $(LREF call)) - enum Rethrow : bool { no, yes } - - /** - * Resets this fiber so that it may be re-used, optionally with a - * new function/delegate. This routine should only be called for - * fibers that have terminated, as doing otherwise could result in - * scope-dependent functionality that is not executed. - * Stack-based classes, for example, may not be cleaned up - * properly if a fiber is reset before it has terminated. - * - * In: - * This fiber must be in state TERM or HOLD. - */ - final void reset() nothrow @nogc - in - { - assert( m_state == State.TERM || m_state == State.HOLD ); - } - do - { - m_ctxt.tstack = m_ctxt.bstack; - m_state = State.HOLD; - initStack(); - m_unhandled = null; - } - - /// ditto - final void reset( void function() fn ) nothrow @nogc - { - reset(); - m_call = fn; - } - - /// ditto - final void reset( void delegate() dg ) nothrow @nogc - { - reset(); - m_call = dg; - } - - /////////////////////////////////////////////////////////////////////////// - // General Properties - /////////////////////////////////////////////////////////////////////////// - - - /// A fiber may occupy one of three states: HOLD, EXEC, and TERM. - enum State - { - /** The HOLD state applies to any fiber that is suspended and ready to - be called. */ - HOLD, - /** The EXEC state will be set for any fiber that is currently - executing. */ - EXEC, - /** The TERM state is set when a fiber terminates. Once a fiber - terminates, it must be reset before it may be called again. */ - TERM - } - - - /** - * Gets the current state of this fiber. - * - * Returns: - * The state of this fiber as an enumerated value. - */ - final @property State state() const @safe pure nothrow @nogc - { - return m_state; - } - - - /////////////////////////////////////////////////////////////////////////// - // Actions on Calling Fiber - /////////////////////////////////////////////////////////////////////////// - - - /** - * Forces a context switch to occur away from the calling fiber. - */ - static void yield() nothrow @nogc - { - Fiber cur = getThis(); - assert( cur, "Fiber.yield() called with no active fiber" ); - assert( cur.m_state == State.EXEC ); - - static if ( __traits( compiles, ucontext_t ) ) - cur.m_ucur = &cur.m_utxt; - - cur.m_state = State.HOLD; - cur.switchOut(); - cur.m_state = State.EXEC; - } - - - /** - * Forces a context switch to occur away from the calling fiber and then - * throws obj in the calling fiber. - * - * Params: - * t = The object to throw. - * - * In: - * t must not be null. - */ - static void yieldAndThrow( Throwable t ) nothrow @nogc - in - { - assert( t ); - } - do - { - Fiber cur = getThis(); - assert( cur, "Fiber.yield() called with no active fiber" ); - assert( cur.m_state == State.EXEC ); - - static if ( __traits( compiles, ucontext_t ) ) - cur.m_ucur = &cur.m_utxt; - - cur.m_unhandled = t; - cur.m_state = State.HOLD; - cur.switchOut(); - cur.m_state = State.EXEC; + super( dg, sz, guardPageSize ); } @@ -923,8 +660,7 @@ class Fiber */ static Fiber getThis() @safe nothrow @nogc { - version (GNU) pragma(inline, false); - return sm_this; + return cast(Fiber) FiberBase.getThis(); } @@ -945,27 +681,7 @@ class Fiber } } -private: - - // - // Fiber entry point. Invokes the function or delegate passed on - // construction (if any). - // - final void run() - { - m_call(); - } - - // - // Standard fiber data - // - Callable m_call; - bool m_isRunning; - Throwable m_unhandled; - State m_state; - - -private: +protected: /////////////////////////////////////////////////////////////////////////// // Stack Management /////////////////////////////////////////////////////////////////////////// @@ -974,7 +690,7 @@ private: // // Allocate a new stack for this fiber. // - final void allocStack( size_t sz, size_t guardPageSize ) nothrow + final override void allocStack( size_t sz, size_t guardPageSize ) nothrow in { assert( !m_pmem && !m_ctxt ); @@ -1043,7 +759,9 @@ private: } else { - version (Posix) import core.sys.posix.sys.mman; // mmap, MAP_ANON + version (Posix) import core.sys.posix.sys.mman : MAP_ANON, MAP_FAILED, MAP_PRIVATE, mmap, + mprotect, PROT_NONE, PROT_READ, PROT_WRITE; + version (OpenBSD) import core.sys.posix.sys.mman : MAP_STACK; static if ( __traits( compiles, ucontext_t ) ) { @@ -1121,7 +839,7 @@ private: // // Free this fiber's stack. // - final void freeStack() nothrow @nogc + final override void freeStack() nothrow @nogc in(m_pmem) in(m_ctxt) { @@ -1137,7 +855,7 @@ private: } else { - import core.sys.posix.sys.mman; // munmap + import core.sys.posix.sys.mman : mmap, munmap; static if ( __traits( compiles, mmap ) ) { @@ -1157,7 +875,7 @@ private: // Initialize the allocated stack. // Look above the definition of 'class Fiber' for some information about the implementation of this routine // - final void initStack() nothrow @nogc + final override void initStack() nothrow @nogc in { assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack ); @@ -1232,7 +950,7 @@ private: } enum sehChainEnd = cast(EXCEPTION_REGISTRATION*) 0xFFFFFFFF; - __gshared static fp_t finalHandler = null; + __gshared fp_t finalHandler = null; if ( finalHandler is null ) { static EXCEPTION_REGISTRATION* fs0() nothrow @@ -1505,7 +1223,7 @@ private: // Only need to set return address ($r1). Everything else is fine // zero initialized. pstack -= size_t.sizeof * 11; // skip past space reserved for $r21-$r31 - push (cast(size_t) &fiber_entryPoint); + push(cast(size_t) &fiber_entryPoint); pstack += size_t.sizeof; // adjust sp (newp) above lr } else version (AsmAArch64_Posix) @@ -1616,537 +1334,6 @@ private: else static assert(0, "Not implemented"); } - - - StackContext* m_ctxt; - size_t m_size; - void* m_pmem; - - static if ( __traits( compiles, ucontext_t ) ) - { - // NOTE: The static ucontext instance is used to represent the context - // of the executing thread. - static ucontext_t sm_utxt = void; - ucontext_t m_utxt = void; - ucontext_t* m_ucur = null; - } - else static if (GNU_Enable_CET) - { - // When libphobos was built with --enable-cet, these fields need to - // always be present in the Fiber class layout. - import core.sys.posix.ucontext; - static ucontext_t sm_utxt = void; - ucontext_t m_utxt = void; - ucontext_t* m_ucur = null; - } - - -private: - /////////////////////////////////////////////////////////////////////////// - // Storage of Active Fiber - /////////////////////////////////////////////////////////////////////////// - - - // - // Sets a thread-local reference to the current fiber object. - // - static void setThis( Fiber f ) nothrow @nogc - { - sm_this = f; - } - - static Fiber sm_this; - - -private: - /////////////////////////////////////////////////////////////////////////// - // Context Switching - /////////////////////////////////////////////////////////////////////////// - - - // - // Switches into the stack held by this fiber. - // - final void switchIn() nothrow @nogc - { - ThreadBase tobj = ThreadBase.getThis(); - void** oldp = &tobj.m_curr.tstack; - void* newp = m_ctxt.tstack; - - // NOTE: The order of operations here is very important. The current - // stack top must be stored before m_lock is set, and pushContext - // must not be called until after m_lock is set. This process - // is intended to prevent a race condition with the suspend - // mechanism used for garbage collection. If it is not followed, - // a badly timed collection could cause the GC to scan from the - // bottom of one stack to the top of another, or to miss scanning - // a stack that still contains valid data. The old stack pointer - // oldp will be set again before the context switch to guarantee - // that it points to exactly the correct stack location so the - // successive pop operations will succeed. - *oldp = getStackTop(); - atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); - tobj.pushContext( m_ctxt ); - - fiber_switchContext( oldp, newp ); - - // NOTE: As above, these operations must be performed in a strict order - // to prevent Bad Things from happening. - tobj.popContext(); - atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); - tobj.m_curr.tstack = tobj.m_curr.bstack; - } - - - // - // Switches out of the current stack and into the enclosing stack. - // - final void switchOut() nothrow @nogc - { - ThreadBase tobj = ThreadBase.getThis(); - void** oldp = &m_ctxt.tstack; - void* newp = tobj.m_curr.within.tstack; - - // NOTE: The order of operations here is very important. The current - // stack top must be stored before m_lock is set, and pushContext - // must not be called until after m_lock is set. This process - // is intended to prevent a race condition with the suspend - // mechanism used for garbage collection. If it is not followed, - // a badly timed collection could cause the GC to scan from the - // bottom of one stack to the top of another, or to miss scanning - // a stack that still contains valid data. The old stack pointer - // oldp will be set again before the context switch to guarantee - // that it points to exactly the correct stack location so the - // successive pop operations will succeed. - *oldp = getStackTop(); - atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true); - - fiber_switchContext( oldp, newp ); - - // NOTE: As above, these operations must be performed in a strict order - // to prevent Bad Things from happening. - // NOTE: If use of this fiber is multiplexed across threads, the thread - // executing here may be different from the one above, so get the - // current thread handle before unlocking, etc. - tobj = ThreadBase.getThis(); - atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false); - tobj.m_curr.tstack = tobj.m_curr.bstack; - } -} - -/// -unittest { - int counter; - - class DerivedFiber : Fiber - { - this() - { - super( &run ); - } - - private : - void run() - { - counter += 2; - } - } - - void fiberFunc() - { - counter += 4; - Fiber.yield(); - counter += 8; - } - - // create instances of each type - Fiber derived = new DerivedFiber(); - Fiber composed = new Fiber( &fiberFunc ); - - assert( counter == 0 ); - - derived.call(); - assert( counter == 2, "Derived fiber increment." ); - - composed.call(); - assert( counter == 6, "First composed fiber increment." ); - - counter += 16; - assert( counter == 22, "Calling context increment." ); - - composed.call(); - assert( counter == 30, "Second composed fiber increment." ); - - // since each fiber has run to completion, each should have state TERM - assert( derived.state == Fiber.State.TERM ); - assert( composed.state == Fiber.State.TERM ); -} - -version (CoreUnittest) -{ - class TestFiber : Fiber - { - this() - { - super(&run); - } - - void run() - { - foreach (i; 0 .. 1000) - { - sum += i; - Fiber.yield(); - } - } - - enum expSum = 1000 * 999 / 2; - size_t sum; - } - - void runTen() - { - TestFiber[10] fibs; - foreach (ref fib; fibs) - fib = new TestFiber(); - - bool cont; - do { - cont = false; - foreach (fib; fibs) { - if (fib.state == Fiber.State.HOLD) - { - fib.call(); - cont |= fib.state != Fiber.State.TERM; - } - } - } while (cont); - - foreach (fib; fibs) - { - assert(fib.sum == TestFiber.expSum); - } - } -} - - -// Single thread running separate fibers -unittest -{ - runTen(); -} - - -// Multiple threads running separate fibers -unittest -{ - auto group = new ThreadGroup(); - foreach (_; 0 .. 4) - { - group.create(&runTen); - } - group.joinAll(); -} - - -// Multiple threads running shared fibers -version (PPC) version = UnsafeFiberMigration; -version (PPC64) version = UnsafeFiberMigration; -version (OSX) -{ - version (X86) version = UnsafeFiberMigration; - version (X86_64) version = UnsafeFiberMigration; - version (AArch64) version = UnsafeFiberMigration; -} - -version (UnsafeFiberMigration) -{ - // XBUG: core.thread fibers are supposed to be safe to migrate across - // threads, however, there is a problem: GCC always assumes that the - // address of thread-local variables don't change while on a given stack. - // In consequence, migrating fibers between threads currently is an unsafe - // thing to do, and will break on some targets (possibly PR26461). -} -else -{ - version = FiberMigrationUnittest; -} - -version (FiberMigrationUnittest) -unittest -{ - shared bool[10] locks; - TestFiber[10] fibs; - - void runShared() - { - bool cont; - do { - cont = false; - foreach (idx; 0 .. 10) - { - if (cas(&locks[idx], false, true)) - { - if (fibs[idx].state == Fiber.State.HOLD) - { - fibs[idx].call(); - cont |= fibs[idx].state != Fiber.State.TERM; - } - locks[idx] = false; - } - else - { - cont = true; - } - } - } while (cont); - } - - foreach (ref fib; fibs) - { - fib = new TestFiber(); - } - - auto group = new ThreadGroup(); - foreach (_; 0 .. 4) - { - group.create(&runShared); - } - group.joinAll(); - - foreach (fib; fibs) - { - assert(fib.sum == TestFiber.expSum); - } -} - - -// Test exception handling inside fibers. -unittest -{ - enum MSG = "Test message."; - string caughtMsg; - (new Fiber({ - try - { - throw new Exception(MSG); - } - catch (Exception e) - { - caughtMsg = e.msg; - } - })).call(); - assert(caughtMsg == MSG); -} - - -unittest -{ - int x = 0; - - (new Fiber({ - x++; - })).call(); - assert( x == 1 ); -} - -nothrow unittest -{ - new Fiber({}).call!(Fiber.Rethrow.no)(); -} - -unittest -{ - new Fiber({}).call(Fiber.Rethrow.yes); - new Fiber({}).call(Fiber.Rethrow.no); -} - -unittest -{ - enum MSG = "Test message."; - - try - { - (new Fiber(function() { - throw new Exception( MSG ); - })).call(); - assert( false, "Expected rethrown exception." ); - } - catch ( Throwable t ) - { - assert( t.msg == MSG ); - } -} - -// Test exception chaining when switching contexts in finally blocks. -unittest -{ - static void throwAndYield(string msg) { - try { - throw new Exception(msg); - } finally { - Fiber.yield(); - } - } - - static void fiber(string name) { - try { - try { - throwAndYield(name ~ ".1"); - } finally { - throwAndYield(name ~ ".2"); - } - } catch (Exception e) { - assert(e.msg == name ~ ".1"); - assert(e.next); - assert(e.next.msg == name ~ ".2"); - assert(!e.next.next); - } - } - - auto first = new Fiber(() => fiber("first")); - auto second = new Fiber(() => fiber("second")); - first.call(); - second.call(); - first.call(); - second.call(); - first.call(); - second.call(); - assert(first.state == Fiber.State.TERM); - assert(second.state == Fiber.State.TERM); -} - -// Test Fiber resetting -unittest -{ - static string method; - - static void foo() - { - method = "foo"; - } - - void bar() - { - method = "bar"; - } - - static void expect(Fiber fib, string s) - { - assert(fib.state == Fiber.State.HOLD); - fib.call(); - assert(fib.state == Fiber.State.TERM); - assert(method == s); method = null; - } - auto fib = new Fiber(&foo); - expect(fib, "foo"); - - fib.reset(); - expect(fib, "foo"); - - fib.reset(&foo); - expect(fib, "foo"); - - fib.reset(&bar); - expect(fib, "bar"); - - fib.reset(function void(){method = "function";}); - expect(fib, "function"); - - fib.reset(delegate void(){method = "delegate";}); - expect(fib, "delegate"); -} - -// Test unsafe reset in hold state -unittest -{ - auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096); - foreach (_; 0 .. 10) - { - fib.call(); - assert(fib.state == Fiber.State.HOLD); - fib.reset(); - } -} - -// stress testing GC stack scanning -unittest -{ - import core.memory; - import core.thread.osthread : Thread; - import core.time : dur; - - static void unreferencedThreadObject() - { - static void sleep() { Thread.sleep(dur!"msecs"(100)); } - auto thread = new Thread(&sleep).start(); - } - unreferencedThreadObject(); - GC.collect(); - - static class Foo - { - this(int value) - { - _value = value; - } - - int bar() - { - return _value; - } - - int _value; - } - - static void collect() - { - auto foo = new Foo(2); - assert(foo.bar() == 2); - GC.collect(); - Fiber.yield(); - GC.collect(); - assert(foo.bar() == 2); - } - - auto fiber = new Fiber(&collect); - - fiber.call(); - GC.collect(); - fiber.call(); - - // thread reference - auto foo = new Foo(2); - - void collect2() - { - assert(foo.bar() == 2); - GC.collect(); - Fiber.yield(); - GC.collect(); - assert(foo.bar() == 2); - } - - fiber = new Fiber(&collect2); - - fiber.call(); - GC.collect(); - fiber.call(); - - static void recurse(size_t cnt) - { - --cnt; - Fiber.yield(); - if (cnt) - { - auto fib = new Fiber(() { recurse(cnt); }); - fib.call(); - GC.collect(); - fib.call(); - } - } - fiber = new Fiber(() { recurse(20); }); - fiber.call(); } diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index 2379f7925e4..e5f0cadbbf2 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -15,15 +15,14 @@ */ module core.thread.osthread; -import core.thread.threadbase; -import core.thread.context; -import core.thread.types; import core.atomic; -import core.memory : GC, pageSize; -import core.time; import core.exception : onOutOfMemoryError; import core.internal.traits : externDFunc; - +import core.memory : GC, pageSize; +import core.thread.context; +import core.thread.threadbase; +import core.thread.types; +import core.time; /////////////////////////////////////////////////////////////////////////////// // Platform Detection and Memory Allocation @@ -118,7 +117,7 @@ version (Posix) // a version identifier. Please note that this is considered // an obsolescent feature according to the POSIX spec, so a // custom solution is still preferred. - import core.sys.posix.ucontext; + static import core.sys.posix.ucontext; } } @@ -141,25 +140,34 @@ version (Windows) } else version (Posix) { + static import core.sys.posix.pthread; + static import core.sys.posix.signal; import core.stdc.errno; - import core.sys.posix.semaphore; - import core.sys.posix.stdlib; // for malloc, valloc, free, atexit - import core.sys.posix.pthread; - import core.sys.posix.signal; - import core.sys.posix.time; + import core.sys.posix.pthread : pthread_atfork, pthread_attr_destroy, pthread_attr_getstack, pthread_attr_init, + pthread_attr_setstacksize, pthread_create, pthread_detach, pthread_getschedparam, pthread_join, pthread_self, + pthread_setschedparam, sched_get_priority_max, sched_get_priority_min, sched_param, sched_yield; + import core.sys.posix.semaphore : sem_init, sem_post, sem_t, sem_wait; + import core.sys.posix.signal : pthread_kill, sigaction, sigaction_t, sigdelset, sigfillset, sigset_t, sigsuspend, + SIGUSR1, stack_t; + import core.sys.posix.stdlib : free, malloc, realloc; + import core.sys.posix.sys.types : pthread_attr_t, pthread_key_t, pthread_t; + import core.sys.posix.time : nanosleep, timespec; version (Darwin) { - import core.sys.darwin.mach.thread_act; + import core.sys.darwin.mach.kern_return : KERN_SUCCESS; + import core.sys.darwin.mach.port : mach_port_t; + import core.sys.darwin.mach.thread_act : mach_msg_type_number_t, thread_get_state, thread_resume, + thread_suspend, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT, x86_thread_state64_t; import core.sys.darwin.pthread : pthread_mach_thread_np; } } version (Solaris) { - import core.sys.solaris.sys.priocntl; - import core.sys.solaris.sys.types; import core.sys.posix.sys.wait : idtype_t; + import core.sys.solaris.sys.priocntl : PC_CLNULL, PC_GETCLINFO, PC_GETPARMS, PC_SETPARMS, pcinfo_t, pcparms_t, priocntl; + import core.sys.solaris.sys.types : P_MYID, pri_t; } version (GNU) @@ -869,8 +877,10 @@ class Thread : ThreadBase } else version (Posix) { - static if (__traits(compiles, pthread_setschedprio)) + static if (__traits(compiles, core.sys.posix.pthread.pthread_setschedprio)) { + import core.sys.posix.pthread : pthread_setschedprio; + if (auto err = pthread_setschedprio(m_addr, val)) { // ignore error if thread is not running => Bugzilla 8960 @@ -1528,13 +1538,11 @@ private extern (D) void scanWindowsOnly(scope ScanAllThreadsTypeFn scan, ThreadB */ version (Posix) { - import core.sys.posix.unistd; - - alias getpid = core.sys.posix.unistd.getpid; + alias getpid = imported!"core.sys.posix.unistd".getpid; } else version (Windows) { - alias getpid = core.sys.windows.winbase.GetCurrentProcessId; + alias getpid = imported!"core.sys.windows.winbase".GetCurrentProcessId; } extern (C) @nogc nothrow @@ -1599,7 +1607,7 @@ private extern(D) void* getStackBottom() nothrow @nogc } else version (Darwin) { - import core.sys.darwin.pthread; + import core.sys.darwin.pthread : pthread_get_stackaddr_np; return pthread_get_stackaddr_np(pthread_self()); } else version (PThread_Getattr_NP) @@ -2079,6 +2087,10 @@ extern (C) void thread_init() @nogc nothrow enum SIGRTMIN = SIGUSR1; enum SIGRTMAX = 32; } + else + { + import core.sys.posix.signal : SIGRTMAX, SIGRTMIN; + } if ( suspendSignalNumber == 0 ) { @@ -2102,8 +2114,12 @@ extern (C) void thread_init() @nogc nothrow // NOTE: SA_RESTART indicates that system calls should restart if they // are interrupted by a signal, but this is not available on all // Posix systems, even those that support multithreading. - static if ( __traits( compiles, SA_RESTART ) ) + static if (__traits(compiles, core.sys.posix.signal.SA_RESTART)) + { + import core.sys.posix.signal : SA_RESTART; + suspend.sa_flags = SA_RESTART; + } suspend.sa_handler = &thread_suspendHandler; // NOTE: We want to ignore all signals while in this handler, so fill @@ -2233,19 +2249,6 @@ else version (Posix) { private { - import core.stdc.errno; - import core.sys.posix.semaphore; - import core.sys.posix.stdlib; // for malloc, valloc, free, atexit - import core.sys.posix.pthread; - import core.sys.posix.signal; - import core.sys.posix.time; - - version (Darwin) - { - import core.sys.darwin.mach.thread_act; - import core.sys.darwin.pthread : pthread_mach_thread_np; - } - // // Entry point for POSIX threads // @@ -2308,14 +2311,18 @@ else version (Posix) // implementation actually requires default initialization // then pthread_cleanup should be restructured to maintain // the current lack of a link dependency. - static if ( __traits( compiles, pthread_cleanup ) ) + static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup)) { + import core.sys.posix.pthread : pthread_cleanup; + pthread_cleanup cleanup = void; cleanup.push( &thread_cleanupHandler, cast(void*) obj ); } - else static if ( __traits( compiles, pthread_cleanup_push ) ) + else static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup_push)) { - pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj ); + import core.sys.posix.pthread : pthread_cleanup_push; + + pthread_cleanup_push(&thread_cleanupHandler, cast(void*) obj); } else { @@ -2366,12 +2373,14 @@ else version (Posix) // NOTE: Normal cleanup is handled by scope(exit). - static if ( __traits( compiles, pthread_cleanup ) ) + static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup)) { cleanup.pop( 0 ); } - else static if ( __traits( compiles, pthread_cleanup_push ) ) + else static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup_push)) { + import core.sys.posix.pthread : pthread_cleanup_pop; + pthread_cleanup_pop( 0 ); } @@ -2558,10 +2567,9 @@ private // Note: if the DLL is never unloaded, process termination kills all threads // and signals their handles before unconditionally calling DllMain(DLL_PROCESS_DETACH). - import core.sys.windows.winbase : FreeLibraryAndExitThread, GetModuleHandleExW, - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; - import core.sys.windows.windef : HMODULE; import core.sys.windows.dll : dll_getRefCount; + import core.sys.windows.winbase : FreeLibraryAndExitThread, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, GetModuleHandleExW; + import core.sys.windows.windef : HMODULE; version (CRuntime_Microsoft) extern(C) extern __gshared ubyte msvcUsesUCRT; // from rt/msvc.d diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d index f3854076b0b..93af3b113d8 100644 --- a/libphobos/libdruntime/core/thread/threadbase.d +++ b/libphobos/libdruntime/core/thread/threadbase.d @@ -7,7 +7,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak - * Source: $(DRUNTIMESRC core/thread/osthread.d) + * Source: $(DRUNTIMESRC core/thread/threadbase.d) */ /* NOTE: This file has been patched from the original DMD distribution to diff --git a/libphobos/libdruntime/core/thread/threadgroup.d b/libphobos/libdruntime/core/thread/threadgroup.d index d00ce05854d..b2ab9313901 100644 --- a/libphobos/libdruntime/core/thread/threadgroup.d +++ b/libphobos/libdruntime/core/thread/threadgroup.d @@ -6,7 +6,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak - * Source: $(DRUNTIMESRC core/thread/osthread.d) + * Source: $(DRUNTIMESRC core/thread/threadgroup.d) */ module core.thread.threadgroup; diff --git a/libphobos/libdruntime/core/thread/types.d b/libphobos/libdruntime/core/thread/types.d index 998f610c255..4d0b3649ec7 100644 --- a/libphobos/libdruntime/core/thread/types.d +++ b/libphobos/libdruntime/core/thread/types.d @@ -6,7 +6,7 @@ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak - * Source: $(DRUNTIMESRC core/thread/osthread.d) + * Source: $(DRUNTIMESRC core/thread/types.d) */ module core.thread.types; @@ -20,7 +20,7 @@ version (Windows) else version (Posix) { - import core.sys.posix.pthread; + import core.sys.posix.sys.types : pthread_t; alias ThreadID = pthread_t; } @@ -55,7 +55,7 @@ shared static this() { version (Posix) { - import core.sys.posix.unistd; + import core.sys.posix.unistd : _SC_THREAD_STACK_MIN, sysconf; PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN); } diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d index dc79141efa7..53a0533f25e 100644 --- a/libphobos/libdruntime/core/time.d +++ b/libphobos/libdruntime/core/time.d @@ -66,19 +66,9 @@ module core.time; import core.exception; -import core.stdc.time; -import core.stdc.stdio; import core.internal.string; - -version (Windows) -{ -import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/; -} -else version (Posix) -{ -import core.sys.posix.time; -import core.sys.posix.sys.time; -} +import core.stdc.stdio; +import core.stdc.time; version (OSX) version = Darwin; @@ -89,12 +79,28 @@ else version (TVOS) else version (WatchOS) version = Darwin; +version (Windows) +{ + import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/; +} +else version (Darwin) +{ + import core.sys.posix.sys.time : gettimeofday, timeval; + import core.sys.posix.time : timespec; +} +else version (Posix) +{ + import core.sys.posix.sys.time : gettimeofday, timeval; + import core.sys.posix.time : clock_getres, clock_gettime, CLOCK_MONOTONIC, timespec; +} + + //This probably should be moved somewhere else in druntime which //is Darwin-specific. version (Darwin) { -public import core.sys.darwin.mach.kern_return; +import core.sys.darwin.mach.kern_return : kern_return_t; extern(C) nothrow @nogc { @@ -3925,7 +3931,14 @@ version (CoreUnittest) const(char)* numToStringz()(long value) @trusted pure not } -import core.internal.traits : AliasSeq; +/+ + dmd @@@BUG18223@@@ + A selective import of `AliasSeq` happens to bleed through and causes symbol clashes downstream. + +/ +version (none) + import core.internal.traits : AliasSeq; +else + import core.internal.traits; /+ An adjusted copy of std.exception.assertThrown. +/ diff --git a/libphobos/libdruntime/rt/aApply.d b/libphobos/libdruntime/rt/aApply.d index c59d9dc1234..b8e575d20fe 100644 --- a/libphobos/libdruntime/rt/aApply.d +++ b/libphobos/libdruntime/rt/aApply.d @@ -10,6 +10,8 @@ module rt.aApply; import core.internal.utf : decode, toUTF8; +debug (apply) import core.stdc.stdio : printf; + /**********************************************/ /* 1 argument versions */ @@ -76,7 +78,7 @@ extern (C) int _aApplycd1(scope const(char)[] aa, dg_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplycd1(), len = %d\n", len); + debug(apply) printf("_aApplycd1(), len = %zd\n", len); for (size_t i = 0; i < len; ) { dchar d = aa[i]; @@ -137,7 +139,7 @@ extern (C) int _aApplywd1(scope const(wchar)[] aa, dg_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplywd1(), len = %d\n", len); + debug(apply) printf("_aApplywd1(), len = %zd\n", len); for (size_t i = 0; i < len; ) { dchar d = aa[i]; @@ -198,7 +200,7 @@ extern (C) int _aApplycw1(scope const(char)[] aa, dg_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplycw1(), len = %d\n", len); + debug(apply) printf("_aApplycw1(), len = %zd\n", len); for (size_t i = 0; i < len; ) { wchar w = aa[i]; @@ -272,7 +274,7 @@ extern (C) int _aApplywc1(scope const(wchar)[] aa, dg_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplywc1(), len = %d\n", len); + debug(apply) printf("_aApplywc1(), len = %zd\n", len); for (size_t i = 0; i < len; ) { wchar w = aa[i]; @@ -351,7 +353,7 @@ extern (C) int _aApplydc1(scope const(dchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplydc1(), len = %d\n", aa.length); + debug(apply) printf("_aApplydc1(), len = %zd\n", aa.length); foreach (dchar d; aa) { if (d & ~0x7F) @@ -427,7 +429,7 @@ extern (C) int _aApplydw1(scope const(dchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplydw1(), len = %d\n", aa.length); + debug(apply) printf("_aApplydw1(), len = %zd\n", aa.length); foreach (dchar d; aa) { wchar w; @@ -513,7 +515,7 @@ extern (C) int _aApplycd2(scope const(char)[] aa, dg2_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplycd2(), len = %d\n", len); + debug(apply) printf("_aApplycd2(), len = %zd\n", len); size_t n; for (size_t i = 0; i < len; i += n) { @@ -581,7 +583,7 @@ extern (C) int _aApplywd2(scope const(wchar)[] aa, dg2_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplywd2(), len = %d\n", len); + debug(apply) printf("_aApplywd2(), len = %zd\n", len); size_t n; for (size_t i = 0; i < len; i += n) { @@ -649,7 +651,7 @@ extern (C) int _aApplycw2(scope const(char)[] aa, dg2_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplycw2(), len = %d\n", len); + debug(apply) printf("_aApplycw2(), len = %zd\n", len); size_t n; for (size_t i = 0; i < len; i += n) { @@ -728,7 +730,7 @@ extern (C) int _aApplywc2(scope const(wchar)[] aa, dg2_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplywc2(), len = %d\n", len); + debug(apply) printf("_aApplywc2(), len = %zd\n", len); size_t n; for (size_t i = 0; i < len; i += n) { @@ -813,7 +815,7 @@ extern (C) int _aApplydc2(scope const(dchar)[] aa, dg2_t dg) int result; size_t len = aa.length; - debug(apply) printf("_aApplydc2(), len = %d\n", len); + debug(apply) printf("_aApplydc2(), len = %zd\n", len); for (size_t i = 0; i < len; i++) { dchar d = aa[i]; @@ -891,7 +893,7 @@ unittest extern (C) int _aApplydw2(scope const(dchar)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplydw2(), len = %d\n", aa.length); + debug(apply) printf("_aApplydw2(), len = %zd\n", aa.length); foreach (size_t i, dchar d; aa) { wchar w; diff --git a/libphobos/libdruntime/rt/aApplyR.d b/libphobos/libdruntime/rt/aApplyR.d index 560025c636d..14052dfcd47 100644 --- a/libphobos/libdruntime/rt/aApplyR.d +++ b/libphobos/libdruntime/rt/aApplyR.d @@ -10,6 +10,8 @@ module rt.aApplyR; import core.internal.utf; +debug (apply) import core.stdc.stdio : printf; + /**********************************************/ /* 1 argument versions */ @@ -37,7 +39,7 @@ Returns: extern (C) int _aApplyRcd1(scope const(char)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRcd1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; @@ -110,7 +112,7 @@ unittest extern (C) int _aApplyRwd1(scope const(wchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRwd1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; @@ -173,7 +175,7 @@ unittest extern (C) int _aApplyRcw1(scope const(char)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRcw1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; wchar w; @@ -259,7 +261,7 @@ unittest extern (C) int _aApplyRwc1(scope const(wchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRwc1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; char c; @@ -343,7 +345,7 @@ unittest extern (C) int _aApplyRdc1(scope const(dchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRdc1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0;) { dchar d = aa[--i]; char c; @@ -421,7 +423,7 @@ unittest extern (C) int _aApplyRdw1(scope const(dchar)[] aa, dg_t dg) { int result; - debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRdw1(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d = aa[--i]; wchar w; @@ -507,7 +509,7 @@ extern (C) int _aApplyRcd2(scope const(char)[] aa, dg2_t dg) size_t i; size_t len = aa.length; - debug(apply) printf("_aApplyRcd2(), len = %d\n", len); + debug(apply) printf("_aApplyRcd2(), len = %zd\n", len); for (i = len; i != 0; ) { dchar d; @@ -581,7 +583,7 @@ unittest extern (C) int _aApplyRwd2(scope const(wchar)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRwd2(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; @@ -646,7 +648,7 @@ unittest extern (C) int _aApplyRcw2(scope const(char)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRcw2(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; wchar w; @@ -734,7 +736,7 @@ unittest extern (C) int _aApplyRwc2(scope const(wchar)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRwc2(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d; char c; @@ -820,7 +822,7 @@ unittest extern (C) int _aApplyRdc2(scope const(dchar)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRdc2(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d = aa[--i]; char c; @@ -899,7 +901,7 @@ unittest extern (C) int _aApplyRdw2(scope const(dchar)[] aa, dg2_t dg) { int result; - debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length); + debug(apply) printf("_aApplyRdw2(), len = %zd\n", aa.length); for (size_t i = aa.length; i != 0; ) { dchar d = aa[--i]; wchar w; diff --git a/libphobos/libdruntime/rt/adi.d b/libphobos/libdruntime/rt/adi.d index ea5a78f9c13..ece0f4b9f2e 100644 --- a/libphobos/libdruntime/rt/adi.d +++ b/libphobos/libdruntime/rt/adi.d @@ -27,7 +27,7 @@ private extern (C) int _adEq2(void[] a1, void[] a2, TypeInfo ti) { - debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length); + debug(adi) printf("_adEq2(a1.length = %zd, a2.length = %zd)\n", a1.length, a2.length); if (a1.length != a2.length) return 0; // not equal if (!ti.equals(&a1, &a2)) diff --git a/libphobos/libdruntime/rt/arraycat.d b/libphobos/libdruntime/rt/arraycat.d index d8794809af3..0ab785ba3b9 100644 --- a/libphobos/libdruntime/rt/arraycat.d +++ b/libphobos/libdruntime/rt/arraycat.d @@ -21,7 +21,7 @@ extern (C) @trusted nothrow: void[] _d_arraycopy(size_t size, void[] from, void[] to) { - debug(PRINTF) printf("f = %p,%d, t = %p,%d, size = %d\n", + debug(PRINTF) printf("f = %p,%zd, t = %p,%zd, size = %zd\n", from.ptr, from.length, to.ptr, to.length, size); enforceRawArraysConformable("copy", size, from, to); diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index c7d8bbaab35..cd110bfc2aa 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -14,6 +14,8 @@ */ module rt.cast_; +debug(cast_) import core.stdc.stdio : printf; + extern (C): @nogc: nothrow: @@ -60,7 +62,7 @@ Object _d_toObject(return scope void* p) */ if (pi.offset < 0x10000) { - debug(cast_) printf("\tpi.offset = %d\n", pi.offset); + debug(cast_) printf("\tpi.offset = %zd\n", pi.offset); return cast(Object)(p - pi.offset); } return o; @@ -72,19 +74,19 @@ Object _d_toObject(return scope void* p) */ void* _d_interface_cast(void* p, ClassInfo c) { - debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name); + debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, cast(int) c.name.length, c.name.ptr); if (!p) return null; Interface* pi = **cast(Interface***) p; - debug(cast_) printf("\tpi.offset = %d\n", pi.offset); + debug(cast_) printf("\tpi.offset = %zd\n", pi.offset); Object o2 = cast(Object)(p - pi.offset); void* res = null; size_t offset = 0; if (o2 && _d_isbaseof2(typeid(o2), c, offset)) { - debug(cast_) printf("\toffset = %d\n", offset); + debug(cast_) printf("\toffset = %zd\n", offset); res = cast(void*) o2 + offset; } debug(cast_) printf("\tresult = %p\n", res); @@ -101,13 +103,13 @@ void* _d_interface_cast(void* p, ClassInfo c) */ void* _d_dynamic_cast(Object o, ClassInfo c) { - debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); + debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, cast(int) c.name.length, c.name.ptr); void* res = null; size_t offset = 0; if (o && _d_isbaseof2(typeid(o), c, offset)) { - debug(cast_) printf("\toffset = %d\n", offset); + debug(cast_) printf("\toffset = %zd\n", offset); res = cast(void*) o + offset; } debug(cast_) printf("\tresult = %p\n", res); @@ -124,7 +126,7 @@ void* _d_dynamic_cast(Object o, ClassInfo c) */ void* _d_class_cast(Object o, ClassInfo c) { - debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s', level %d)\n", o, c.name, level); + debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s')\n", o, cast(int) c.name.length, c.name.ptr); if (!o) return null; diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index 7851f664297..dbdfcb0b1f0 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -261,7 +261,7 @@ Params: */ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow { - debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %d, arr.ptr = x%x arr.length = %d\n", ti.next.tsize, arr.ptr, arr.length); + debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %zd, arr.ptr = %p arr.length = %zd\n", ti.next.tsize, arr.ptr, arr.length); auto tinext = unqualify(ti.next); auto size = tinext.tsize; // array element size auto reqsize = arr.length * size; @@ -471,7 +471,7 @@ extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure noth auto tinext = unqualify(ti.next); auto size = tinext.tsize; - debug(PRINTF) printf("_d_newarrayU(length = x%x, size = %d)\n", length, size); + debug(PRINTF) printf("_d_newarrayU(length = x%zx, size = %zd)\n", length, size); if (length == 0 || size == 0) return null; @@ -876,7 +876,7 @@ do { //printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength); if (p) - printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length); + printf("\tp.ptr = %p, p.length = %zd\n", (*p).ptr, (*p).length); } if (newlength <= (*p).length) @@ -925,7 +925,7 @@ do assert(0); } - debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); + debug(PRINTF) printf("newsize = %zx, newlength = %zx\n", newsize, newlength); const isshared = typeid(ti) is typeid(TypeInfo_Shared); @@ -998,7 +998,7 @@ do { //printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength); if (p) - printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length); + printf("\tp.ptr = %p, p.length = %zd\n", (*p).ptr, (*p).length); } if (newlength <= (*p).length) @@ -1047,7 +1047,7 @@ do assert(0); } - debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength); + debug(PRINTF) printf("newsize = %zx, newlength = %zx\n", newsize, newlength); const isshared = typeid(ti) is typeid(TypeInfo_Shared); @@ -1184,7 +1184,7 @@ size_t newCapacity(size_t newlength, size_t elemsize) // ((newlength * mult + 99) / 100) * elemsize newcap = cast(size_t)((newlength * mult + 127) >> 7) * elemsize; debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/128.0,newcap / cast(double)elemsize); - debug(PRINTF) printf("newcap = %d, newlength = %d, elemsize = %d\n", newcap, newlength, elemsize); + debug(PRINTF) printf("newcap = %zd, newlength = %zd, elemsize = %zd\n", newcap, newlength, elemsize); return newcap; } @@ -1426,7 +1426,7 @@ void* _d_arrayliteralTX(const TypeInfo ti, size_t length) @weak auto sizeelem = tinext.tsize; // array element size void* result; - debug(PRINTF) printf("_d_arrayliteralTX(sizeelem = %d, length = %d)\n", sizeelem, length); + debug(PRINTF) printf("_d_arrayliteralTX(sizeelem = %zd, length = %zd)\n", sizeelem, length); if (length == 0 || sizeelem == 0) result = null; else diff --git a/libphobos/libdruntime/rt/monitor_.d b/libphobos/libdruntime/rt/monitor_.d index 3a9c1f7cc2e..5d6c2f8c148 100644 --- a/libphobos/libdruntime/rt/monitor_.d +++ b/libphobos/libdruntime/rt/monitor_.d @@ -185,7 +185,10 @@ version (Windows) } else version (Posix) { - import core.sys.posix.pthread; + import core.sys.posix.pthread : pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock, + PTHREAD_MUTEX_RECURSIVE, pthread_mutex_unlock, pthread_mutexattr_destroy, pthread_mutexattr_init, + pthread_mutexattr_settype; + import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t; @nogc: alias Mutex = pthread_mutex_t; |
