diff --git a/stdlib/public/Glibc/CMakeLists.txt b/stdlib/public/Glibc/CMakeLists.txt index e80197d0093e1..2358a0366eada 100644 --- a/stdlib/public/Glibc/CMakeLists.txt +++ b/stdlib/public/Glibc/CMakeLists.txt @@ -29,6 +29,7 @@ swift_install_in_component(stdlib add_swift_library(swiftGlibc IS_SDK_OVERLAY Glibc.swift + Misc.c FILE_DEPENDS copy_glibc_module "${SWIFTLIB_DIR}/glibc" INSTALL_IN_COMPONENT stdlib-experimental) diff --git a/stdlib/public/Glibc/Glibc.swift b/stdlib/public/Glibc/Glibc.swift index 8891634252824..6a38eed6c529a 100644 --- a/stdlib/public/Glibc/Glibc.swift +++ b/stdlib/public/Glibc/Glibc.swift @@ -29,6 +29,82 @@ public var errno: Int32 { // fcntl.h //===----------------------------------------------------------------------===// +@warn_unused_result +@_silgen_name("_swift_Glibc_open") +func _swift_Glibc_open(path: UnsafePointer, + _ oflag: CInt, _ mode: mode_t) -> CInt + +@warn_unused_result +@_silgen_name("_swift_Glibc_openat") +func _swift_Glibc_openat(fd: CInt, + _ path: UnsafePointer, + _ oflag: CInt, _ mode: mode_t) -> CInt + +@warn_unused_result +public func open(path: UnsafePointer, _ oflag: CInt) -> CInt { + return _swift_Glibc_open(path, oflag, 0) +} + +@warn_unused_result +public func open(path: UnsafePointer, _ oflag: CInt, + _ mode: mode_t) -> CInt { + return _swift_Glibc_open(path, oflag, mode) +} + +@warn_unused_result +public func openat(fd: CInt, _ path: UnsafePointer, + _ oflag: CInt) -> CInt { + return _swift_Glibc_openat(fd, path, oflag, 0) +} + +@warn_unused_result +public func openat(fd: CInt, _ path: UnsafePointer, + _ oflag: CInt, _ mode: mode_t) -> CInt { + return _swift_Glibc_openat(fd, path, oflag, mode) +} + +@warn_unused_result +@_silgen_name("_swift_Glibc_fcntl") +internal func _swift_Glibc_fcntl( + fd: CInt, + _ cmd: CInt, + _ value: CInt + ) -> CInt + +@warn_unused_result +@_silgen_name("_swift_Glibc_fcntlPtr") +internal func _swift_Glibc_fcntlPtr( + fd: CInt, + _ cmd: CInt, + _ ptr: UnsafeMutablePointer + ) -> CInt + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt + ) -> CInt { + return _swift_Glibc_fcntl(fd, cmd, 0) +} + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt, + _ value: CInt + ) -> CInt { + return _swift_Glibc_fcntl(fd, cmd, value) +} + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt, + _ ptr: UnsafeMutablePointer + ) -> CInt { + return _swift_Glibc_fcntlPtr(fd, cmd, ptr) +} + public var S_IFMT: mode_t { return mode_t(0o170000) } public var S_IFIFO: mode_t { return mode_t(0o010000) } public var S_IFCHR: mode_t { return mode_t(0o020000) } @@ -57,6 +133,8 @@ public var S_ISUID: mode_t { return mode_t(0o004000) } public var S_ISGID: mode_t { return mode_t(0o002000) } public var S_ISVTX: mode_t { return mode_t(0o001000) } + + //===----------------------------------------------------------------------===// // signal.h //===----------------------------------------------------------------------===// @@ -74,3 +152,46 @@ public var SIG_HOLD: __sighandler_t { } #endif +//===----------------------------------------------------------------------===// +// semaphore.h +//===----------------------------------------------------------------------===// + +/// The value returned by `sem_open()` in the case of failure. +public var SEM_FAILED: UnsafeMutablePointer { + // The value is ABI. Value verified to be correct on Linux. + return UnsafeMutablePointer(bitPattern: 0) +} + +@warn_unused_result +@_silgen_name("_swift_Glibc_sem_open2") +internal func _swift_Glibc_sem_open2( + name: UnsafePointer, + _ oflag: CInt + ) -> UnsafeMutablePointer + +@warn_unused_result +@_silgen_name("_swift_Glibc_sem_open4") +internal func _swift_Glibc_sem_open4( + name: UnsafePointer, + _ oflag: CInt, + _ mode: mode_t, + _ value: CUnsignedInt + ) -> UnsafeMutablePointer + +@warn_unused_result +public func sem_open( + name: UnsafePointer, + _ oflag: CInt + ) -> UnsafeMutablePointer { + return _swift_Glibc_sem_open2(name, oflag) +} + +@warn_unused_result +public func sem_open( + name: UnsafePointer, + _ oflag: CInt, + _ mode: mode_t, + _ value: CUnsignedInt + ) -> UnsafeMutablePointer { + return _swift_Glibc_sem_open4(name, oflag, mode, value) +} diff --git a/stdlib/public/Glibc/Misc.c b/stdlib/public/Glibc/Misc.c new file mode 100644 index 0000000000000..7f7c2c1f22845 --- /dev/null +++ b/stdlib/public/Glibc/Misc.c @@ -0,0 +1,44 @@ +//===--- Misc.c - Glibc overlay helpers -----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 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 the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include +#include + +extern int +_swift_Glibc_open(const char *path, int oflag, mode_t mode) { + return open(path, oflag, mode); +} + +extern int +_swift_Glibc_openat(int fd, const char *path, int oflag, mode_t mode) { + return openat(fd, path, oflag, mode); +} + +extern sem_t *_swift_Glibc_sem_open2(const char *name, int oflag) { + return sem_open(name, oflag); +} + +extern sem_t *_swift_Glibc_sem_open4(const char *name, int oflag, + mode_t mode, unsigned int value) { + return sem_open(name, oflag, mode, value); +} + +extern int +_swift_Glibc_fcntl(int fd, int cmd, int value) { + return fcntl(fd, cmd, value); +} + +extern int +_swift_Glibc_fcntlPtr(int fd, int cmd, void* ptr) { + return fcntl(fd, cmd, ptr); +} + diff --git a/stdlib/public/SDK/Darwin/Darwin.swift b/stdlib/public/SDK/Darwin/Darwin.swift index 47b19024b5ce6..31cfe96ef243a 100644 --- a/stdlib/public/SDK/Darwin/Darwin.swift +++ b/stdlib/public/SDK/Darwin/Darwin.swift @@ -177,6 +177,48 @@ public func openat(fd: CInt, _ path: UnsafePointer, return _swift_Darwin_openat(fd, path, oflag, mode) } +@warn_unused_result +@_silgen_name("_swift_Darwin_fcntl") +internal func _swift_Darwin_fcntl( + fd: CInt, + _ cmd: CInt, + _ value: CInt + ) -> CInt + +@warn_unused_result +@_silgen_name("_swift_Darwin_fcntlPtr") +internal func _swift_Darwin_fcntlPtr( + fd: CInt, + _ cmd: CInt, + _ ptr: UnsafeMutablePointer + ) -> CInt + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt + ) -> CInt { + return _swift_Darwin_fcntl(fd, cmd, 0) +} + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt, + _ value: CInt + ) -> CInt { + return _swift_Darwin_fcntl(fd, cmd, value) +} + +@warn_unused_result +public func fcntl( + fd: CInt, + _ cmd: CInt, + _ ptr: UnsafeMutablePointer + ) -> CInt { + return _swift_Darwin_fcntlPtr(fd, cmd, ptr) +} + public var S_IFMT: mode_t { return mode_t(0o170000) } public var S_IFIFO: mode_t { return mode_t(0o010000) } public var S_IFCHR: mode_t { return mode_t(0o020000) } diff --git a/stdlib/public/SDK/Darwin/Misc.mm b/stdlib/public/SDK/Darwin/Misc.mm index 207c7dbbfde1f..f54927e661160 100644 --- a/stdlib/public/SDK/Darwin/Misc.mm +++ b/stdlib/public/SDK/Darwin/Misc.mm @@ -32,3 +32,13 @@ return sem_open(name, oflag, mode, value); } +extern "C" int +_swift_Darwin_fcntl(int fd, int cmd, int value) { + return fcntl(fd, cmd, value); +} + +extern "C" int +_swift_Darwin_fcntlPtr(int fd, int cmd, void* ptr) { + return fcntl(fd, cmd, ptr); +} + diff --git a/test/1_stdlib/POSIX.swift b/test/1_stdlib/POSIX.swift index dd19fc5c05cad..e18efbc127828 100644 --- a/test/1_stdlib/POSIX.swift +++ b/test/1_stdlib/POSIX.swift @@ -1,29 +1,32 @@ // RUN: %target-run-simple-swift // REQUIRES: executable_test -// XFAIL: linux -// FIXME: Glibc needs the same overlay. - import StdlibUnittest -import Darwin +#if os(Linux) + import Glibc +#else + import Darwin +#endif -var POSIXSemaphore = TestSuite("POSIXSemaphore") +var POSIXTests = TestSuite("POSIXTests") let semaphoreName = "TestSem" +let fn = "test.txt" -POSIXSemaphore.setUp { +POSIXTests.setUp { sem_unlink(semaphoreName) + unlink(fn) } // Failed semaphore creation. -POSIXSemaphore.test("sem_open fail") { +POSIXTests.test("sem_open fail") { let sem = sem_open(semaphoreName, 0) expectEqual(SEM_FAILED, sem) expectEqual(ENOENT, errno) } // Successful semaphore creation. -POSIXSemaphore.test("sem_open success") { +POSIXTests.test("sem_open success") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) @@ -35,7 +38,7 @@ POSIXSemaphore.test("sem_open success") { } // Successful semaphore creation with O_EXCL. -POSIXSemaphore.test("sem_open O_EXCL success") { +POSIXTests.test("sem_open O_EXCL success") { let sem = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) expectNotEqual(SEM_FAILED, sem) @@ -47,7 +50,7 @@ POSIXSemaphore.test("sem_open O_EXCL success") { } // Successful creation and re-obtaining of existing semaphore. -POSIXSemaphore.test("sem_open existing") { +POSIXTests.test("sem_open existing") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) @@ -64,7 +67,7 @@ POSIXSemaphore.test("sem_open existing") { } // Fail because the semaphore already exists. -POSIXSemaphore.test("sem_open existing O_EXCL fail") { +POSIXTests.test("sem_open existing O_EXCL fail") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) @@ -78,6 +81,111 @@ POSIXSemaphore.test("sem_open existing O_EXCL fail") { let res2 = sem_unlink(semaphoreName) expectEqual(0, res2) } + +// Fail because file doesn't exist. +POSIXTests.test("fcntl(CInt, CInt): fail") { + let fd = open(fn, 0) + expectEqual(-1, fd) + expectEqual(ENOENT, errno) + + let _ = fcntl(fd, F_GETFL) + expectEqual(EBADF, errno) +} + +// Change modes on existing file. +POSIXTests.test("fcntl(CInt, CInt): F_GETFL/F_SETFL success with file") { + // Create and open file. + let fd = open(fn, O_CREAT, 0o666) + expectGT(Int(fd), 0) + + var flags = fcntl(fd, F_GETFL) + expectGE(Int(flags), 0) + + // Change to APPEND mode... + var rc = fcntl(fd, F_SETFL, O_APPEND) + expectEqual(0, rc) + + flags = fcntl(fd, F_GETFL) + expectEqual(flags | O_APPEND, flags) + + // Change back... + rc = fcntl(fd, F_SETFL, 0) + expectEqual(0, rc) + + flags = fcntl(fd, F_GETFL) + expectGE(Int(flags), 0) + + // Clean up... + rc = close(fd) + expectEqual(0, rc) + + rc = unlink(fn) + expectEqual(0, rc) +} + +POSIXTests.test("fcntl(CInt, CInt, CInt): block and unblocking sockets success") { + // Create socket, note: socket created by default in blocking mode... + let sock = socket(PF_INET, 1, 0) + expectGT(Int(sock), 0) + + var flags = fcntl(sock, F_GETFL) + expectGE(Int(flags), 0) + + // Change mode of socket to non-blocking... + var rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK) + expectEqual(0, rc) + + flags = fcntl(sock, F_GETFL) + expectEqual((flags | O_NONBLOCK), flags) + + // Change back to blocking... + rc = fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) + expectEqual(0, rc) + + flags = fcntl(sock, F_GETFL) + expectGE(Int(flags), 0) + + // Clean up... + rc = close(sock) + expectEqual(0, rc) +} + +POSIXTests.test("fcntl(CInt, CInt, UnsafeMutablePointer): locking and unlocking success") { + // Create the file and add data to it... + var fd = open(fn, O_CREAT | O_WRONLY, 0o666) + expectGT(Int(fd), 0) + + let data = "Testing 1 2 3" + let bytesWritten = write(fd, data, data.utf8.count) + expectEqual(data.utf8.count, bytesWritten) + + var rc = close(fd) + expectEqual(0, rc) + + // Re-open the file... + fd = open(fn, 0) + expectGT(Int(fd), 0) + + // Lock for reading... + var flck = flock() + flck.l_type = Int16(F_RDLCK) + flck.l_len = off_t(data.utf8.count) + rc = fcntl(fd, F_SETLK, &flck) + expectEqual(0, rc) + + // Unlock for reading... + flck = flock() + flck.l_type = Int16(F_UNLCK) + rc = fcntl(fd, F_SETLK, &flck) + expectEqual(0, rc) + + // Clean up... + rc = close(fd) + expectEqual(0, rc) + + rc = unlink(fn) + expectEqual(0, rc) +} runAllTests()