Skip to content

Simple portions of the Windows Port #1796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Dec 11, 2018
Merged

Conversation

compnerd
Copy link
Member

@compnerd compnerd commented Dec 7, 2018

This is set of changes that are simple and non-controversial for the Windows port. This allows us to work on a smaller set of changes that have more interesting consequences (like threading and locking) without having to worry about the additional context of these patches. It also makes it easier to work on the port as it reduces the likelihood of conflicts.

@compnerd
Copy link
Member Author

compnerd commented Dec 7, 2018

@swift-ci please test

@compnerd
Copy link
Member Author

compnerd commented Dec 7, 2018

CC: @parkera @millenomi
As discussed on #1783, this splits off the "simple" parts of the change so that we can focus on the possibly worrisome patches.

@compnerd
Copy link
Member Author

compnerd commented Dec 7, 2018

hahaha, __unused in the header is causing the issue with glibc!

@compnerd
Copy link
Member Author

compnerd commented Dec 7, 2018

@swift-ci please test

@compnerd
Copy link
Member Author

compnerd commented Dec 7, 2018

@swift-ci please test Linux platform

@@ -307,29 +304,21 @@ CF_EXPORT int _NS_access(const char *name, int amode);
#define WIN32_LEAN_AND_MEAN

#ifndef WINVER
#define WINVER 0x0501
#define WINVER 0x0601
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -351,7 +351,7 @@ CFBurstTrieRef CFBurstTrieCreateFromFile(CFStringRef path) {
if (stat(filename, &sb) != 0) return NULL;

/* Check if file can be opened */
if ((fd=open(filename, CF_OPENFLGS|O_RDONLY)) < 0) return NULL;
if ((fd = open(filename, CF_OPENFLGS|O_RDONLY, 0)) < 0) return NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to use _wsopen_s on Windows, not open.

Unfortunately, the story with C APIs is the same as with the *A vs *W variants of Win32 functions -- you must use the wide-character variants for Unicode to work at all.

Please go through and audit any C API calls through SCF and make sure that the _w variants are used on Windows. It's probably a good idea to separate all C APIs which take strings into an abstraction layer somewhere.

I'd do something like this. Have an abstraction layer which provides both UTF-8 and UTF-16 variants of each C API that we use:

int scf_open(const char *);
int scf_wopen(const uint16_t *, size_t len); // do NOT use wchar_t, it's different size on different platforms
int scf_cfopen(CFStringRef);

In the implementations (pseudocode):

int scf_open(const char *s) {
    if (windows) {
        // We have a UTF-8 string and are on Windows, convert to UTF-16
        auto x = convert_to_utf16(s);
        return scf_wopen(x.ptr, x.length);
    } else {
        // We have a UTF-8 string and are on UNIX, no conversion needed
        return ::open(s);
    }
}

int scf_wopen(const uint16_t *s, size_t len) {
    if (windows) {
        // We have a UTF-16 string and are on Windows, no conversion needed
        return ::_wsopen_s(s);
    } else {
        // We have a UTF-16 string and are on UNIX, convert to UTF-8
        return scf_open(convert_to_utf8(s));
    }
}

int scf_cfopen(CFStringRef s) {
    if (windows) {
        return scf_wopen(CFStringGetCharactersPtr(s), CFStringGetLength(s));
    } else {
        char filename[PATH_MAX];
        CFStringGetCString(s, filename, PATH_MAX, kCFStringEncodingUTF8);
        return scf_open(filename);
    }
}

That way you can call either the UTF-8 or UTF-16 variant depending on what kind of string you have coming from the input, and it'll do the right thing on each platform in order to minimize conversions.

For example, when you have a CFString and need to pass it to a native Win32 API, you can actually avoid the UTF-8 conversion you're doing here (which again is currently broken due to UTF-8 not being supported).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

open is not open, it is a macro, and replaces it with _NS_open, and it does go through _wopen_s. I believe that all of the ones have already been replaced with _NS_* equivalents.

Copy link
Contributor

@jakepetroules jakepetroules Dec 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, didn't notice that. However, the approach I suggested would still be more performant on Windows because you're not converting (in many cases) from UTF-16 to UTF-8 right back to UTF-16 again. Having two roundtrips like that every time a Win32 API is called is going to add up.

But performance improvements like that can be done in a later change, so I rescind my "changes requested" for now. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree, that would be a great follow up!

@jakepetroules jakepetroules dismissed their stale review December 8, 2018 02:24

code is correct, suggested perf improvements can be done in a later patch

C does not support default valued arguments.  Remove the default valued
argument and update the invocations.
Not all deployment targets use POSIX threads (pthreads).  Use the POSIX
mandated macro `_POSIX_THREADS` to detect whether POSIX threads are in
use.  Conditionally include `unistd.h` which is the Unix standard header
which provides the definition for `_POSIX_THREADS` if the platform uses
POSIX threads.  Unfortunately, clang does not define `__unix__` for
macOS (Bob Wilson does not recall why this was the case, and we have yet
to test if we can get away with defining `__unix__` for the platform
without breaking existing software).
We need to forward declare the struct as otherwise the definition is
local to the declaration and cannot be defined.  This addresses the
`-Wvisibility` warning when building for Windows.
Use `<sys/param.h>` for the definition of min/max on Linux.  This header
is also available on FreeBSD.  On Windows, we inherit the definition
from `generic_win_base.h` from libdispatch.
For compatibility, define a mode_t which is an integral type.  This
matches the code in libdispatch as well as matches the type definition
on Linux.
fts.h is a BSD4.4 conforming header.  Linux (via glibc) and Haiku also
provide it.  Unfortunately, there is no easy check for this header.  It
is not present on AIX, HP-UX, IRIX, OSX/1, Solaris, and BeOS.  The
current guard at least allows us to build for Windows.
`dirent.h` is part of SuS, so it should be available on pretty much any
Unix.  Guard the inclusion for Windows.
Rather than trying to define `scalbn` in terms of `scalb`, use the MSVC
provided definition.
Although `major` and `minor` are not part of POSIX or SuS, treat them as
part of SuS as many Unixes provide the interfaces.  `dirent` is part of
the SuS and can be safely guarded by this check.
Guard the os_unfair_lock definition to pthread to when POSIX threads are
present.  The single use of `os_unfair_lock` will be resolved later with
the use of `SRWLOCK` on Windows.
rdar://problem/7923891 is no longer relevant as we are building against
a modern libdispatch when targeting windows.  Remove the conflicting
macro definition which breaks CoreFoundation.
Replicate the QoS groups for Windows based on the Linux behaviour
`bzero` is deprecated, use `memset` as suggested by the specification.
This avoids a warning for the inclusion of `strings.h`.
The Apple System Logger is not available on Windows (as it is not open
source).  Do not include `asl.h` on Windows.
Use the system provided definition through `time.h` instead.  This has
been provided for a long time now.
`unistd.h` is the unix standard header.  This header cannot be included
on all systems.  It should normally be guarded by `__unix__`.  However,
macOS X does not define `__unix__` for some reason, so add an additional
condition for the inclusion.
Win32 uses WinSock2 rather than the BSD sockets API.  Guard the
inclusion accordingly.
The use of the signed value here would result in a tautological
comparison which was always out of range.  Use the unsigned type
instead.
Windows has a macro `_environ` which provides access through the
environment accessor function `__environ_p`.
The function `_CFLocaleCopyLocaleIdentifierByAddingLikelySubtags` is
used internally.  Ensure that we provide the definition of the function.
The FLS APIs provide additional flexibility and give similar semantics
as pthread TLS.
`sys/mman.h` is a POSIX header.  Windows is a non-POSIX environment.
Guard the inclusion accordingly.
The local definition must match the signature from msvcrt otherwise
there are type mismatch errors.  Just rename it to `_CF_isspace` and
change the signature to be more ergonomic.
The macro needs to be defined for the Windows port.  Duplicate the
definition from the Linux path.
We wish to use the constant CFStrings when targeting Windows as well.
We will consider the list last.  There is no mention of `langs`
anywhere.  Assume that this is left over from previous builds.
This was not defined, and would break the build for Windows.
Reorder the definitions to ensure that the symbol is defined before the
use.
Load the timezone information from the registry on Windows.  Add missing
definition and define structures for Windows as well.
…ifiers`

Add a cast for the discarded qualifier.
Clean up a formatting warning.
Declare the function for the Windows port.
Add a local definition of `timeradd` for Windows.
Windows uses `signed char` rather than `unsigned char`.  Add a cast to
silence the `-Wpointer-sign` warning.
Update the signatures for the timer functions to match the current
declarations.
Ensure that the local macro definitions are defined early enough for the
forward declarations to be provided for the use.
If `dispatch/private.h` is not available, then we fall back to forward
declaring dispatch interfaces.  One of those is the `mach_port_t` shim
typedef.
Include `process.h` for the declaration of the threading functions.
This header is used pervasively, and we use certain types defined from
this umbrella header.
Do not attempt to define the core COM types on Windows.  These conflict
with the system provided definitions which are included via
ForSwiftFoundationOnly.h.
@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

I think that I can improve some of the Windows implementations, but, lets get the basic bits in and do that in a follow up.

@compnerd compnerd merged commit b23dc8e into swiftlang:master Dec 11, 2018
@compnerd compnerd deleted the simple-windows branch December 11, 2018 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants