Skip to content

Commit

Permalink
[libc] Add a minimal implementation of the POSIX fork function.
Browse files Browse the repository at this point in the history
A very simple and minimal implementation of fork is added. Future
changes will add more functionality to satisfy POSIX and Linux
requirements.

An implementation of wait and a few support macros in sys/wait.h
have also been added to help with testing the fork function.

Reviewed By: lntue, michaelrj

Differential Revision: https://reviews.llvm.org/D135131
  • Loading branch information
Siva Chandra Reddy committed Oct 4, 2022
1 parent b39b805 commit e3638e8
Show file tree
Hide file tree
Showing 21 changed files with 345 additions and 0 deletions.
4 changes: 4 additions & 0 deletions libc/config/linux/api.td
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ def SysStatAPI : PublicAPI<"sys/stat.h"> {
"struct timespec", "blksize_t", "blkcnt_t", "struct stat"];
}

def SysWaitAPI : PublicAPI<"sys/wait.h"> {
let Types = ["pid_t"];
}

def SysSendfileAPI : PublicAPI<"sys/sendfile.h"> {
let Types = ["off_t", "size_t", "ssize_t"];
}
Expand Down
6 changes: 6 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/utsname.h entrypoints
libc.src.sys.utsname.uname

# sys/wait.h entrypoints
libc.src.sys.wait.wait

# unistd.h entrypoints
libc.src.unistd.access
libc.src.unistd.chdir
Expand Down Expand Up @@ -401,6 +404,9 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.clock_gettime

# unistd.h entrypoints
libc.src.unistd.fork
)
endif()

