Import upstream changes of `TSC.Process` (#460)

This commit is contained in:
omochimetaru 2024-05-20 18:27:46 +09:00 committed by GitHub
parent bb9a91ce0b
commit 7613683095
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1529 additions and 1221 deletions

View File

@ -116,9 +116,23 @@ let package = Package(
],
exclude: ["Utilities/README.md"]
),
.target(
/** Shim target to import missing C headers in Darwin and Glibc modulemap. */
name: "TSCclibc",
cSettings: [
.define("_GNU_SOURCE", .when(platforms: [.linux])),
]
),
.target(
/** Cross-platform access to bare `libc` functionality. */
name: "TSCLibc"
),
.target(
name: "CartonHelpers",
dependencies: [],
dependencies: [
"TSCclibc",
"TSCLibc"
],
exclude: ["Basics/README.md"]
),
.target(name: "WebDriverClient", dependencies: []),

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Foundation
#if os(Windows)
import WinSDK
#endif
/// This class bridges the gap between Darwin and Linux Foundation Threading API.
/// It provides closure based execution and a join method to block the calling thread
/// until the thread is finished executing.
final public class Thread {
/// The thread implementation which is Foundation.Thread on Linux and
/// a Thread subclass which provides closure support on Darwin.
private var thread: ThreadImpl!
/// Condition variable to support blocking other threads using join when this thread has not finished executing.
private var finishedCondition: Condition
/// A boolean variable to track if this thread has finished executing its task.
private var isFinished: Bool
/// Creates an instance of thread class with closure to be executed when start() is called.
public init(task: @escaping () -> Void) {
isFinished = false
finishedCondition = Condition()
// Wrap the task with condition notifying any other threads blocked due to this thread.
// Capture self weakly to avoid reference cycle. In case Thread is deinited before the task
// runs, skip the use of finishedCondition.
let theTask = { [weak self] in
if let strongSelf = self {
precondition(!strongSelf.isFinished)
strongSelf.finishedCondition.whileLocked {
task()
strongSelf.isFinished = true
strongSelf.finishedCondition.broadcast()
}
} else {
// If the containing thread has been destroyed, we can ignore the finished condition and just run the
// task.
task()
}
}
self.thread = ThreadImpl(block: theTask)
}
/// Starts the thread execution.
public func start() {
thread.start()
}
/// Blocks the calling thread until this thread is finished execution.
public func join() {
finishedCondition.whileLocked {
while !isFinished {
finishedCondition.wait()
}
}
}
/// Causes the calling thread to yield execution to another thread.
public static func yield() {
#if os(Windows)
SwitchToThread()
#else
sched_yield()
#endif
}
}
#if canImport(Darwin)
/// A helper subclass of Foundation's Thread with closure support.
final private class ThreadImpl: Foundation.Thread {
/// The task to be executed.
private let task: () -> Void
override func main() {
task()
}
init(block task: @escaping () -> Void) {
self.task = task
}
}
#else
// Thread on Linux supports closure so just use it directly.
typealias ThreadImpl = Foundation.Thread
#endif

View File

