diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-02-03 19:01:32 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-02-03 22:06:42 +0100 |
commit | b1a207c6df0a9c5555017f65f8731acf8d4c14c2 (patch) | |
tree | fca99fd7efdcdf6fc71b042be6df26de755c9468 /libphobos/src | |
parent | b52a1dfe12a6303c7649f3ff5b8dac6c1001d49a (diff) | |
download | gcc-b1a207c6df0a9c5555017f65f8731acf8d4c14c2.tar.gz |
libphobos: Merge upstream druntime 9d0c8364, phobos 9d575282e.
Druntime changes:
- Add platform-specific bindings for stdlib.h and sys/syctl.h.
- Add darwin bindings for mach/dyld.h.
- Fix solaris bindings for locale.h (PR98910).
- Remove deprecated bindings from the module headers.
Phobos changes:
- Backport platform-specific fixes for std.conv, std.datetime,
std.exception, std.experimental.allocator, std.file, std.math,
std.parallelism, std.socket, std.stdio, and std.system.
Reviewed-on: https://github.com/dlang/druntime/pull/3363
https://github.com/dlang/phobos/pull/7784
libphobos/ChangeLog:
PR d/98910
* libdruntime/MERGE: Merge upstream druntime 9d0c8364.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
core/internal/attributes.d
(DRUNTIME_DSOURCES_BIONIC): Add core/sys/bionic/stdlib.d.
(DRUNTIME_DSOURCES_DARWIN): Add core/sys/darwin/stdlib.d, and
core/sys/darwin/sys/sysctl.d.
(DRUNTIME_DSOURCES_DRAGONFLYBSD): Add
core/sys/dragonflybsd/stdlib.d, and
core/sys/dragonflybsd/sys/sysctl.d.
(DRUNTIME_DSOURCES_FREEBSD): Add core/sys/freebsd/stdlib.d, and
core/sys/freebsd/sys/sysctl.d.
(DRUNTIME_DSOURCES_NETBSD): Add core/sys/netbsd/stdlib.d, and
core/sys/netbsd/sys/sysctl.d.
(DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/stdlib.d, and
core/sys/openbsd/sys/sysctl.d.
(DRUNTIME_DSOURCES_SOLARIS): Add core/sys/solaris/stdlib.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 9d575282e.
Diffstat (limited to 'libphobos/src')
-rw-r--r-- | libphobos/src/MERGE | 2 | ||||
-rw-r--r-- | libphobos/src/std/conv.d | 2 | ||||
-rw-r--r-- | libphobos/src/std/datetime/systime.d | 110 | ||||
-rw-r--r-- | libphobos/src/std/datetime/timezone.d | 17 | ||||
-rw-r--r-- | libphobos/src/std/exception.d | 5 | ||||
-rw-r--r-- | libphobos/src/std/experimental/allocator/building_blocks/region.d | 44 | ||||
-rw-r--r-- | libphobos/src/std/experimental/allocator/mmap_allocator.d | 17 | ||||
-rw-r--r-- | libphobos/src/std/file.d | 88 | ||||
-rw-r--r-- | libphobos/src/std/math.d | 33 | ||||
-rw-r--r-- | libphobos/src/std/parallelism.d | 233 | ||||
-rw-r--r-- | libphobos/src/std/socket.d | 4 | ||||
-rw-r--r-- | libphobos/src/std/stdio.d | 9 | ||||
-rw-r--r-- | libphobos/src/std/system.d | 6 |
13 files changed, 412 insertions, 158 deletions
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 1d8f8dfb46d..6de04b453ff 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -3dd5df6864b3849450d3657e219b90909663a513 +9d575282edeccecbc061e615bf2486fd07e8c084 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d index 743d203b2bb..31cc6517173 100644 --- a/libphobos/src/std/conv.d +++ b/libphobos/src/std/conv.d @@ -3148,8 +3148,6 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum { version (CRuntime_Microsoft) ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod - else version (CRuntime_Bionic) - ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod else ld1 = strtold(s.ptr, null); } diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d index 0b11ed96745..b2291910616 100644 --- a/libphobos/src/std/datetime/systime.d +++ b/libphobos/src/std/datetime/systime.d @@ -7,6 +7,15 @@ +/ module std.datetime.systime; +version (OSX) + version = Darwin; +else version (iOS) + version = Darwin; +else version (TVOS) + version = Darwin; +else version (WatchOS) + version = Darwin; + import core.time; import std.datetime.date; import std.datetime.timezone; @@ -161,18 +170,19 @@ public: static import core.stdc.time; enum hnsecsToUnixEpoch = unixTimeToStdTime(0); - version (OSX) + version (Darwin) { static if (clockType == ClockType.second) return unixTimeToStdTime(core.stdc.time.time(null)); else { import core.sys.posix.sys.time : gettimeofday, timeval; - timeval tv; - if (gettimeofday(&tv, null) != 0) - throw new TimeException("Call to gettimeofday() failed"); + timeval tv = void; + // Posix gettimeofday called with a valid timeval address + // and a null second parameter doesn't fail. + gettimeofday(&tv, null); return convert!("seconds", "hnsecs")(tv.tv_sec) + - convert!("usecs", "hnsecs")(tv.tv_usec) + + tv.tv_usec * 10 + hnsecsToUnixEpoch; } } @@ -188,9 +198,16 @@ public: else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME; else static assert(0, "Previous static if is wrong."); - timespec ts; - if (clock_gettime(clockArg, &ts) != 0) - throw new TimeException("Call to clock_gettime() failed"); + timespec ts = void; + immutable error = clock_gettime(clockArg, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) + { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; @@ -205,9 +222,16 @@ public: else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE; else static if (clockType == ClockType.second) alias clockArg = CLOCK_SECOND; else static assert(0, "Previous static if is wrong."); - timespec ts; - if (clock_gettime(clockArg, &ts) != 0) - throw new TimeException("Call to clock_gettime() failed"); + timespec ts = void; + immutable error = clock_gettime(clockArg, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) + { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; @@ -218,12 +242,38 @@ public: return unixTimeToStdTime(core.stdc.time.time(null)); else { - import core.sys.posix.sys.time : gettimeofday, timeval; - timeval tv; - if (gettimeofday(&tv, null) != 0) - throw new TimeException("Call to gettimeofday() failed"); - return convert!("seconds", "hnsecs")(tv.tv_sec) + - convert!("usecs", "hnsecs")(tv.tv_usec) + + import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME; + timespec ts = void; + immutable error = clock_gettime(CLOCK_REALTIME, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) + { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } + return convert!("seconds", "hnsecs")(ts.tv_sec) + + ts.tv_nsec / 100 + + hnsecsToUnixEpoch; + } + } + else version (OpenBSD) + { + static if (clockType == ClockType.second) + return unixTimeToStdTime(core.stdc.time.time(null)); + else + { + import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME; + static if (clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME; + else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; + else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME; + else static assert(0, "Previous static if is wrong."); + timespec ts; + if (clock_gettime(clockArg, &ts) != 0) + throw new TimeException("Call to clock_gettime() failed"); + return convert!("seconds", "hnsecs")(ts.tv_sec) + + ts.tv_nsec / 100 + hnsecsToUnixEpoch; } } @@ -236,9 +286,16 @@ public: else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE; else static if (clockType == ClockType.second) alias clockArg = CLOCK_SECOND; else static assert(0, "Previous static if is wrong."); - timespec ts; - if (clock_gettime(clockArg, &ts) != 0) - throw new TimeException("Call to clock_gettime() failed"); + timespec ts = void; + immutable error = clock_gettime(clockArg, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) + { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; @@ -254,9 +311,16 @@ public: else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME; else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME; else static assert(0, "Previous static if is wrong."); - timespec ts; - if (clock_gettime(clockArg, &ts) != 0) - throw new TimeException("Call to clock_gettime() failed"); + timespec ts = void; + immutable error = clock_gettime(clockArg, &ts); + // Posix clock_gettime called with a valid address and valid clock_id is only + // permitted to fail if the number of seconds does not fit in time_t. If tv_sec + // is long or larger overflow won't happen before 292 billion years A.D. + static if (ts.tv_sec.max < long.max) + { + if (error) + throw new TimeException("Call to clock_gettime() failed"); + } return convert!("seconds", "hnsecs")(ts.tv_sec) + ts.tv_nsec / 100 + hnsecsToUnixEpoch; diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index 7ae19020243..9b744ff7ab0 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -14,6 +14,15 @@ import std.exception : enforce; import std.range.primitives; import std.traits : isIntegral, isSomeString, Unqual; +version (OSX) + version = Darwin; +else version (iOS) + version = Darwin; +else version (TVOS) + version = Darwin; +else version (WatchOS) + version = Darwin; + version (Windows) { import core.stdc.time : time_t; @@ -296,7 +305,7 @@ public: else version (NetBSD) enum utcZone = "UTC"; else version (DragonFlyBSD) enum utcZone = "UTC"; else version (linux) enum utcZone = "UTC"; - else version (OSX) enum utcZone = "UTC"; + else version (Darwin) enum utcZone = "UTC"; else version (Solaris) enum utcZone = "UTC"; else static assert(0, "The location of the UTC timezone file on this Posix platform must be set."); @@ -671,7 +680,11 @@ public: @safe unittest { - assert(LocalTime().dstName !is null); + // tzname, called from dstName, isn't set by default for Musl. + version (CRuntime_Musl) + assert(LocalTime().dstName is null); + else + assert(LocalTime().dstName !is null); version (Posix) { diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d index 73afadc07e0..56133c9ad89 100644 --- a/libphobos/src/std/exception.d +++ b/libphobos/src/std/exception.d @@ -1478,10 +1478,13 @@ private bool isUnionAliasedImpl(T)(size_t offset) static assert( isUnionAliased!(S.A5, 1)); //a5.b1; } +version (CRuntime_Glibc) version = GNU_STRERROR; +version (CRuntime_UClibc) version = GNU_STRERROR; + package string errnoString(int errno) nothrow @trusted { import core.stdc.string : strlen; - version (CRuntime_Glibc) + version (GNU_STRERROR) { import core.stdc.string : strerror_r; char[1024] buf = void; diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d index 835d0937cec..53f5ef988d4 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/region.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d @@ -5,6 +5,15 @@ import std.experimental.allocator.building_blocks.null_allocator; import std.experimental.allocator.common; import std.typecons : Flag, Yes, No; +version (OSX) + version = Darwin; +else version (iOS) + version = Darwin; +else version (TVOS) + version = Darwin; +else version (WatchOS) + version = Darwin; + /** A $(D Region) allocator allocates memory straight from one contiguous chunk. There is no deallocation, and once the region is full, allocation requests @@ -580,14 +589,26 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment) assert(a.length == 2001); } -version(CRuntime_Musl) +version (CRuntime_Musl) { // sbrk and brk are disabled in Musl: // https://git.musl-libc.org/cgit/musl/commit/?id=7a995fe706e519a4f55399776ef0df9596101f93 // https://git.musl-libc.org/cgit/musl/commit/?id=863d628d93ea341b6a32661a1654320ce69f6a07 -} else: -private extern(C) void* sbrk(long); -private extern(C) int brk(shared void*); +} +version (DragonFlyBSD) +{ + // sbrk is deprecated in favor of mmap (we could implement a mmap + MAP_NORESERVE + PROT_NONE version) + // brk has been removed + // https://www.dragonflydigest.com/2019/02/22/22586.html + // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/dc676eaefa61b0f47bbea1c53eab86fd5ccd78c6 + // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/4b5665564ef37dc939a3a9ffbafaab9894c18885 + // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/8618d94a0e2ff8303ad93c123a3fa598c26a116e +} +else +{ + private extern(C) void* sbrk(long) nothrow @nogc; + private extern(C) int brk(shared void*) nothrow @nogc; +} /** @@ -599,11 +620,14 @@ that uncontrolled calls to $(D brk) and $(D sbrk) may affect the workings of $(D SbrkRegion) adversely. */ +version (CRuntime_Musl) {} else +version (DragonFlyBSD) {} else version (Posix) struct SbrkRegion(uint minAlign = platformAlignment) { import core.sys.posix.pthread : pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_t, pthread_mutex_lock, pthread_mutex_unlock, - PTHREAD_MUTEX_INITIALIZER; + + PTHREAD_MUTEX_INITIALIZER; private static shared pthread_mutex_t sbrkMutex = PTHREAD_MUTEX_INITIALIZER; import std.typecons : Ternary; @@ -763,7 +787,9 @@ version (Posix) struct SbrkRegion(uint minAlign = platformAlignment) } } -version (Posix) @system unittest +version (CRuntime_Musl) {} else +version (DragonFlyBSD) {} else +version (Posix) @system nothrow @nogc unittest { // Let's test the assumption that sbrk(n) returns the old address const p1 = sbrk(0); @@ -775,7 +801,9 @@ version (Posix) @system unittest sbrk(-4096); } -version (Posix) @system unittest +version (CRuntime_Musl) {} else +version (DragonFlyBSD) {} else +version (Posix) @system nothrow @nogc unittest { import std.typecons : Ternary; alias alloc = SbrkRegion!(8).instance; @@ -786,7 +814,7 @@ version (Posix) @system unittest assert(alloc.owns(a) == Ternary.yes); assert(alloc.owns(b) == Ternary.yes); // reducing the brk does not work on OSX - version (OSX) {} else + version (Darwin) {} else { assert(alloc.deallocate(b)); assert(alloc.deallocateAll); diff --git a/libphobos/src/std/experimental/allocator/mmap_allocator.d b/libphobos/src/std/experimental/allocator/mmap_allocator.d index 945859b8c56..e07d444c32c 100644 --- a/libphobos/src/std/experimental/allocator/mmap_allocator.d +++ b/libphobos/src/std/experimental/allocator/mmap_allocator.d @@ -46,6 +46,21 @@ struct MmapAllocator if (b.ptr) munmap(b.ptr, b.length) == 0 || assert(0); return true; } + + // Anonymous mmap might be zero-filled on all Posix systems but + // not all commit to this in the documentation. + version (linux) + // http://man7.org/linux/man-pages/man2/mmap.2.html + package alias allocateZeroed = allocate; + else version (NetBSD) + // http://netbsd.gw.com/cgi-bin/man-cgi?mmap+2+NetBSD-current + package alias allocateZeroed = allocate; + else version (Solaris) + // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html + package alias allocateZeroed = allocate; + else version (AIX) + // https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.basetrf1/mmap.htm + package alias allocateZeroed = allocate; } else version (Windows) { @@ -67,6 +82,8 @@ struct MmapAllocator { return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0; } + + package alias allocateZeroed = allocate; } } diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index 380ecfc2bcd..13a3db0ff66 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -1490,6 +1490,15 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)) // vfs.timestamp_precision sysctl to a value greater than zero. // - OS X, where the native filesystem (HFS+) stores filesystem // timestamps with 1-second precision. +// +// Note: on linux systems, although in theory a change to a file date +// can be tracked with precision of 4 msecs, this test waits 20 msecs +// to prevent possible problems relative to the CI services the dlang uses, +// as they may have the HZ setting that controls the software clock set to 100 +// (instead of the more common 250). +// see https://man7.org/linux/man-pages/man7/time.7.html +// https://stackoverflow.com/a/14393315, +// https://issues.dlang.org/show_bug.cgi?id=21148 version (FreeBSD) {} else version (DragonFlyBSD) {} else version (OSX) {} else @@ -1508,7 +1517,7 @@ version (OSX) {} else remove(deleteme); assert(time != lastTime); lastTime = time; - Thread.sleep(10.msecs); + Thread.sleep(20.msecs); } } @@ -2757,15 +2766,27 @@ else version (NetBSD) buffer.length *= 2; } } + else version (DragonFlyBSD) + { + import core.sys.dragonflybsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME; + import std.exception : errnoEnforce, assumeUnique; + + int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]; + size_t len; + + auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); // get the length of the path + errnoEnforce(result == 0); + + auto buffer = new char[len - 1]; + result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0); + errnoEnforce(result == 0); + + return buffer.assumeUnique; + } else version (FreeBSD) { + import core.sys.freebsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME; import std.exception : errnoEnforce, assumeUnique; - enum - { - CTL_KERN = 1, - KERN_PROC = 14, - KERN_PROC_PATHNAME = 12 - } int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]; size_t len; @@ -2781,11 +2802,58 @@ else version (NetBSD) } else version (NetBSD) { - return readLink("/proc/self/exe"); + import core.sys.netbsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC_ARGS, KERN_PROC_PATHNAME; + import std.exception : errnoEnforce, assumeUnique; + + int[4] mib = [CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME]; + size_t len; + + auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); // get the length of the path + errnoEnforce(result == 0); + + auto buffer = new char[len - 1]; + result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0); + errnoEnforce(result == 0); + + return buffer.assumeUnique; } - else version (DragonFlyBSD) + else version (OpenBSD) { - return readLink("/proc/curproc/file"); + import core.sys.openbsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC_ARGS, KERN_PROC_ARGV; + import core.sys.posix.unistd : getpid; + import std.conv : to; + import std.exception : enforce, errnoEnforce; + import std.process : searchPathFor; + + int[4] mib = [CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV]; + size_t len; + + auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); + errnoEnforce(result == 0); + + auto argv = new char*[len - 1]; + result = sysctl(mib.ptr, mib.length, argv.ptr, &len, null, 0); + errnoEnforce(result == 0); + + auto argv0 = argv[0]; + if (*argv0 == '/' || *argv0 == '.') + { + import core.sys.posix.stdlib : realpath; + auto absolutePath = realpath(argv0, null); + scope (exit) + { + if (absolutePath) + free(absolutePath); + } + errnoEnforce(absolutePath); + return to!(string)(absolutePath); + } + else + { + auto absolutePath = searchPathFor(to!string(argv0)); + errnoEnforce(absolutePath); + return absolutePath; + } } else version (Solaris) { diff --git a/libphobos/src/std/math.d b/libphobos/src/std/math.d index 3d18cfa528b..ff368b79f9d 100644 --- a/libphobos/src/std/math.d +++ b/libphobos/src/std/math.d @@ -167,19 +167,14 @@ version (SystemZ) version = IBMZ_Any; version (RISCV32) version = RISCV_Any; version (RISCV64) version = RISCV_Any; -version (D_InlineAsm_X86) -{ - version = InlineAsm_X86_Any; -} -else version (D_InlineAsm_X86_64) -{ - version = InlineAsm_X86_Any; -} +version (D_InlineAsm_X86) version = InlineAsm_X86_Any; +version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; -version (CRuntime_Microsoft) +version (InlineAsm_X86_Any) version = InlineAsm_X87; +version (InlineAsm_X87) { - version (InlineAsm_X86_Any) - version = MSVC_InlineAsm; + static assert(real.mant_dig == 64); + version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC; } version (X86_64) version = StaticallyHaveSSE; @@ -3610,7 +3605,7 @@ real log1p(real x) @safe pure nothrow @nogc real log2(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) - return core.math.yl2x(x, 1); + return core.math.yl2x(x, 1.0L); else { // Special cases are the same as for log. @@ -4586,19 +4581,21 @@ real round(real x) @trusted nothrow @nogc * If the fractional part of x is exactly 0.5, the return value is rounded * away from zero. * - * $(BLUE This function is Posix-Only.) + * $(BLUE This function is not implemented for Digital Mars C runtime.) */ long lround(real x) @trusted nothrow @nogc { - version (Posix) - return core.stdc.math.llroundl(x); - else + version (CRuntime_DigitalMars) assert(0, "lround not implemented"); + else + return core.stdc.math.llroundl(x); } -version (Posix) +/// +@safe nothrow @nogc unittest { - @safe nothrow @nogc unittest + version (CRuntime_DigitalMars) {} + else { assert(lround(0.49) == 0); assert(lround(0.5) == 1); diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d index 64fa2f93c7e..43a1ba59527 100644 --- a/libphobos/src/std/parallelism.d +++ b/libphobos/src/std/parallelism.d @@ -40,6 +40,15 @@ License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) */ module std.parallelism; +version (OSX) + version = Darwin; +else version (iOS) + version = Darwin; +else version (TVOS) + version = Darwin; +else version (WatchOS) + version = Darwin; + /// @system unittest { @@ -86,107 +95,82 @@ import std.meta; import std.range.primitives; import std.traits; -version (OSX) -{ - version = useSysctlbyname; -} -else version (FreeBSD) -{ - version = useSysctlbyname; -} -else version (DragonFlyBSD) -{ - version = useSysctlbyname; -} -else version (NetBSD) -{ - version = useSysctlbyname; -} +/* +(For now public undocumented with reserved name.) +A lazily initialized global constant. The underlying value is a shared global +statically initialized to `outOfBandValue` which must not be a legit value of +the constant. Upon the first call the situation is detected and the global is +initialized by calling `initializer`. The initializer is assumed to be pure +(even if not marked as such), i.e. return the same value upon repeated calls. +For that reason, no special precautions are taken so `initializer` may be called +more than one time leading to benign races on the cached value. -version (Windows) -{ - // BUGS: Only works on Windows 2000 and above. - shared static this() - { - import core.sys.windows.windows : SYSTEM_INFO, GetSystemInfo; - import std.algorithm.comparison : max; +In the quiescent state the cost of the function is an atomic load from a global. - SYSTEM_INFO si; - GetSystemInfo(&si); - totalCPUs = max(1, cast(uint) si.dwNumberOfProcessors); - } +Params: + T = The type of the pseudo-constant (may be qualified) + outOfBandValue = A value that cannot be valid, it is used for initialization + initializer = The function performing initialization; must be `nothrow` -} -else version (linux) -{ - shared static this() - { - import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; - totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN); - } -} -else version (Solaris) -{ - shared static this() - { - import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; - totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN); - } -} -else version (useSysctlbyname) +Returns: + The lazily initialized value +*/ +@property pure +T __lazilyInitializedConstant(T, alias outOfBandValue, alias initializer)() +if (is(Unqual!T : T) + && is(typeof(initializer()) : T) + && is(typeof(outOfBandValue) : T)) { - extern(C) int sysctlbyname( - const char *, void *, size_t *, void *, size_t - ); - - shared static this() - { - version (OSX) - { - auto nameStr = "machdep.cpu.core_count\0".ptr; - } - else version (FreeBSD) + static T impl() nothrow + { + // Thread-local cache + static Unqual!T tls = outOfBandValue; + auto local = tls; + // Shortest path, no atomic operations + if (local != outOfBandValue) return local; + // Process-level cache + static shared Unqual!T result = outOfBandValue; + // Initialize both process-level cache and tls + local = atomicLoad(result); + if (local == outOfBandValue) { - auto nameStr = "hw.ncpu\0".ptr; + local = initializer(); + atomicStore(result, local); } - else version (DragonFlyBSD) - { - auto nameStr = "hw.ncpu\0".ptr; - } - else version (NetBSD) - { - auto nameStr = "hw.ncpu\0".ptr; - } - - uint ans; - size_t len = uint.sizeof; - sysctlbyname(nameStr, &ans, &len, null, 0); - totalCPUs = ans; + tls = local; + return local; } + import std.traits : SetFunctionAttributes; + alias Fun = SetFunctionAttributes!(typeof(&impl), "D", + functionAttributes!(typeof(&impl)) | FunctionAttribute.pure_); + auto purified = (() @trusted => cast(Fun) &impl)(); + return purified(); } -else -{ - static assert(0, "Don't know how to get N CPUs on this OS."); -} -immutable size_t cacheLineSize; -shared static this() +// Returns the size of a cache line. +alias cacheLineSize = + __lazilyInitializedConstant!(immutable(size_t), size_t.max, cacheLineSizeImpl); + +private size_t cacheLineSizeImpl() @nogc nothrow @trusted { + size_t result = 0; import core.cpuid : datacache; - size_t lineSize = 0; - foreach (cachelevel; datacache) + foreach (ref const cachelevel; datacache) { - if (cachelevel.lineSize > lineSize && cachelevel.lineSize < uint.max) + if (cachelevel.lineSize > result && cachelevel.lineSize < uint.max) { - lineSize = cachelevel.lineSize; + result = cachelevel.lineSize; } } - - cacheLineSize = lineSize; + return result; } +@nogc @safe nothrow unittest +{ + assert(cacheLineSize == cacheLineSizeImpl); +} /* Atomics code. These forward to core.atomic, but are written like this for two reasons: @@ -957,7 +941,81 @@ if (is(typeof(fun(args))) && isSafeTask!F) The total number of CPU cores available on the current machine, as reported by the operating system. */ -immutable uint totalCPUs; +alias totalCPUs = + __lazilyInitializedConstant!(immutable(uint), uint.max, totalCPUsImpl); + +uint totalCPUsImpl() @nogc nothrow @trusted +{ + version (Windows) + { + // BUGS: Only works on Windows 2000 and above. + import core.sys.windows.winbase : SYSTEM_INFO, GetSystemInfo; + import std.algorithm.comparison : max; + SYSTEM_INFO si; + GetSystemInfo(&si); + return max(1, cast(uint) si.dwNumberOfProcessors); + } + else version (linux) + { + import core.sys.linux.sched : CPU_COUNT, cpu_set_t, sched_getaffinity; + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + + cpu_set_t set = void; + if (sched_getaffinity(0, cpu_set_t.sizeof, &set) == 0) + { + int count = CPU_COUNT(&set); + if (count > 0) + return cast(uint) count; + } + return cast(uint) sysconf(_SC_NPROCESSORS_ONLN); + } + else version (Darwin) + { + import core.sys.darwin.sys.sysctl : sysctlbyname; + uint result; + size_t len = result.sizeof; + sysctlbyname("hw.physicalcpu", &result, &len, null, 0); + return result; + } + else version (DragonFlyBSD) + { + import core.sys.dragonflybsd.sys.sysctl : sysctlbyname; + uint result; + size_t len = result.sizeof; + sysctlbyname("hw.ncpu", &result, &len, null, 0); + return result; + } + else version (FreeBSD) + { + import core.sys.freebsd.sys.sysctl : sysctlbyname; + uint result; + size_t len = result.sizeof; + sysctlbyname("hw.ncpu", &result, &len, null, 0); + return result; + } + else version (NetBSD) + { + import core.sys.netbsd.sys.sysctl : sysctlbyname; + uint result; + size_t len = result.sizeof; + sysctlbyname("hw.ncpu", &result, &len, null, 0); + return result; + } + else version (Solaris) + { + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + return cast(uint) sysconf(_SC_NPROCESSORS_ONLN); + } + else version (OpenBSD) + { + import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf; + return cast(uint) sysconf(_SC_NPROCESSORS_ONLN); + } + else + { + static assert(0, "Don't know how to get N CPUs on this OS."); + } +} /* This class serves two purposes: @@ -3302,11 +3360,7 @@ terminating the main thread. }()); } -private shared uint _defaultPoolThreads; -shared static this() -{ - atomicStore(_defaultPoolThreads, totalCPUs - 1); -} +private shared uint _defaultPoolThreads = uint.max; /** These properties get and set the number of worker threads in the $(D TaskPool) @@ -3316,7 +3370,8 @@ number of worker threads in the instance returned by $(D taskPool). */ @property uint defaultPoolThreads() @trusted { - return atomicLoad(_defaultPoolThreads); + const local = atomicLoad(_defaultPoolThreads); + return local < uint.max ? local : totalCPUs - 1; } /// Ditto diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d index a4ba39c8336..ecb2c8b916e 100644 --- a/libphobos/src/std/socket.d +++ b/libphobos/src/std/socket.d @@ -146,6 +146,8 @@ class SocketException: Exception mixin basicExceptionCtors; } +version (CRuntime_Glibc) version = GNU_STRERROR; +version (CRuntime_UClibc) version = GNU_STRERROR; /* * Needs to be public so that SocketOSException can be thrown outside of @@ -159,7 +161,7 @@ string formatSocketError(int err) @trusted { char[80] buf; const(char)* cs; - version (CRuntime_Glibc) + version (GNU_STRERROR) { cs = strerror_r(err, buf.ptr, buf.length); } diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index c59bc4c219b..bbf785773d4 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -79,6 +79,10 @@ else version (NetBSD) { version = GENERIC_IO; } +else version (OpenBSD) +{ + version = GENERIC_IO; +} else version (DragonFlyBSD) { version = GENERIC_IO; @@ -93,12 +97,11 @@ version (Windows) { private alias FSChar = wchar; } -else version (Posix) +else { private alias FSChar = char; } -else - static assert(0); + version (Windows) { diff --git a/libphobos/src/std/system.d b/libphobos/src/std/system.d index e0b3dee8dae..353d692848a 100644 --- a/libphobos/src/std/system.d +++ b/libphobos/src/std/system.d @@ -30,6 +30,9 @@ immutable win64, /// Microsoft 64 bit Windows systems linux, /// All Linux Systems, except for Android osx, /// Mac OS X + iOS, /// iOS + tvOS, /// tvOS + watchOS, /// watchOS freeBSD, /// FreeBSD netBSD, /// NetBSD dragonFlyBSD, /// DragonFlyBSD @@ -44,6 +47,9 @@ immutable else version (Android) OS os = OS.android; else version (linux) OS os = OS.linux; else version (OSX) OS os = OS.osx; + else version (iOS) OS os = OS.iOS; + else version (tvOS) OS os = OS.tvOS; + else version (watchOS) OS os = OS.watchOS; else version (FreeBSD) OS os = OS.freeBSD; else version (NetBSD) OS os = OS.netBSD; else version (DragonFlyBSD) OS os = OS.dragonFlyBSD; |