Skip to content

Commit

Permalink
[libc] Add exit and atexit
Browse files Browse the repository at this point in the history
Often atexit is implemented using __cxa_atexit. I have not implemented __cxa_atexit here because it potentially requires more discussion. It is unique for llvm-libc (I think) that it is an exported symbol that wouldn’t be defined in any spec file because it doesn’t have a header. Implementing it will be trivial given what is here already, but I figured it would be more contentious so it can be implemented later.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D119512
  • Loading branch information
abrachet committed Feb 17, 2022
1 parent f374c8d commit d669838
Show file tree
Hide file tree
Showing 15 changed files with 307 additions and 30 deletions.
3 changes: 2 additions & 1 deletion libc/config/linux/api.td
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ def StdlibAPI : PublicAPI<"stdlib.h"> {
"lldiv_t",
"size_t",
"__bsearchcompare_t",
"__qsortcompare_t"
"__qsortcompare_t",
"__atexithandler_t",
];
}

Expand Down
2 changes: 2 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ if(LLVM_LIBC_FULL_BUILD)
# stdlib.h entrypoints
libc.src.stdlib._Exit
# libc.src.stdlib.abort
libc.src.stdlib.atexit
libc.src.stdlib.exit

# signal.h entrypoints
# TODO: Enable signal.h entrypoints after fixing signal.h
Expand Down
1 change: 1 addition & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ add_gen_header(
.llvm-libc-types.ldiv_t
.llvm-libc-types.lldiv_t
.llvm-libc-types.size_t
.llvm-libc-types.__atexithandler_t
)

add_gen_header(
Expand Down
1 change: 1 addition & 0 deletions libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ add_header(struct_tm HDR struct_tm.h)
add_header(thrd_start_t HDR thrd_start_t.h)
add_header(thrd_t HDR thrd_t.h)
add_header(time_t HDR time_t.h)
add_header(__atexithandler_t HDR __atexithandler_t.h)
14 changes: 14 additions & 0 deletions libc/include/llvm-libc-types/__atexithandler_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===-- Definition of type __atexithandler_t ------------------------------===//
//
// 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_TYPES_ATEXITHANDLER_T_H__
#define __LLVM_LIBC_TYPES_ATEXITHANDLER_T_H__

typedef void (*__atexithandler_t)(void);

#endif // __LLVM_LIBC_TYPES_ATEXITHANDLER_T_H__
2 changes: 2 additions & 0 deletions libc/spec/spec.td
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def TimeTType : NamedType<"time_t">;
def BSearchCompareT : NamedType<"__bsearchcompare_t">;
def QSortCompareT : NamedType<"__qsortcompare_t">;

def AtexitHandlerT : NamedType<"__atexithandler_t">;

//added because __assert_fail needs it.
def UnsignedType : NamedType<"unsigned">;

Expand Down
3 changes: 3 additions & 0 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ def StdC : StandardSpec<"stdc"> {
SizeTType,
BSearchCompareT,
QSortCompareT,
AtexitHandlerT,
], // Types
[], // Enumerations
[
Expand Down Expand Up @@ -538,6 +539,8 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"free", RetValSpec<VoidType>, [ArgSpec<VoidPtr>]>,

FunctionSpec<"_Exit", RetValSpec<NoReturn>, [ArgSpec<IntType>]>,
FunctionSpec<"exit", RetValSpec<NoReturn>, [ArgSpec<IntType>]>,
FunctionSpec<"atexit", RetValSpec<IntType>, [ArgSpec<AtexitHandlerT>]>,
]
>;

Expand Down
24 changes: 24 additions & 0 deletions libc/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,30 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}._Exit
)

add_entrypoint_object(
atexit
SRCS
atexit.cpp
HDRS
atexit.h
DEPENDS
libc.src.__support.CPP.vector
libc.src.threads.mtx_init
libc.src.threads.mtx_lock
libc.src.threads.mtx_unlock
)

add_entrypoint_object(
exit
SRCS
exit.cpp
HDRS
exit.h
DEPENDS
._Exit
.atexit
)

# add_entrypoint_object(
# abort
# ALIAS
Expand Down
54 changes: 54 additions & 0 deletions libc/src/stdlib/atexit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//===-- Implementation of atexit ------------------------------------------===//
//
// 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/stdlib/atexit.h"
#include "src/__support/CPP/vector.h"
#include "src/__support/common.h"
#include "src/threads/mtx_init.h"
#include "src/threads/mtx_lock.h"
#include "src/threads/mtx_unlock.h"