@ -809,7 +809,7 @@ private protocol _FileWatcher {
let delegate: FSEventStreamDelegate
/// The thread on which the stream is running.
private var thread: Thread?
private var thread: Foundation.Thread?
/// The run loop attached to the stream.
private var runLoop: CFRunLoop?
@ -844,7 +844,7 @@ private protocol _FileWatcher {
// Start the runloop.
public func start() throws {
let thread = Thread { [weak self] in
let thread = Foundation.Thread { [weak self] in
guard let `self` = self else { return }
self.runLoop = CFRunLoopGetCurrent()
let queue = DispatchQueue(label: "org.swiftwasm.carton.FSWatch")

101
Sources/TSCLibc/libc.swift Normal file
View File

@ -0,0 +1,101 @@
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
#if canImport(Glibc)
@_exported import Glibc
#elseif canImport(Musl)
@_exported import Musl
#elseif os(Windows)
@_exported import CRT
@_exported import WinSDK
#else
@_exported import Darwin.C
#endif
#if os(Windows)
private func __randname(_ buffer: UnsafeMutablePointer<CChar>) {
let alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
_ = (0 ..< 6).map { index in
buffer[index] = CChar(alpha.shuffled().randomElement()!.utf8.first!)
}
}
// char *mkdtemp(char *template);
// NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
public func mkdtemp(
_ template: UnsafeMutablePointer<CChar>?
) -> UnsafeMutablePointer<CChar>? {
// Although the signature of the function is `char *(*)(char *)`, the C
// library treats it as `char *(*)(char * _Nonull)`. Most implementations
// will simply use and trigger a segmentation fault on x86 (and similar faults
// on other architectures) when the memory is accessed. This roughly emulates
// that by terminating in the case even though it is possible for us to return
// an error.
guard let template = template else { fatalError() }
let length: Int = strlen(template)
// Validate the precondition: the template must terminate with 6 `X` which
// will be filled in to generate a unique directory.
guard length >= 6, memcmp(template + length - 6, "XXXXXX", 6) == 0 else {
_set_errno(EINVAL)
return nil
}
// Attempt to create the directory
var retries: Int = 100
repeat {
__randname(template + length - 6)
if _mkdir(template) == 0 {
return template
}
retries = retries - 1
} while retries > 0
return nil
}
// int mkstemps(char *template, int suffixlen);
public func mkstemps(
_ template: UnsafeMutablePointer<CChar>?,
_ suffixlen: Int32
) -> Int32 {
// Although the signature of the function is `char *(*)(char *)`, the C
// library treats it as `char *(*)(char * _Nonull)`. Most implementations
// will simply use and trigger a segmentation fault on x86 (and similar faults
// on other architectures) when the memory is accessed. This roughly emulates
// that by terminating in the case even though it is possible for us to return
// an error.
guard let template = template else { fatalError() }
let length: Int = strlen(template)
// Validate the precondition: the template must terminate with 6 `X` which
// will be filled in to generate a unique directory.
guard length >= 6, memcmp(template + length - Int(suffixlen) - 6, "XXXXXX", 6) == 0 else {
_set_errno(EINVAL)
return -1
}
// Attempt to create file
var retries: Int = 100
repeat {
__randname(template + length - Int(suffixlen) - 6)
var fd: CInt = -1
if _sopen_s(&fd, template, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
_SH_DENYNO, _S_IREAD | _S_IWRITE) == 0 {
return fd
}
retries = retries - 1
} while retries > 0
return -1
}
#endif

View File

@ -0,0 +1,21 @@
#if defined(__linux__)
#include <sys/inotify.h>
#endif
#define STR_EXPAND(VALUE) #VALUE
#define STR(VALUE) STR_EXPAND(VALUE)
static inline const char* SPM_VendorNameString() {
#ifdef SPM_VENDOR_NAME
return STR(SPM_VENDOR_NAME);
#else
return "";
#endif
}
static inline const char* SPM_BuildIdentifierString() {
#ifdef SPM_BUILD_IDENT
return STR(SPM_BUILD_IDENT);
#else
return "";
#endif
}

View File

@ -0,0 +1,5 @@
module TSCclibc {
header "TSCclibc.h"
header "process.h"
export *
}

View File

@ -0,0 +1,12 @@
#if defined(__linux__)
#include <spawn.h>
#include <stdbool.h>
// Wrapper method for posix_spawn_file_actions_addchdir_np that fails on Linux versions that do not have this method available.
int SPM_posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *restrict file_actions, const char *restrict path);
// Runtime check for the availability of posix_spawn_file_actions_addchdir_np. Returns 0 if the method is available, -1 if not.
bool SPM_posix_spawn_file_actions_addchdir_np_supported();
#endif

View File

@ -0,0 +1,35 @@
#if defined(__linux__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for posix_spawn_file_actions_addchdir_np */
#endif
#include <errno.h>
#include "process.h"
int SPM_posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *restrict file_actions, const char *restrict path) {
#if defined(__GLIBC__)
# if __GLIBC_PREREQ(2, 29)
return posix_spawn_file_actions_addchdir_np(file_actions, path);
# else
return ENOSYS;
# endif
#else
return ENOSYS;
#endif
}
bool SPM_posix_spawn_file_actions_addchdir_np_supported() {
#if defined(__GLIBC__)
# if __GLIBC_PREREQ(2, 29)
return true;
# else
return false;
# endif
#else
return false;
#endif
}
#endif