[PATCH 1/1] newlib01: Check exit processing for file objects
Matthew Joyce
matthew.joyce at embedded-brains.de
Wed Mar 23 11:36:03 UTC 2022
From: Matt Joyce <matthew.joyce at embedded-brains.de>
---
testsuites/libtests/newlib01/init.c | 131 ++++++++++++++++++++++++++--
1 file changed, 124 insertions(+), 7 deletions(-)
diff --git a/testsuites/libtests/newlib01/init.c b/testsuites/libtests/newlib01/init.c
index 5864047a80..58757a7676 100644
--- a/testsuites/libtests/newlib01/init.c
+++ b/testsuites/libtests/newlib01/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2014, 2022 embedded brains GmbH. All rights reserved.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -11,13 +11,16 @@
#endif
#include <stdio.h>
+#include <errno.h>
#include <sys/reent.h>
+#include <sys/stat.h>
#include <rtems.h>
#include <rtems/console.h>
#include <rtems/imfs.h>
#include <rtems/libcsupport.h>
+#include <rtems/sysinit.h>
#include "tmacros.h"
@@ -25,6 +28,15 @@ const char rtems_test_name[] = "NEWLIB 1";
static const char file_path[] = "/file";
+static void test_sysinit_handler1(void);
+
+/*
+ * Test Newlib exit procedures. Allows us to place an exit handler at position
+ * 0, which is called after rtems_stdio_exit by Newlib's __call_exitprocs().
+ */
+RTEMS_SYSINIT_ITEM( test_sysinit_handler1, RTEMS_SYSINIT_STD_FILE_DESCRIPTORS,
+ RTEMS_SYSINIT_ORDER_FIRST );
+
typedef enum {
INIT,
OPEN,
@@ -247,7 +259,45 @@ static const IMFS_node_control node_control = IMFS_GENERIC_INITIALIZER(
IMFS_node_destroy_default
);
-static void test(void)
+/*
+ * This exit handler will be called last among the functions registered with
+ * _atexit. Check that stdio file descriptors are closed. The cleanup handler
+ * has not yet run, so the stdio file objects themselves are still open.
+ */
+static void test_exit_handler1(void)
+{
+ struct stat buffer;
+ int status;
+
+ status = fstat(0, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ status = fstat(1, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ status = fstat(2, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ rtems_test_assert( stdin->_flags != 0 );
+ rtems_test_assert( stdout->_flags != 0 );
+ rtems_test_assert( stderr->_flags != 0 );
+}
+
+/*
+ * Register test_exit_handler1 at position 0 in the _atexit _fns array.
+ * Thus, test_exit_handler1 will be called last--after rtems_libio_exit().
+ */
+static void test_sysinit_handler1(void)
+{
+ int rv;
+ rv = atexit(test_exit_handler1);
+ rtems_test_assert(rv == 0);
+}
+
+static void test_thread_specific_close(void)
{
test_context *ctx = &test_instance;
rtems_status_code sc;
@@ -297,14 +347,79 @@ static void test(void)
rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
}
+/*
+ * At this point, neither the _atexit functions nor __cleanup have been
+ * called. Therefore, stdio file descriptors should be open and stdio file
+ * object flags should be non-zero.
+ */
+static void test_exit_handling(void)
+{
+ struct stat buffer;
+ int status;
+
+ status = fstat(0, &buffer);
+ rtems_test_assert(status == 0);
+ rtems_test_assert(errno == 0);
+
+ status = fstat(1, &buffer);
+ rtems_test_assert(status == 0);
+ rtems_test_assert(errno == 0);
+
+ status = fstat(2, &buffer);
+ rtems_test_assert(status == 0);
+ rtems_test_assert(errno == 0);
+
+ rtems_test_assert( stdin->_flags != 0 );
+ rtems_test_assert( stdout->_flags != 0 );
+ rtems_test_assert( stderr->_flags != 0 );
+
+ /* Run exit handlers and __cleanup */
+ exit(0);
+}
+
static void Init(rtems_task_argument arg)
{
TEST_BEGIN();
+ test_thread_specific_close();
+ test_exit_handling();
+}
- test();
-
- TEST_END();
- rtems_test_exit(0);
+static void fatal_extension(
+ rtems_fatal_source source,
+ bool always_set_to_false,
+ rtems_fatal_code error
+)
+{
+ if (
+ source == RTEMS_FATAL_SOURCE_EXIT
+ && !always_set_to_false
+ && error == 0
+ ) {
+
+ /*
+ * Final conditions check after exit handlers and __cleanup have run.
+ * File descriptors and file objects themselves are closed.
+ */
+ struct stat buffer;
+ int status;
+
+ status = fstat(0, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ status = fstat(1, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ status = fstat(2, &buffer);
+ rtems_test_assert(status == -1);
+ rtems_test_assert(errno == EBADF);
+
+ rtems_test_assert( stdin->_flags == 0 );
+ rtems_test_assert( stdout->_flags == 0 );
+ rtems_test_assert( stderr->_flags == 0 );
+ TEST_END();
+ }
}
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
@@ -314,7 +429,9 @@ static void Init(rtems_task_argument arg)
#define CONFIGURE_MAXIMUM_TASKS 2
-#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+#define CONFIGURE_INITIAL_EXTENSIONS \
+ { .fatal = fatal_extension }, \
+ RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
--
2.31.1
More information about the devel
mailing list