namespace __llvm_libc {

namespace {

mtx_t lock;
// TODO need an easier way to use mtx_t internally, or use pthread_mutex_t
// with PTHREAD_MUTEX_INITIALIZER when it lands.
struct Init {
Init() { __llvm_libc::mtx_init(&lock, mtx_plain); }
} init;

// TOOD should we make cpp::vector like llvm::SmallVector<T, N> where it will
// allocate at least N before needing dynamic allocation?
static cpp::vector<void (*)(void)> handlers;

} // namespace

namespace internal {

void call_exit_handlers() {
__llvm_libc::mtx_lock(&lock);
// TODO: implement rbegin() + rend() for cpp::vector
for (int i = handlers.size() - 1; i >= 0; i--) {
__llvm_libc::mtx_unlock(&lock);
handlers[i]();
__llvm_libc::mtx_lock(&lock);
}
}

} // namespace internal

LLVM_LIBC_FUNCTION(int, atexit, (void (*function)())) {
__llvm_libc::mtx_lock(&lock);
handlers.push_back(function);
__llvm_libc::mtx_unlock(&lock);
return 0;
}

} // namespace __llvm_libc
18 changes: 18 additions & 0 deletions libc/src/stdlib/atexit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for atexit ------------------------*- 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_STDLIB_ATEXIT_H
#define LLVM_LIBC_SRC_STDLIB_ATEXIT_H

namespace __llvm_libc {

int atexit(void (*function)());

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_STDLIB_ATEXIT_H
24 changes: 24 additions & 0 deletions libc/src/stdlib/exit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===-- Implementation of exit --------------------------------------------===//
//
// 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/stdlib/exit.h"
#include "src/__support/common.h"
#include "src/stdlib/_Exit.h"

namespace __llvm_libc {

namespace internal {
void call_exit_handlers();
}

LLVM_LIBC_FUNCTION(void, exit, (int status)) {
internal::call_exit_handlers();
_Exit(status);
}

} // namespace __llvm_libc
20 changes: 20 additions & 0 deletions libc/src/stdlib/exit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for exit --------------------------*- 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
//
//===----------------------------------------------------------------------===//

#include <stdlib.h>

#ifndef LLVM_LIBC_SRC_STDLIB_EXIT_H
#define LLVM_LIBC_SRC_STDLIB_EXIT_H

namespace __llvm_libc {

void exit(int status);

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_STDLIB_EXIT_H
73 changes: 44 additions & 29 deletions libc/test/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,35 +110,6 @@ add_libc_unittest(
libc.src.stdlib.strtoull
)

if(NOT LLVM_LIBC_FULL_BUILD)
return()
endif()

add_libc_unittest(
_Exit_test
SUITE
libc_stdlib_unittests
SRCS
_Exit_test.cpp
DEPENDS
libc.include.stdlib
libc.src.stdlib._Exit
)

# add_libc_unittest(
# abort_test
# SUITE
# libc_stdlib_unittests
# SRCS
# abort_test.cpp
# DEPENDS
# libc.include.stdlib
# libc.include.signal
# libc.src.stdlib.abort
# libc.src.stdlib._Exit
# libc.src.signal.raise
# )

add_libc_unittest(
abs_test
SUITE
Expand Down Expand Up @@ -229,3 +200,47 @@ add_libc_unittest(
libc.include.stdlib
libc.src.stdlib.qsort
)

if(LLVM_LIBC_FULL_BUILD)

add_libc_unittest(
_Exit_test
SUITE
libc_stdlib_unittests
SRCS
_Exit_test.cpp
DEPENDS
libc.include.stdlib
libc.src.stdlib._Exit
libc.src.stdlib.exit
)

add_libc_unittest(
atexit_test
SUITE
libc_stdlib_unittests
SRCS
atexit_test.cpp
DEPENDS
libc.include.stdlib
libc.src.stdlib._Exit
libc.src.stdlib.exit
libc.src.stdlib.atexit
libc.src.__support.CPP.standalone_cpp
)

# add_libc_unittest(
# abort_test
# SUITE
# libc_stdlib_unittests
# SRCS
# abort_test.cpp
# DEPENDS
# libc.include.stdlib
# libc.include.signal
# libc.src.stdlib.abort
# libc.src.stdlib._Exit
# libc.src.signal.raise
# )

endif()
4 changes: 4 additions & 0 deletions libc/test/src/stdlib/_Exit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

#include "include/stdlib.h"
#include "src/stdlib/_Exit.h"
#include "src/stdlib/exit.h"
#include "utils/UnitTest/Test.h"

TEST(LlvmLibcStdlib, _Exit) {
EXPECT_EXITS([] { __llvm_libc::_Exit(1); }, 1);
EXPECT_EXITS([] { __llvm_libc::_Exit(65); }, 65);

EXPECT_EXITS([] { __llvm_libc::exit(1); }, 1);
EXPECT_EXITS([] { __llvm_libc::exit(65); }, 65);
}
Loading

0 comments on commit d669838

Please sign in to comment.