Expand Down
11 changes: 11 additions & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ add_gen_header(
.llvm_libc_common_h
.llvm-libc-macros.file_seek_macros
.llvm-libc-macros.unistd_macros
.llvm-libc-types.off_t
.llvm-libc-types.pid_t
.llvm-libc-types.size_t
.llvm-libc-types.ssize_t
Expand Down Expand Up @@ -273,6 +274,16 @@ add_gen_header(
.llvm-libc-types.struct_utsname
)

add_gen_header(
sys_wait
DEF_FILE sys/wait.h.def
GEN_HDR sys/wait.h
DEPENDS
.llvm_libc_common_h
.llvm-libc-macros.sys_wait_macros
.llvm-libc-types.pid_t
)

if(NOT LLVM_LIBC_FULL_BUILD)
# We don't install headers in non-fullbuild mode.
return()
Expand Down
8 changes: 8 additions & 0 deletions libc/include/llvm-libc-macros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ add_header(
.linux.sys_resource_macros
)

add_header(
sys_wait_macros
HDR
sys-wait-macros.h
DEPENDS
.linux.sys_wait_macros
)

add_header(
time_macros
HDR
Expand Down
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-macros/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ add_header(
sys-stat-macros.h
)

add_header(
sys_wait_macros
HDR
sys-wait-macros.h
)

add_header(
time_macros
HDR
Expand Down
17 changes: 17 additions & 0 deletions libc/include/llvm-libc-macros/linux/sys-wait-macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//===-- Definition of macros from sys/wait.h ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef __LLVM_LIBC_MACROS_LINUX_SYS_WAIT_MACROS_H
#define __LLVM_LIBC_MACROS_LINUX_SYS_WAIT_MACROS_H

// Wait status info macros
#define WTERMSIG(status) (((status)&0x7F))
#define WIFEXITED(status) (WTERMSIG(status) == 0)
#define WEXITSTATUS(status) (((status)&0xFF00) >> 8)

#endif // __LLVM_LIBC_MACROS_LINUX_SYS_WAIT_MACROS_H
16 changes: 16 additions & 0 deletions libc/include/llvm-libc-macros/sys-wait-macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//===-- Macros defined in sys/wait.h header file --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef __LLVM_LIBC_MACROS_SYS_WAIT_MACROS_H
#define __LLVM_LIBC_MACROS_SYS_WAIT_MACROS_H

#ifdef __linux__
#include "linux/sys-wait-macros.h"
#endif

#endif // __LLVM_LIBC_MACROS_SYS_WAIT_MACROS_H
18 changes: 18 additions & 0 deletions libc/include/sys/wait.h.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- POSIX header wait.h -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SYS_WAIT_H
#define LLVM_LIBC_SYS_WAIT_H

#include <__llvm-libc-common.h>

#include <llvm-libc-macros/sys-wait-macros.h>

%%public_api()

#endif // LLVM_LIBC_SYS_WAIT_H
20 changes: 20 additions & 0 deletions libc/spec/posix.td
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<IntType>]
>,
FunctionSpec<
"fork",
RetValSpec<PidT>,
[ArgSpec<VoidType>]
>,
FunctionSpec<
"fsync",
RetValSpec<IntType>,
Expand Down Expand Up @@ -963,6 +968,20 @@ def POSIX : StandardSpec<"POSIX"> {
]
>;

HeaderSpec SysWait = HeaderSpec<
"sys/wait.h",
[], // Macros
[PidT],
[], // Enumerations
[
FunctionSpec<
"wait",
RetValSpec<PidT>,
[ArgSpec<IntPtr>]
>
]
>;

let Headers = [
CType,
Dirent,
Expand All @@ -976,6 +995,7 @@ def POSIX : StandardSpec<"POSIX"> {
SysResource,
SysStat,
SysUtsName,
SysWait,
Time,
UniStd,
String
Expand Down
1 change: 1 addition & 0 deletions libc/src/sys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ add_subdirectory(resource)
add_subdirectory(sendfile)
add_subdirectory(stat)
add_subdirectory(utsname)
add_subdirectory(wait)
10 changes: 10 additions & 0 deletions libc/src/sys/wait/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()

add_entrypoint_object(
wait
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.wait
)
13 changes: 13 additions & 0 deletions libc/src/sys/wait/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_entrypoint_object(
wait
SRCS
wait.cpp
HDRS
../wait.h
DEPENDS
libc.include.errno
libc.include.sys_wait
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
34 changes: 34 additions & 0 deletions libc/src/sys/wait/linux/wait.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- Linux implementation of wait --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/sys/wait/wait.h"

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
#include <sys/wait.h>

namespace __llvm_libc {

// The implementation of wait here is very minimal. We will add more
// functionality and standard compliance in future.

LLVM_LIBC_FUNCTION(pid_t, wait, (int *wait_status)) {
pid_t pid = __llvm_libc::syscall_impl(SYS_wait4, -1, wait_status, 0, 0);
if (pid < 0) {
// Error case, a child process was not created.
errno = -pid;
return -1;
}

return pid;
}

} // namespace __llvm_libc
20 changes: 20 additions & 0 deletions libc/src/sys/wait/wait.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for wait --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SYS_WAIT_WAIT_H
#define LLVM_LIBC_SRC_SYS_WAIT_WAIT_H

#include <sys/wait.h>

namespace __llvm_libc {

pid_t wait(int *waitstatus);

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SYS_WAIT_WAIT_H
7 changes: 7 additions & 0 deletions libc/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.fchdir
)

add_entrypoint_object(
fork
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.fork
)

add_entrypoint_object(
fsync
ALIAS
Expand Down
20 changes: 20 additions & 0 deletions libc/src/unistd/fork.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for fork --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_UNISTD_FORK_H
#define LLVM_LIBC_SRC_UNISTD_FORK_H

#include <unistd.h>

namespace __llvm_libc {

pid_t fork();

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_UNISTD_FORK_H
15 changes: 15 additions & 0 deletions libc/src/unistd/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ add_entrypoint_object(
libc.src.errno.errno
)

add_entrypoint_object(
fork
SRCS
fork.cpp
HDRS
../fork.h
DEPENDS
libc.include.errno
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.__support.threads.thread
libc.src.errno.errno
)

add_entrypoint_object(
fsync
SRCS
Expand Down
49 changes: 49 additions & 0 deletions libc/src/unistd/linux/fork.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===-- Linux implementation of fork --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/unistd/fork.h"

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/__support/threads/thread.h" // For thread self object

#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.

namespace __llvm_libc {

// The implementation of fork here is very minimal. We will add more
// functionality and standard compliance in future.

LLVM_LIBC_FUNCTION(pid_t, fork, (void)) {
#ifdef SYS_fork
pid_t ret = __llvm_libc::syscall_impl(SYS_fork);
#elif defined(SYS_clone)
pid_t ret = __llvm_libc::syscall_impl(SYS_clone, SIGCHLD, 0);
#else
#error "SYS_fork or SYS_clone not available."
#endif
if (ret == 0) {
// Return value is 0 in the child process.
// The child is created with a single thread whose self object will be a
// copy of parent process' thread which called fork. So, we have to fix up
// the child process' self object with the new process' tid.
self.attrib->tid = __llvm_libc::syscall_impl(SYS_gettid);
return 0;
}

if (ret < 0) {
// Error case, a child process was not created.
errno = -ret;
return -1;
}

return ret;
}

} // namespace __llvm_libc
1 change: 1 addition & 0 deletions libc/test/integration/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ add_subdirectory(pthread)
add_subdirectory(stdio)
add_subdirectory(stdlib)
add_subdirectory(threads)
add_subdirectory(unistd)
20 changes: 20 additions & 0 deletions libc/test/integration/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
add_custom_target(unistd-integration-tests)
add_dependencies(libc-integration-tests unistd-integration-tests)

add_integration_test(
fork_test
SUITE
unistd-integration-tests
SRCS
fork_test.cpp
LOADER
libc.loader.linux.crt1
DEPENDS
libc.include.errno
libc.include.signal
libc.include.sys_wait
libc.include.unistd
libc.src.signal.raise
libc.src.sys.wait.wait
libc.src.unistd.fork
)
Loading

0 comments on commit e3638e8

Please sign in to comment.