diff --git a/GNUmakefile.os4 b/GNUmakefile.os4 index a17616ad..c42ddae3 100644 --- a/GNUmakefile.os4 +++ b/GNUmakefile.os4 @@ -58,9 +58,10 @@ WARNINGS := \ -Wall -W -Wextra -Wpointer-arith -Wsign-compare -Wmissing-prototypes \ -Wundef -Wmissing-declarations -Wunused -Wwrite-strings -Wno-array-bounds -Wno-missing-braces -Wno-unused-value -Wno-comment \ -Wno-deprecated-declarations -Wno-sign-compare -Wno-cast-function-type -Wno-unused-variable -Wno-parentheses -Wno-missing-prototypes \ - -Wstrict-aliasing -Wno-shadow -Wno-implicit-fallthrough -Wno-prio-ctor-dtor # -Werror -Wbad-function-cast -Wconversion -Wformat + -Wstrict-aliasing -Wno-shadow -Wno-implicit-fallthrough -Wno-discarded-qualifiers -Wno-unused-function -Wno-unused-parameter -Wno-strict-aliasing \ + -Wno-type-limits -Werror # -Wbad-function-cast -Wconversion -Wformat -PIC := -fPIC +PIC := -fPIC -DPIC INCLUDES := -I$(LIB_DIR)/include \ -Ilibrary \ -I$(LIB_DIR)/external/include \ @@ -96,14 +97,14 @@ OPTIONS := $(LARGEDATA) -DHAVE_SYSV -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE OPTIMIZE := -O3 -mmultiple -mupdate -mstrict-align ifndef DEBUG - OPTIMIZE := $(OPTIMIZE) -gstabs -DNDEBUG + OPTIMIZE += -gstabs -DNDEBUG else - OPTIMIZE := $(OPTIMIZE) -gstabs -DDEBUG + OPTIMIZE += -gstabs -DDEBUG endif -CFLAGS := $(COMPILER_VERSION) $(WARNINGS) $(OPTIMIZE) $(OPTIONS) $(INCLUDES) -D__USE_INLINE__ -CFLAGS_N := $(COMPILER_VERSION) $(WARNINGS) $(OPTIMIZE) $(OPTIONS) $(INCLUDES) -AFLAGS := $(COMPILER_VERSION) -Wa,-mregnames +CFLAGS := $(WARNINGS) $(OPTIMIZE) $(OPTIONS) $(INCLUDES) -D__USE_INLINE__ +CFLAGS_N := $(WARNINGS) $(OPTIMIZE) $(OPTIONS) $(INCLUDES) +AFLAGS := -Wa,-mregnames VERBOSE := @ @@ -182,22 +183,22 @@ $(OUTPUT_LIB)/crt0.o : $(LIB_DIR)/crt0.S $(VERBOSE)$(ASSEMBLE) -$(COPY) $(OUTPUT_LIB)/crt0.o $(INSTALL_PREFIX)/lib/ -$(OUTPUT_LIB)/crtbegin.o : CFLAGS += -fno-aggressive-loop-optimizations +$(OUTPUT_LIB)/crtbegin.o : CFLAGS += -O0 -fno-aggressive-loop-optimizations $(OUTPUT_LIB)/crtbegin.o : $(LIB_DIR)/crtbegin.c $(VERBOSE)$(COMPILE) -$(COPY) $(OUTPUT_LIB)/crtbegin.o $(INSTALL_PREFIX)/lib/ -$(OUTPUT_LIB)/crtend.o : CFLAGS += -fno-aggressive-loop-optimizations +$(OUTPUT_LIB)/crtend.o : CFLAGS += -O0 -fno-aggressive-loop-optimizations $(OUTPUT_LIB)/crtend.o : $(LIB_DIR)/crtend.c $(VERBOSE)$(COMPILE) -$(COPY) $(OUTPUT_LIB)/crtend.o $(INSTALL_PREFIX)/lib/ -$(OUTPUT_LIB)/shcrtbegin.o : CFLAGS += -O0 -fno-aggressive-loop-optimizations +$(OUTPUT_LIB)/shcrtbegin.o : CFLAGS += $(PIC) -O0 -fno-aggressive-loop-optimizations $(OUTPUT_LIB)/shcrtbegin.o : $(LIB_DIR)/shcrtbegin.c $(VERBOSE)$(COMPILE) -$(COPY) $(OUTPUT_LIB)/shcrtbegin.o $(INSTALL_PREFIX)/lib/ -$(OUTPUT_LIB)/shcrtend.o : CFLAGS += -O0 -fno-aggressive-loop-optimizations +$(OUTPUT_LIB)/shcrtend.o : CFLAGS += $(PIC) -O0 -fno-aggressive-loop-optimizations $(OUTPUT_LIB)/shcrtend.o : $(LIB_DIR)/shcrtend.c $(VERBOSE)$(COMPILE) -$(COPY) $(OUTPUT_LIB)/shcrtend.o $(INSTALL_PREFIX)/lib/ @@ -225,13 +226,13 @@ endef define COMPILE_SHARED $(VERBOSE)@$(MAKEDIR) $(@D) $(VERBOSE)echo -e "\rCompiling Shared \033[0;33m[$(@D)]\033[0m \r\t\t\t\t\t\t\t\t\t\t\t \033[0;31m$(@F)\033[0m" -$(VERBOSE)$(CC) $(CFLAGS) $(PIC) -o $@ -c $< $(LOG_COMMAND) +$(VERBOSE)$(CC) $(CFLAGS) $(PIC) -DSHARED -o $@ -c $< $(LOG_COMMAND) endef define COMPILE_SHARED_ASM $(VERBOSE)@$(MAKEDIR) $(@D) $(VERBOSE)echo -e "\rCompiling Shared Asm \033[0;33m[$(@D)]\033[0m \r\t\t\t\t\t\t\t\t\t\t\t \033[0;31m$(@F)\033[0m" -$(VERBOSE)$(CC) $(PIC) -o $@ -c $< $(LOG_COMMAND) +$(VERBOSE)$(CC) $(PIC) -DSHARED -o $@ -c $< $(LOG_COMMAND) endef define ASSEMBLE @@ -258,7 +259,7 @@ define MAKESHARED $(VERBOSE)@$(MAKEDIR) $(@D) $(VERBOSE)@$(DELETE) $@ $(VERBOSE)echo -e "\rMaking Shared \033[0;31m$@\033[0m" -$(VERBOSE)$(CC) -mcrt=clib2 -shared -use-dynld -o $@ $^ $(LOG_COMMAND) -Lbuild/lib -lc +$(VERBOSE)$(CC) -nostdlib -mcrt=clib2 -shared -o $@ $(OUTPUT_LIB)/shcrtbegin.o $^ $(OUTPUT_LIB)/shcrtend.o $(LOG_COMMAND) -Wl,-soname,$(@F) endef compile-tests: @@ -277,6 +278,7 @@ release: -$(MAKEDIR) clib2/lib -$(COPY) LICENSE* clib2/ -$(COPY) misc clib2/ + -$(COPY) libs/libauto.a clib2/lib/ -$(COPY) $(OUTPUT_LIB)/* clib2/lib/ -$(COPY) $(LIB_ROOT)/library/include/* clib2/include/ jlha -aqo7i clib2.lha clib2 diff --git a/POSIX.md b/POSIX.md index 8d34c9e5..8572d9c7 100644 --- a/POSIX.md +++ b/POSIX.md @@ -1,84 +1,84 @@ # C POSIX library header files -| Header file | Description | Status | -|--------------------------|---------------------------------------------------------------------------------------|---------------------------------| -| | Asynchronous input and output | Not present | -| | Functions for manipulating numeric IP addresses (part of Berkley sockets) | Complete | -| | Verify assumptions | Complete | -| | Complex Arithmetic | Complete | -| | Magic numbers for the cpio archive format | Not present | -| | Character types | Complete | | -| | Allows the opening and listing of directories | Complete | -| | Dynamic linking | Complete | -| | Retrieving Error Number | Complete | -| | File opening, locking and other operations | Complete | -| | Floating-Point Environment (FPE) | Complete | -| | Floating-point types | Complete | -| | Filename matching | Complete | -| | File tree traversal | Complete | -| | Pathname "globbing" (pattern-matching) | Complete | -| | User group information and control | Present with missing functions | -| | Codeset conversion facility | Complete | -| | Fixed sized integer types | Complete | -| | Alternative spellings | Complete | -| | Language information constants – builds on C localization functions | Complete | -| | Pathname manipulation | Complete | -| | Implementation-defined constants | Complete | -| | Mathematical declarations | Complete | -| | String formatting of monetary units | Not present | -| | Message queue | Not present | -| | NDBM database operations | Not present | -| | Listing of local network interfaces | Complete | -| | Translating protocol and host names into numeric addresses (part of Berkeley sockets | Complete | -| | Defines Internet protocol and address family (part of Berkley sockets) | Complete | -| | Issue | Complete | -| | Localization message catalog functions | Complete | -| | Asynchronous file descriptor multiplexing | Present with missing functions | -| | Defines an API for creating and manipulating POSIX threads | Complete | -| | Passwd (user information) access and control | Present with missing functions | -| | Regular expression matching | Complete | -| | Execution scheduling | Present with missing functions | -| | Search tables | Complete | -| | POSIX semaphores | Complete | -| | Stack environment declarations | Complete | -| | Signals | Complete | -| | Process spawning | Not present | -| | Handle Variable Argument List | Complete | -| | Boolean type and values | Complete | -| | Standard type definitions | Complete | -| | Integer types | Complete | -| | Standard buffered input/output | Complete | -| | Standard library definitions | Complete | -| | Several String Operations | Complete | -| | Case-insensitive string comparisons | Complete | -| | Stream manipulation, including ioctl | Not present | -| | Inter-process Communication (IPC) | Complete | -| | Memory management, including POSIX shared memory and memory mapped files | Present with missing functions | -| | POSIX messages queues | Complete | -| | Resource usage, priorities, and limiting | Present with missing functions | -| | Synchronous I/O multiplexing | Complete | -| | XSI (SysV style)semaphores | Complete | -| | XSI (SysV style) shared memory | Complete | -| | Main Berkeley sockets header | Complete | -| | File information | Complete | -| | File System information | Complete | -| | Time and date functions and structures | Complete | -| | File access and modification times | Complete | -| | Various data types used elsewhere | Complete | -| | Vectored I/O operations | Complete | -| | Unix domain sockets | Present with missing functions | -| | Operating system information, including uname | Complete | -| | Status of terminated child processes | Present with missing functions | -| | System error logging | Not present | -| | Magic numbers for the tar archive format | Not present | -| | Allows terminal I/O interfaces | Complete | -| | Type-Generic Macros | Complete | -| | Type-Generic Macros | Complete | -| | Tracing of runtime behavior (DEPRECATED) | Not present | -| | Resource limiting (DEPRECATED in favor of ) | Present with missing functions | -| | Various essential POSIX functions and constants | Complete | -| | access and modification times | Complete | -| | User accounting database functions | Not present | -| | Wide-Character Handling | Complete | -| | Wide-Character Classification and Mapping Utilities | Complete | -| | Word-expansion like the shell would perform | Not present | +| Header file | Description | Status | +|--------------------------|---------------------------------------------------------------------------------------|-----------------------------------| +| | Asynchronous input and output | Implemented with some limitations | +| | Functions for manipulating numeric IP addresses (part of Berkley sockets) | Complete | +| | Verify assumptions | Complete | +| | Complex Arithmetic | Complete | +| | Magic numbers for the cpio archive format | Not present | +| | Character types | Complete | | +| | Allows the opening and listing of directories | Complete | +| | Dynamic linking | Complete | +| | Retrieving Error Number | Complete | +| | File opening, locking and other operations | Complete | +| | Floating-Point Environment (FPE) | Complete | +| | Floating-point types | Complete | +| | Filename matching | Complete | +| | File tree traversal | Complete | +| | Pathname "globbing" (pattern-matching) | Complete | +| | User group information and control | Present with missing functions | +| | Codeset conversion facility | Complete | +| | Fixed sized integer types | Complete | +| | Alternative spellings | Complete | +| | Language information constants – builds on C localization functions | Complete | +| | Pathname manipulation | Complete | +| | Implementation-defined constants | Complete | +| | Mathematical declarations | Complete | +| | String formatting of monetary units | Not present | +| | Message queue | Not present | +| | NDBM database operations | Not present | +| | Listing of local network interfaces | Complete | +| | Translating protocol and host names into numeric addresses (part of Berkeley sockets | Complete | +| | Defines Internet protocol and address family (part of Berkley sockets) | Complete | +| | Issue | Complete | +| | Localization message catalog functions | Complete | +| | Asynchronous file descriptor multiplexing | Present with missing functions | +| | Defines an API for creating and manipulating POSIX threads | Complete | +| | Passwd (user information) access and control | Present with missing functions | +| | Regular expression matching | Complete | +| | Execution scheduling | Present with missing functions | +| | Search tables | Complete | +| | POSIX semaphores | Complete | +| | Stack environment declarations | Complete | +| | Signals | Complete | +| | Process spawning | Not present | +| | Handle Variable Argument List | Complete | +| | Boolean type and values | Complete | +| | Standard type definitions | Complete | +| | Integer types | Complete | +| | Standard buffered input/output | Complete | +| | Standard library definitions | Complete | +| | Several String Operations | Complete | +| | Case-insensitive string comparisons | Complete | +| | Stream manipulation, including ioctl | Not present | +| | Inter-process Communication (IPC) | Complete | +| | Memory management, including POSIX shared memory and memory mapped files | Present with missing functions | +| | POSIX messages queues | Complete | +| | Resource usage, priorities, and limiting | Present with missing functions | +| | Synchronous I/O multiplexing | Complete | +| | XSI (SysV style)semaphores | Complete | +| | XSI (SysV style) shared memory | Complete | +| | Main Berkeley sockets header | Complete | +| | File information | Complete | +| | File System information | Complete | +| | Time and date functions and structures | Complete | +| | File access and modification times | Complete | +| | Various data types used elsewhere | Complete | +| | Vectored I/O operations | Complete | +| | Unix domain sockets | Present with missing functions | +| | Operating system information, including uname | Complete | +| | Status of terminated child processes | Present with missing functions | +| | System error logging | Not present | +| | Magic numbers for the tar archive format | Not present | +| | Allows terminal I/O interfaces | Complete | +| | Type-Generic Macros | Complete | +| | Type-Generic Macros | Complete | +| | Tracing of runtime behavior (DEPRECATED) | Not present | +| | Resource limiting (DEPRECATED in favor of ) | Present with missing functions | +| | Various essential POSIX functions and constants | Complete | +| | access and modification times | Complete | +| | User accounting database functions | Not present | +| | Wide-Character Handling | Complete | +| | Wide-Character Classification and Mapping Utilities | Complete | +| | Word-expansion like the shell would perform | Not present | diff --git a/README.md b/README.md index 8cd65faa..85de9c26 100755 --- a/README.md +++ b/README.md @@ -56,7 +56,8 @@ Keep in mind that clib2 is not compiled with altivec optimizations for all files Shared objects **are working** also with clib2 (there is an example under test_programs/dlopen folder). using dlopen/dlsym will not crash anymore however there is a bug in `libstdc++.so` that is causing a crash on program start. -So if you want to use libstdc++ it is better to remove it and link against the static version. +So if you want to use libstdc++ it is better to remove it and link against the static version. +However they needs the beta elf.library not yet released to public ### Large file support @@ -102,6 +103,13 @@ A lot of other functions has been added trying to make OS4 ports easier. Clib2 now contain also libauto with almost all OS4 components. We'll try to keep them updated. +### libpthread + +Clib2 now contain a native pthread implementation. However pthread functions are in libc and libpthread is just a stub. +That's because pthread functions are used (and will be used more in the future) internally and they are needed by libc. +libpthread.a is however present as stub to avoid old program stop compiling claiming this library + + ### libresolv Added resolv library to use dns functions. A lot of socket functions that was using bsdsocket.library now use this library. @@ -154,7 +162,8 @@ Check `fcntl.h` for details ### Known problems -Don't call `exit()` function in an `alarm()` handler otherwise your program will be stuck at exit. +Don't call `exit()` function in an `alarm()` handler otherwise your program will be stuck at exit. +All *crt* files needs to be compiled with -fno-aggressive-loop-optimizations! Otherwise you will have problems during constructors/destructors executions ### TODO diff --git a/libc.gmk b/libc.gmk index 5569d582..fe75b46e 100755 --- a/libc.gmk +++ b/libc.gmk @@ -18,6 +18,20 @@ C_BASE := \ libc_init_global.o \ errno_data.o +C_AIO := \ + aio/aio_cancel.o \ + aio/aio_error.o \ + aio/aio_fsync.o \ + aio/aio_misc.o \ + aio/aio_notify.o \ + aio/aio_read.o \ + aio/aio_read64.o \ + aio/aio_return.o \ + aio/aio_sigqueue.o \ + aio/aio_suspend.o \ + aio/aio_write.o \ + aio/aio_write64.o \ + C_ARGZ := \ argz/add.o \ argz/add_sep.o \ @@ -128,6 +142,9 @@ C_LOCALE := \ locale/open_locale.o \ locale/setlocale.o +C_MISC := \ + misc/clist.o \ + C_MOUNT := \ mount/convertinfo.o \ mount/fstatfs.o \ @@ -188,6 +205,88 @@ C_POSIX := \ posix/writev.o \ posix/uname.o +C_PTHREAD := \ + pthread/common.o \ + pthread/pthread.o \ + pthread/pthread_attr_destroy.o \ + pthread/pthread_attr_getdetachstate.o \ + pthread/pthread_attr_getguardsize.o \ + pthread/pthread_attr_getschedparam.o \ + pthread/pthread_attr_getstack.o \ + pthread/pthread_attr_getstacksize.o \ + pthread/pthread_attr_init.o \ + pthread/pthread_attr_setdetachstate.o \ + pthread/pthread_attr_setguardsize.o \ + pthread/pthread_attr_setschedparam.o \ + pthread/pthread_attr_setstack.o \ + pthread/pthread_attr_setstacksize.o \ + pthread/pthread_barrier_destroy.o \ + pthread/pthread_barrier_init.o \ + pthread/pthread_barrier_wait.o \ + pthread/pthread_cancel.o \ + pthread/pthread_cleanup_pop.o \ + pthread/pthread_cleanup_push.o \ + pthread/pthread_cond_broadcast.o \ + pthread/pthread_cond_destroy.o \ + pthread/pthread_cond_init.o \ + pthread/pthread_cond_signal.o \ + pthread/pthread_cond_timedwait.o \ + pthread/pthread_cond_timedwait_relative_np.o \ + pthread/pthread_cond_wait.o \ + pthread/pthread_condattr_destroy.o \ + pthread/pthread_condattr_init.o \ + pthread/pthread_create.o \ + pthread/pthread_detach.o \ + pthread/pthread_equal.o \ + pthread/pthread_exit.o \ + pthread/pthread_getattr_np.o \ + pthread/pthread_getname_np.o \ + pthread/pthread_getschedparam.o \ + pthread/pthread_getspecific.o \ + pthread/pthread_join.o \ + pthread/pthread_key_create.o \ + pthread/pthread_key_delete.o \ + pthread/pthread_kill.o \ + pthread/pthread_mutex_destroy.o \ + pthread/pthread_mutex_init.o \ + pthread/pthread_mutex_lock.o \ + pthread/pthread_mutex_timedlock.o \ + pthread/pthread_mutex_trylock.o \ + pthread/pthread_mutex_unlock.o \ + pthread/pthread_mutexattr_destroy.o \ + pthread/pthread_mutexattr_gettype.o \ + pthread/pthread_mutexattr_init.o \ + pthread/pthread_mutexattr_settype.o \ + pthread/pthread_once.o \ + pthread/pthread_rwlock_destroy.o \ + pthread/pthread_rwlock_init.o \ + pthread/pthread_rwlock_rdlock.o \ + pthread/pthread_rwlock_timedrdlock.o \ + pthread/pthread_rwlock_timedwrlock.o \ + pthread/pthread_rwlock_tryrdlock.o \ + pthread/pthread_rwlock_trywrlock.o \ + pthread/pthread_rwlock_unlock.o \ + pthread/pthread_rwlock_wrlock.o \ + pthread/pthread_rwlockattr_destroy.o \ + pthread/pthread_rwlockattr_init.o \ + pthread/pthread_self.o \ + pthread/pthread_setcancelstate.o \ + pthread/pthread_setcanceltype.o \ + pthread/pthread_setname_np.o \ + pthread/pthread_setschedparam.o \ + pthread/pthread_setschedprio.o \ + pthread/pthread_setspecific.o \ + pthread/pthread_spin_destroy.o \ + pthread/pthread_spin_init.o \ + pthread/pthread_spin_lock.o \ + pthread/pthread_spin_trylock.o \ + pthread/pthread_spin_unlock.o \ + pthread/pthread_testcancel.o \ + pthread/sched_get_priority_max.o \ + pthread/sched_get_priority_min.o \ + pthread/sched_yield.o \ + pthread/semaphore.o + C_REGEX := \ regex/regcomp.o \ regex/regerror.o \ @@ -208,6 +307,14 @@ C_SEARCH := \ search/tsearch.o \ search/twalk.o +C_SETJMP := \ + setjmp/_longjmp.o \ + setjmp/longjmp.o \ + setjmp/setjmp.o \ + setjmp/sigjmp.o \ + setjmp/siglongjmp.o \ + setjmp/sigsetjmp.o + C_SOCKET := \ resolv/dns_parse.o \ resolv/lookup_ipliteral.o \ @@ -478,11 +585,11 @@ C_STDLIB := \ stdlib/itoa.o \ stdlib/l64a.o \ stdlib/labs.o \ - stdlib/llabs.o \ - stdlib/lltoa.o \ stdlib/ldiv.o \ - stdlib/lldiv.o \ stdlib/lib_startup.o \ + stdlib/llabs.o \ + stdlib/lldiv.o \ + stdlib/lltoa.o \ stdlib/main.o \ stdlib/main_stub.o \ stdlib/malloc.o \ @@ -510,7 +617,6 @@ C_STDLIB := \ stdlib/secure_getenv.o \ stdlib/semaphore.o \ stdlib/setenv.o \ - stdlib/setjmp.o \ stdlib/set_errno.o \ stdlib/set_process_window.o \ stdlib/shared_objs.o \ @@ -636,6 +742,7 @@ C_TIME := \ time/clock.o \ time/clock_getres.o \ time/clock_gettime.o \ + time/clock_gettime64.o \ time/clock_nanosleep.o \ time/converttime.o \ time/convert_datestamp.o \ @@ -734,7 +841,9 @@ C_UNISTD := \ unistd/pipe.o \ unistd/pipe2.o \ unistd/pread.o \ + unistd/pread64.o \ unistd/pwrite.o \ + unistd/pwrite64.o \ unistd/readlink.o \ unistd/reallocarray.o \ unistd/realpath.o \ @@ -903,18 +1012,22 @@ C_WCHAR := \ C_LIB := \ $(C_BASE) \ - $(C_BYTESWAP) \ + $(C_AIO) \ $(C_ARGZ) \ + $(C_BYTESWAP) \ $(C_CTYPE) \ $(C_DIRENT) \ $(C_DEBUG) \ $(C_ICONV) \ $(C_INTTYPES) \ $(C_LOCALE) \ + $(C_MISC) \ $(C_MOUNT) \ $(C_POSIX) \ + $(C_PTHREAD) \ $(C_REGEX) \ $(C_SEARCH) \ + $(C_SETJMP) \ $(C_SOCKET) \ $(C_STAT) \ $(C_STDIO) \ @@ -935,9 +1048,6 @@ SOURCES_STATIC = $(addprefix $(OUT_STATIC)/, $(C_LIB)) $(OUT_STATIC)/c.lib_rev.o : $(LIB_DIR)/c.lib_rev.c $(LIB_DIR)/c.lib_rev.h $(BUILD_DIR)/obj.shared/c.lib_rev.o : $(LIB_DIR)/c.lib_rev.c $(LIB_DIR)/c.lib_rev.h -$(OUT_STATIC)/%.o : CFLAGS += $(LARGEDATA) -$(OUT_SHARED)/%.o : CFLAGS += $(PIC) $(LARGEDATA) - $(OUT_STATIC)/%.o : $(LIB_DIR)/%.sx $(VERBOSE)$(COMPILE_REG) $(OUT_STATIC)/%.o : $(LIB_DIR)/%.S @@ -960,5 +1070,5 @@ $(OUTPUT_LIB)/libc.so : $(SOURCES_SHARED) @$(MAKEDIR) $(@D) @$(DELETE) $@ $(VERBOSE)echo "Making Shared \033[0;31m$@\033[0m" - $(VERBOSE)$(CC) -nostdlib -mcrt=clib2 -shared -o $@ $(OUTPUT_LIB)/shcrtbegin.o $^ $(OUTPUT_LIB)/shcrtend.o $(LOG_COMMAND) + $(VERBOSE)$(CC) -nostdlib -mcrt=clib2 -shared -o $@ $(OUTPUT_LIB)/shcrtbegin.o $^ $(OUTPUT_LIB)/shcrtend.o $(LOG_COMMAND) -Wl,-soname,$(@F) $(COPY) $(OUTPUT_LIB)/libc.so $(INSTALL_PREFIX)/lib/ diff --git a/libpthread.gmk b/libpthread.gmk index 27729ec2..e4a2ca56 100644 --- a/libpthread.gmk +++ b/libpthread.gmk @@ -15,98 +15,16 @@ ifeq ($(STATIC),yes) LIBS += $(OUTPUT_LIB)/libpthread.a endif -C_PTHREAD := \ - pthread/common.o \ - pthread/pthread.o \ - pthread/pthread_attr_destroy.o \ - pthread/pthread_attr_getdetachstate.o \ - pthread/pthread_attr_getschedparam.o \ - pthread/pthread_attr_getstack.o \ - pthread/pthread_attr_getstacksize.o \ - pthread/pthread_attr_init.o \ - pthread/pthread_attr_setdetachstate.o \ - pthread/pthread_attr_setschedparam.o \ - pthread/pthread_attr_setstack.o \ - pthread/pthread_attr_setstacksize.o \ - pthread/pthread_barrier_destroy.o \ - pthread/pthread_barrier_init.o \ - pthread/pthread_barrier_wait.o \ - pthread/pthread_cancel.o \ - pthread/pthread_cleanup_pop.o \ - pthread/pthread_cleanup_push.o \ - pthread/pthread_cond_broadcast.o \ - pthread/pthread_cond_destroy.o \ - pthread/pthread_cond_init.o \ - pthread/pthread_cond_signal.o \ - pthread/pthread_cond_timedwait.o \ - pthread/pthread_cond_timedwait_relative_np.o \ - pthread/pthread_cond_wait.o \ - pthread/pthread_condattr_destroy.o \ - pthread/pthread_condattr_init.o \ - pthread/pthread_create.o \ - pthread/pthread_detach.o \ - pthread/pthread_equal.o \ - pthread/pthread_exit.o \ - pthread/pthread_getattr_np.o \ - pthread/pthread_getname_np.o \ - pthread/pthread_getschedparam.o \ - pthread/pthread_getspecific.o \ - pthread/pthread_join.o \ - pthread/pthread_key_create.o \ - pthread/pthread_key_delete.o \ - pthread/pthread_kill.o \ - pthread/pthread_mutex_destroy.o \ - pthread/pthread_mutex_init.o \ - pthread/pthread_mutex_lock.o \ - pthread/pthread_mutex_timedlock.o \ - pthread/pthread_mutex_trylock.o \ - pthread/pthread_mutex_unlock.o \ - pthread/pthread_mutexattr_destroy.o \ - pthread/pthread_mutexattr_gettype.o \ - pthread/pthread_mutexattr_init.o \ - pthread/pthread_mutexattr_settype.o \ - pthread/pthread_once.o \ - pthread/pthread_rwlock_destroy.o \ - pthread/pthread_rwlock_init.o \ - pthread/pthread_rwlock_rdlock.o \ - pthread/pthread_rwlock_timedrdlock.o \ - pthread/pthread_rwlock_timedwrlock.o \ - pthread/pthread_rwlock_tryrdlock.o \ - pthread/pthread_rwlock_trywrlock.o \ - pthread/pthread_rwlock_unlock.o \ - pthread/pthread_rwlock_wrlock.o \ - pthread/pthread_rwlockattr_destroy.o \ - pthread/pthread_rwlockattr_init.o \ - pthread/pthread_self.o \ - pthread/pthread_setcancelstate.o \ - pthread/pthread_setcanceltype.o \ - pthread/pthread_setname_np.o \ - pthread/pthread_setschedparam.o \ - pthread/pthread_setschedprio.o \ - pthread/pthread_setspecific.o \ - pthread/pthread_spin_destroy.o \ - pthread/pthread_spin_init.o \ - pthread/pthread_spin_lock.o \ - pthread/pthread_spin_trylock.o \ - pthread/pthread_spin_unlock.o \ - pthread/pthread_testcancel.o \ - pthread/sched_get_priority_max.o \ - pthread/sched_get_priority_min.o \ - pthread/sched_yield.o \ - pthread/semaphore.o - PTHREAD_LIB := \ - $(C_PTHREAD) \ - pthread.lib_rev.o + pthread/pthread.lib_rev.o SOURCES_SHARED = $(addprefix $(OUT_SHARED)/, $(PTHREAD_LIB)) SOURCES_STATIC = $(addprefix $(OUT_STATIC)/, $(PTHREAD_LIB)) - # Dependencies to rebuild if the library version changes -$(OUT_STATIC)/pthread.lib_rev.o : $(LIB_DIR)/pthread.lib_rev.c $(LIB_DIR)/pthread.lib_rev.h -$(OUT_SHARED)/pthread.lib_rev.o : $(LIB_DIR)/pthread.lib_rev.c $(LIB_DIR)/pthread.lib_rev.h +$(OUT_STATIC)/pthread.lib_rev.o : $(LIB_DIR)/pthread/pthread.lib_rev.c $(LIB_DIR)/pthread/pthread.lib_rev.h +$(OUT_SHARED)/pthread.lib_rev.o : $(LIB_DIR)/pthread/pthread.lib_rev.c $(LIB_DIR)/pthread/pthread.lib_rev.h $(OUT_STATIC)/%.o : CFLAGS = $(INCLUDES) -D__USE_INLINE__ -O3 -fno-builtin -Wno-type-limits -Wno-strict-aliasing -Wno-deprecated-declarations $(LARGEDATA) $(OUT_SHARED)/%.o : CFLAGS = $(INCLUDES) -D__USE_INLINE__ -O3 -fno-builtin -Wno-type-limits -Wno-strict-aliasing -Wno-deprecated-declarations $(PIC) $(LARGEDATA) diff --git a/library/aio/aio_cancel.c b/library/aio/aio_cancel.c new file mode 100644 index 00000000..6354f02c --- /dev/null +++ b/library/aio/aio_cancel.c @@ -0,0 +1,107 @@ +/* + * $Id: aio_aio_cancel.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_cancel(int fildes, struct aiocb *aiocbp) { + struct requestlist *req = NULL; + int result = AIO_ALLDONE; + + /* If fildes is invalid, error. */ + if (fcntl(fildes, F_GETFL) < 0) { + __set_errno(EBADF); + return -1; + } + + /* Request the mutex. */ + pthread_mutex_lock(&__aio_requests_mutex); + + /* We are asked to cancel a specific AIO request. */ + if (aiocbp != NULL) { + /* If the AIO request is not for this descriptor it has no value + to look for the request block. */ + if (aiocbp->aio_fildes != fildes) { + pthread_mutex_unlock(&__aio_requests_mutex); + __set_errno(EINVAL); + return -1; + } else if (aiocbp->__error_code == EINPROGRESS) { + struct requestlist *last = NULL; + + req = __aio_find_req_fd(fildes); + + if (req == NULL) { + not_found: + pthread_mutex_unlock(&__aio_requests_mutex); + __set_errno(EINVAL); + return -1; + } + + while (req->aiocbp != (aiocb_union *) aiocbp) { + last = req; + req = req->next_prio; + if (req == NULL) + goto not_found; + } + + /* Don't remove the entry if a thread is already working on it. */ + if (req->running == allocated) { + result = AIO_NOTCANCELED; + req = NULL; + } else { + /* We can remove the entry. */ + __aio_remove_request(last, req, 0); + + result = AIO_CANCELED; + + req->next_prio = NULL; + } + } + } else { + /* Find the beginning of the list of all requests for this + desriptor. */ + req = __aio_find_req_fd(fildes); + + /* If any request is worked on by a thread it must be the first. + So either we can delete all requests or all but the first. */ + if (req != NULL) { + if (req->running == allocated) { + struct requestlist *old = req; + req = req->next_prio; + old->next_prio = NULL; + + result = AIO_NOTCANCELED; + + if (req != NULL) + __aio_remove_request(old, req, 1); + } else { + result = AIO_CANCELED; + + /* We can remove the entry. */ + __aio_remove_request(NULL, req, 1); + } + } + } + + /* Mark requests as canceled and send signal. */ + while (req != NULL) { + struct requestlist *old = req; + assert(req->running == yes || req->running == queued); + req->aiocbp->aiocb.__error_code = ECANCELED; + req->aiocbp->aiocb.__return_value = -1; + __aio_notify(req); + req = req->next_prio; + __aio_free_request(old); + } + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); + + return result; +} diff --git a/library/aio/aio_error.c b/library/aio/aio_error.c new file mode 100644 index 00000000..8f3aacc1 --- /dev/null +++ b/library/aio/aio_error.c @@ -0,0 +1,22 @@ +/* + * $Id: aio_aio_error.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_error(const struct aiocb *aiocbp) { + int ret; + + /* Acquire the mutex to make sure all operations for this request are complete. */ + pthread_mutex_lock(&__aio_requests_mutex); + ret = aiocbp->__error_code; + pthread_mutex_unlock(&__aio_requests_mutex); + + return ret; +} \ No newline at end of file diff --git a/library/aio/aio_fsync.c b/library/aio/aio_fsync.c new file mode 100644 index 00000000..9d081430 --- /dev/null +++ b/library/aio/aio_fsync.c @@ -0,0 +1,26 @@ +/* + * $Id: aio_aio_error.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_fsync(int op, struct aiocb *aiocbp) { + if (op != O_DSYNC && __builtin_expect(op != O_SYNC, 0)) { + __set_errno(EINVAL); + return -1; + } + + /* Verify that this is an open file descriptor. */ + if (fcntl(aiocbp->aio_fildes, F_GETFL) == -1) { + __set_errno(EBADF); + return -1; + } + + return (__aio_enqueue_request((aiocb_union *) aiocbp, op == O_SYNC ? LIO_SYNC : LIO_DSYNC) == NULL ? -1 : 0); +} \ No newline at end of file diff --git a/library/aio/aio_misc.c b/library/aio/aio_misc.c new file mode 100644 index 00000000..359703de --- /dev/null +++ b/library/aio/aio_misc.c @@ -0,0 +1,645 @@ +/* + * $Id: aio_aio_misc.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include +#include +#include "aio_misc.h" +#include "pthread/common.h" + +#ifndef aio_create_helper_thread +# define aio_create_helper_thread __aio_create_helper_thread + +inline int +__aio_create_helper_thread(pthread_t *threadp, void *(*tf)(void *), void *arg, struct aiocb *aiocbp) { + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + SHOWMSG("Obtaining aio lock"); + ObtainSemaphore(__global_clib2->__aio_lock); + int ret = pthread_create(threadp, &attr, tf, arg); + if (ret == 0) { + AioThread aioThread; + SHOWMSG("pthread created correctly"); + ThreadInfo *inf = GetThreadInfo(*threadp); + aioThread.thread = inf->task; + aioThread.aiocbp = aiocbp; + aioThread.fileDes = aiocbp->aio_fildes; + D(("Adding AIO stream with filedes %ld", aiocbp->aio_fildes)); + + SHOWMSG("Adding pthread to list"); + __global_clib2->aio_threads->add(__global_clib2->aio_threads, &aioThread); + } + SHOWMSG("Releasing aio lock"); + ReleaseSemaphore(__global_clib2->__aio_lock); + pthread_attr_destroy(&attr); + return ret; +} + +#endif + +static void add_request_to_runlist(struct requestlist *newrequest); + +/* Pool of request list entries. */ +static struct requestlist **pool; + +/* Number of total and allocated pool entries. */ +static size_t pool_max_size; +static size_t pool_size; + +/* We implement a two dimensional array but allocate each row separately. + The macro below determines how many entries should be used per row. + It should better be a power of two. */ +#define ENTRIES_PER_ROW 32 + +/* How many rows we allocate at once. */ +#define ROWS_STEP 8 + +/* List of available entries. */ +static struct requestlist *freelist; + +/* List of request waiting to be processed. */ +static struct requestlist *runlist; + +/* Structure list of all currently processed requests. */ +static struct requestlist *requests; + +/* Number of threads currently running. */ +static int nthreads; + +/* Number of threads waiting for work to arrive. */ +static int idle_thread_count; + +/* These are the values used to optimize the use of AIO. The user can + overwrite them by using the `aio_init' function. */ +static struct aioinit optim = { + 20, /* int aio_threads; Maximal number of threads. */ + 64, /* int aio_num; Number of expected simultaneous requests. */ + 0, + 0, + 0, + 0, + 1, + 0 +}; + +/* Since the list is global we need a mutex protecting it. */ +pthread_mutex_t __aio_requests_mutex; // = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +/* When you add a request to the list and there are idle threads present, + you signal this condition variable. When a thread finishes work, it waits + on this condition variable for a time before it actually exits. */ +pthread_cond_t __aio_new_request_notification = PTHREAD_COND_INITIALIZER; + +/* Functions to handle request list pool. */ +static struct requestlist * +get_elem(void) { + struct requestlist *result; + + if (freelist == NULL) { + struct requestlist *new_row; + int cnt; + + assert(sizeof(struct aiocb) == sizeof(struct aiocb64)); + + if (pool_size + 1 >= pool_max_size) { + size_t new_max_size = pool_max_size + ROWS_STEP; + struct requestlist **new_tab; + + new_tab = (struct requestlist **) + realloc(pool, new_max_size * sizeof(struct requestlist *)); + + if (new_tab == NULL) + return NULL; + + pool_max_size = new_max_size; + pool = new_tab; + } + + /* Allocate the new row. */ + cnt = pool_size == 0 ? optim.aio_num : ENTRIES_PER_ROW; + new_row = (struct requestlist *) calloc(cnt, + sizeof(struct requestlist)); + if (new_row == NULL) + return NULL; + + pool[pool_size++] = new_row; + + /* Put all the new entries in the freelist. */ + do { + new_row->next_prio = freelist; + freelist = new_row++; + } while (--cnt > 0); + } + + result = freelist; + freelist = freelist->next_prio; + + return result; +} + + +void +__aio_free_request(struct requestlist *elem) { + elem->running = no; + elem->next_prio = freelist; + freelist = elem; +} + +struct requestlist * +__aio_find_req(aiocb_union *elem) { + struct requestlist *runp = requests; + int fildes = elem->aiocb.aio_fildes; + + while (runp != NULL && runp->aiocbp->aiocb.aio_fildes < fildes) + runp = runp->next_fd; + + if (runp != NULL) { + if (runp->aiocbp->aiocb.aio_fildes != fildes) + runp = NULL; + else + while (runp != NULL && runp->aiocbp != elem) + runp = runp->next_prio; + } + + return runp; +} + + +struct requestlist * +__aio_find_req_fd(int fildes) { + struct requestlist *runp = requests; + + while (runp != NULL && runp->aiocbp->aiocb.aio_fildes < fildes) + runp = runp->next_fd; + + return (runp != NULL && runp->aiocbp->aiocb.aio_fildes == fildes + ? runp : NULL); +} + + +void +__aio_remove_request(struct requestlist *last, struct requestlist *req, + int all) { + assert(req->running == yes || req->running == queued + || req->running == done); + + if (last != NULL) + last->next_prio = all ? NULL : req->next_prio; + else { + if (all || req->next_prio == NULL) { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_fd; + else + requests = req->next_fd; + if (req->next_fd != NULL) + req->next_fd->last_fd = req->last_fd; + } else { + if (req->last_fd != NULL) + req->last_fd->next_fd = req->next_prio; + else + requests = req->next_prio; + + if (req->next_fd != NULL) + req->next_fd->last_fd = req->next_prio; + + req->next_prio->last_fd = req->last_fd; + req->next_prio->next_fd = req->next_fd; + + /* Mark this entry as runnable. */ + req->next_prio->running = yes; + } + + if (req->running == yes) { + struct requestlist *runp = runlist; + + last = NULL; + while (runp != NULL) { + if (runp == req) { + if (last == NULL) + runlist = runp->next_run; + else + last->next_run = runp->next_run; + break; + } + last = runp; + runp = runp->next_run; + } + } + } +} + +/* The thread handler. */ +static void *handle_fildes_io(void *arg); + +/* User optimization. */ +void +__aio_init(const struct aioinit *init) { + /* Get the mutex. */ + pthread_mutex_lock(&__aio_requests_mutex); + + /* Only allow writing new values if the table is not yet allocated. */ + if (pool == NULL) { + optim.aio_threads = init->aio_threads < 1 ? 1 : init->aio_threads; + assert(powerof2(ENTRIES_PER_ROW)); + optim.aio_num = (init->aio_num < ENTRIES_PER_ROW + ? ENTRIES_PER_ROW + : init->aio_num & ~(ENTRIES_PER_ROW - 1)); + } + + if (init->aio_idle_time != 0) + optim.aio_idle_time = init->aio_idle_time; + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); +} + + +/* The main function of the async I/O handling. It enqueues requests + and if necessary starts and handles threads. */ +struct requestlist * +__aio_enqueue_request(aiocb_union *aiocbp, int operation) { + int result = 0; + int policy, prio; + struct sched_param param; + struct requestlist *last, *runp, *newp; + int running = no; + + if (operation == LIO_SYNC || operation == LIO_DSYNC) + aiocbp->aiocb.aio_reqprio = 0; + else if (aiocbp->aiocb.aio_reqprio < 0 +#ifdef AIO_PRIO_DELTA_MAX + || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX +#endif + ) { + /* Invalid priority value. */ + __set_errno(EINVAL); + aiocbp->aiocb.__error_code = EINVAL; + aiocbp->aiocb.__return_value = -1; + return NULL; + } + + /* Compute priority for this request. */ + pthread_getschedparam(pthread_self(), &policy, ¶m); + prio = param.sched_priority - aiocbp->aiocb.aio_reqprio; + + /* Get the mutex. */ + pthread_mutex_lock(&__aio_requests_mutex); + + last = NULL; + runp = requests; + /* First look whether the current file descriptor is currently + worked with. */ + while (runp != NULL + && runp->aiocbp->aiocb.aio_fildes < aiocbp->aiocb.aio_fildes) { + last = runp; + runp = runp->next_fd; + } + + /* Get a new element for the waiting list. */ + newp = get_elem(); + if (newp == NULL) { + pthread_mutex_unlock(&__aio_requests_mutex); + __set_errno(EAGAIN); + return NULL; + } + newp->aiocbp = aiocbp; + newp->waiting = NULL; + + aiocbp->aiocb.__abs_prio = prio; + aiocbp->aiocb.__policy = policy; + aiocbp->aiocb.aio_lio_opcode = operation; + aiocbp->aiocb.__error_code = EINPROGRESS; + aiocbp->aiocb.__return_value = 0; + + if (runp != NULL + && runp->aiocbp->aiocb.aio_fildes == aiocbp->aiocb.aio_fildes) { + /* The current file descriptor is worked on. It makes no sense + to start another thread since this new thread would fight + with the running thread for the resources. But we also cannot + say that the thread processing this desriptor shall immediately + after finishing the current job process this request if there + are other threads in the running queue which have a higher + priority. */ + + /* Simply enqueue it after the running one according to the + priority. */ + last = NULL; + while (runp->next_prio != NULL + && runp->next_prio->aiocbp->aiocb.__abs_prio >= prio) { + last = runp; + runp = runp->next_prio; + } + + newp->next_prio = runp->next_prio; + runp->next_prio = newp; + + running = queued; + } else { + running = yes; + /* Enqueue this request for a new descriptor. */ + if (last == NULL) { + newp->last_fd = NULL; + newp->next_fd = requests; + if (requests != NULL) + requests->last_fd = newp; + requests = newp; + } else { + newp->next_fd = last->next_fd; + newp->last_fd = last; + last->next_fd = newp; + if (newp->next_fd != NULL) + newp->next_fd->last_fd = newp; + } + + newp->next_prio = NULL; + last = NULL; + } + + if (running == yes) { + /* We try to create a new thread for this file descriptor. The + function which gets called will handle all available requests + for this descriptor and when all are processed it will + terminate. + + If no new thread can be created or if the specified limit of + threads for AIO is reached we queue the request. */ + + /* See if we need to and are able to create a thread. */ + if (nthreads < optim.aio_threads && idle_thread_count == 0) { + pthread_t thid; + + running = newp->running = allocated; + + /* Now try to start a thread. */ + result = aio_create_helper_thread(&thid, handle_fildes_io, newp, &aiocbp->aiocb); + if (result == 0) + /* We managed to enqueue the request. All errors which can + happen now can be recognized by calls to `aio_return' and + `aio_error'. */ + ++nthreads; + else { + /* Reset the running flag. The new request is not running. */ + running = newp->running = yes; + + if (nthreads == 0) { + /* We cannot create a thread in the moment and there is + also no thread running. This is a problem. `errno' is + set to EAGAIN if this is only a temporary problem. */ + __aio_remove_request(last, newp, 0); + } else + result = 0; + } + } + } + + /* Enqueue the request in the run queue if it is not yet running. */ + if (running == yes && result == 0) { + add_request_to_runlist(newp); + + /* If there is a thread waiting for work, then let it know that we + have just given it something to do. */ + if (idle_thread_count > 0) + pthread_cond_signal(&__aio_new_request_notification); + } + + SHOWVALUE(aiocbp->aiocb.__error_code); + SHOWVALUE(result); + if (result == 0) { + SHOWMSG("Running"); + newp->running = running; + } + else { + SHOWMSG("Error"); + /* Something went wrong. */ + __aio_free_request(newp); + aiocbp->aiocb.__error_code = result; + __set_errno(result); + newp = NULL; + } + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); + + return newp; +} + + +static void * +handle_fildes_io(void *arg) { + pthread_t self = pthread_self(); + struct sched_param param; + struct requestlist *runp = (struct requestlist *) arg; + aiocb_union *aiocbp; + int policy; + int fildes; + + pthread_getschedparam(self, &policy, ¶m); + + do { + /* If runp is NULL, then we were created to service the work queue + in general, not to handle any particular request. In that case we + skip the "do work" stuff on the first pass, and go directly to the + "get work off the work queue" part of this loop, which is near the + end. */ + if (runp == NULL) + pthread_mutex_lock(&__aio_requests_mutex); + else { + /* Hopefully this request is marked as running. */ + assert(runp->running == allocated); + + /* Update our variables. */ + aiocbp = runp->aiocbp; + fildes = aiocbp->aiocb.aio_fildes; + + /* Change the priority to the requested value (if necessary). */ + if (aiocbp->aiocb.__abs_prio != param.sched_priority || aiocbp->aiocb.__policy != policy) { + param.sched_priority = aiocbp->aiocb.__abs_prio; + policy = aiocbp->aiocb.__policy; + pthread_setschedparam(self, policy, ¶m); + } + + + /* Process request pointed to by RUNP. We must not be disturbed by signals. */ + if ((aiocbp->aiocb.aio_lio_opcode & 127) == LIO_READ) { + if (sizeof(off_t) != sizeof(off64_t) && aiocbp->aiocb.aio_lio_opcode & 128) + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(pread64(fildes, + (void *)aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes, + aiocbp->aiocb64.aio_offset)); + else + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(pread(fildes, + (void *) aiocbp->aiocb.aio_buf, + aiocbp->aiocb.aio_nbytes, + aiocbp->aiocb.aio_offset)); + + if (aiocbp->aiocb.__return_value == -1 && errno == ESPIPE) { + /* The Linux kernel is different from others. It returns + ESPIPE if using pread on a socket. Other platforms + simply ignore the offset parameter and behave like read. */ + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(read(fildes, + (void *) aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes)); + } + } else if ((aiocbp->aiocb.aio_lio_opcode & 127) == LIO_WRITE) { + if (sizeof(off_t) != sizeof(off64_t) && aiocbp->aiocb.aio_lio_opcode & 128) { + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(pwrite64(fildes, + (const void *) aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes, + aiocbp->aiocb64.aio_offset)); + } + else { + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(pwrite(fildes, + (const void *) aiocbp->aiocb.aio_buf, + aiocbp->aiocb.aio_nbytes, + aiocbp->aiocb.aio_offset)); + } + + if (aiocbp->aiocb.__return_value == -1 && errno == ESPIPE) { + /* The Linux kernel is different from others. It returns ESPIPE if using pwrite on a socket. Other platforms + simply ignore the offset parameter and behave like write. */ + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(write(fildes, + (void *) aiocbp->aiocb64.aio_buf, + aiocbp->aiocb64.aio_nbytes)); + } + } else if (aiocbp->aiocb.aio_lio_opcode == LIO_DSYNC) + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(fdatasync(fildes)); + else if (aiocbp->aiocb.aio_lio_opcode == LIO_SYNC) + aiocbp->aiocb.__return_value = TEMP_FAILURE_RETRY(fsync(fildes)); + else { + /* This is an invalid opcode. */ + aiocbp->aiocb.__return_value = -1; + __set_errno(EINVAL); + } + + /* Get the mutex. */ + pthread_mutex_lock(&__aio_requests_mutex); + + if (aiocbp->aiocb.__return_value == -1) { + aiocbp->aiocb.__error_code = errno; + } + else + aiocbp->aiocb.__error_code = 0; + + /* Send the signal to notify about finished processing of the request. */ + __aio_notify(runp); + + /* For debugging purposes we reset the running flag of the + finished request. */ + assert(runp->running == allocated); + runp->running = done; + + /* Now dequeue the current request. */ + __aio_remove_request(NULL, runp, 0); + if (runp->next_prio != NULL) + add_request_to_runlist(runp->next_prio); + + /* Free the old element. */ + __aio_free_request(runp); + } + + runp = runlist; + + /* If the runlist is empty, then we sleep for a while, waiting for something to arrive in it. */ + if (runp == NULL && optim.aio_idle_time >= 0) { + struct timespec now; + struct timespec wakeup_time; + + ++idle_thread_count; + clock_gettime(CLOCK_REALTIME, &now); + wakeup_time.tv_sec = now.tv_sec + optim.aio_idle_time; + wakeup_time.tv_nsec = now.tv_nsec; + if (wakeup_time.tv_nsec >= 1000000000) { + wakeup_time.tv_nsec -= 1000000000; + ++wakeup_time.tv_sec; + } + pthread_cond_timedwait(&__aio_new_request_notification, + &__aio_requests_mutex, + &wakeup_time); + --idle_thread_count; + runp = runlist; + } + + if (runp == NULL) + --nthreads; + else { + assert(runp->running == yes); + runp->running = allocated; + runlist = runp->next_run; + + /* If we have a request to process, and there's still another in + the run list, then we need to either wake up or create a new + thread to service the request that is still in the run list. */ + if (runlist != NULL) { + /* There are at least two items in the work queue to work on. + If there are other idle threads, then we should wake them + up for these other work elements; otherwise, we should try + to create a new thread. */ + if (idle_thread_count > 0) + pthread_cond_signal(&__aio_new_request_notification); + else if (nthreads < optim.aio_threads) { + pthread_t thid; + pthread_attr_t attr; + + /* Make sure the thread is created detached. */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + /* Now try to start a thread. If we fail, no big deal, + because we know that there is at least one thread (us) + that is working on AIO operations. */ + if (pthread_create(&thid, &attr, handle_fildes_io, NULL) == 0) + ++nthreads; + } + } + } + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); + } while (runp != NULL); + + return NULL; +} + +/* Free allocated resources. */ +void +__aio_free() { + size_t row; + + for (row = 0; row < pool_max_size; ++row) + free (pool[row]); + + free (pool); +} + +/* Add newrequest to the runlist. The __abs_prio flag of newrequest must + be correctly set to do this. Also, you had better set newrequest's + "running" flag to "yes" before you release your lock or you'll throw an + assertion. */ +static void +add_request_to_runlist(struct requestlist *newrequest) { + int prio = newrequest->aiocbp->aiocb.__abs_prio; + struct requestlist *runp; + + if (runlist == NULL || runlist->aiocbp->aiocb.__abs_prio < prio) { + newrequest->next_run = runlist; + runlist = newrequest; + } else { + runp = runlist; + + while (runp->next_run != NULL + && runp->next_run->aiocbp->aiocb.__abs_prio >= prio) + runp = runp->next_run; + + newrequest->next_run = runp->next_run; + runp->next_run = newrequest; + } +} diff --git a/library/aio/aio_misc.h b/library/aio/aio_misc.h new file mode 100644 index 00000000..4349a19f --- /dev/null +++ b/library/aio/aio_misc.h @@ -0,0 +1,120 @@ +/* Copyright (C) 1997-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _AIO_MISC_H +#define _AIO_MISC_H 1 + +#include +#include + +typedef struct AioThread { + struct MinNode node; + struct Task *thread; + struct aiocb *aiocbp; + int fileDes; +} AioThread; + +/* Extend the operation enum. */ +enum { + LIO_DSYNC = LIO_NOP + 1, + LIO_SYNC, + LIO_READ64 = LIO_READ | 128, + LIO_WRITE64 = LIO_WRITE | 128 +}; + +/* Union of the two request types. */ +typedef union { + struct aiocb aiocb; + struct aiocb64 aiocb64; +} aiocb_union; + + +/* Used to synchronize. */ +struct waitlist { + struct waitlist *next; + + /* The next two fields is used in synchronous `lio_listio' operations. */ +#ifndef DONT_NEED_AIO_MISC_COND + pthread_cond_t *cond; +#endif + int *result; + + volatile unsigned int *counterp; + /* The next field is used in asynchronous `lio_listio' operations. */ + struct sigevent *sigevp; +}; + + +/* Status of a request. */ +enum { + no, + queued, + yes, + allocated, + done +}; + + +/* Used to queue requests.. */ +struct requestlist { + int running; + + struct requestlist *last_fd; + struct requestlist *next_fd; + struct requestlist *next_prio; + struct requestlist *next_run; + + /* Pointer to the actual data. */ + aiocb_union *aiocbp; + + /* List of waiting processes. */ + struct waitlist *waiting; +}; + +extern void __aio_init(const struct aioinit *init); +extern void __aio_free(); + +/* Lock for global I/O list of requests. */ +extern pthread_mutex_t __aio_requests_mutex __attribute__ ((visibility ("hidden"))); + +/* Enqueue request. */ +extern struct requestlist *__aio_enqueue_request(aiocb_union *aiocbp, int operation) __attribute__ ((visibility ("hidden"))); + +/* Find request entry for given AIO control block. */ +extern struct requestlist *__aio_find_req(aiocb_union *elem) __attribute__ ((visibility ("hidden"))); + +/* Find request entry for given file descriptor. */ +extern struct requestlist *__aio_find_req_fd(int fildes) __attribute__ ((visibility ("hidden"))); + +/* Remove request from the list. */ +extern void __aio_remove_request(struct requestlist *last, struct requestlist *req, int all) __attribute__ ((visibility ("hidden"))); + +/* Release the entry for the request. */ +extern void __aio_free_request(struct requestlist *req) __attribute__ ((visibility ("hidden"))); + +/* Notify initiator of request and tell this everybody listening. */ +extern void __aio_notify(struct requestlist *req) __attribute__ ((visibility ("hidden"))); + +/* Notify initiator of request. */ +extern int __aio_notify_only(struct sigevent *sigev) __attribute__ ((visibility ("hidden"))); + +/* Send the signal. */ +extern int __aio_sigqueue(int sig, const union sigval val, pid_t caller_pid) __attribute__ ((visibility ("hidden"))); + +extern int __aio_suspend_time64 (const struct aiocb *const list[], int nent, const struct timespec64 *timeout); + +#endif /* aio_misc.h */ diff --git a/library/aio/aio_notify.c b/library/aio/aio_notify.c new file mode 100644 index 00000000..f144cd14 --- /dev/null +++ b/library/aio/aio_notify.c @@ -0,0 +1,120 @@ +/* + * $Id: aio_aio_notify.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include +#include +#include "aio_misc.h" + +#ifndef aio_start_notify_thread +# define aio_start_notify_thread() do { } while (0) +#endif + +struct notify_func { + void (*func)(sigval_t); + + sigval_t value; +}; + +static void * +notify_func_wrapper(void *arg) { + aio_start_notify_thread (); + struct notify_func *const n = arg; + void (*func)(sigval_t) = n->func; + sigval_t value = n->value; + free(n); + (*func)(value); + return NULL; +} + + +int +__aio_notify_only(struct sigevent *sigev) { + int result = 0; + + /* Send the signal to notify about finished processing of the request. */ + if (sigev->sigev_notify == SIGEV_THREAD) { + /* We have to start a thread. */ + pthread_t tid; + pthread_attr_t attr, *pattr; + + pattr = (pthread_attr_t *) sigev->sigev_notify_attributes; + if (pattr == NULL) { + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pattr = &attr; + } + + /* SIGEV may be freed as soon as we return, so we cannot let the + notification thread use that pointer. Even though a sigval_t is + only one word and the same size as a void *, we cannot just pass + the value through pthread_create as the argument and have the new + thread run the user's function directly, because on some machines + the calling convention for a union like sigval_t is different from + that for a pointer type like void *. */ + struct notify_func *nf = malloc(sizeof *nf); + if (nf == NULL) + result = -1; + else { + nf->func = sigev->sigev_notify_function; + nf->value = sigev->sigev_value; + if (pthread_create(&tid, pattr, notify_func_wrapper, nf) < 0) { + free(nf); + result = -1; + } + } + } else if (sigev->sigev_notify == SIGEV_SIGNAL) { + /* There are no queued signals on this system at all. */ + result = raise(sigev->sigev_signo); + } + + return result; +} + + +void +__aio_notify(struct requestlist *req) { + struct waitlist *waitlist; + struct aiocb *aiocbp = &req->aiocbp->aiocb; + + if (__aio_notify_only(&aiocbp->aio_sigevent) != 0) { + /* XXX What shall we do if already an error is set by read/write/fsync? */ + aiocbp->__error_code = errno; + aiocbp->__return_value = -1; + } + + /* Now also notify possibly waiting threads. */ + waitlist = req->waiting; + while (waitlist != NULL) { + struct waitlist *next = waitlist->next; + + if (waitlist->sigevp == NULL) { + if (waitlist->result != NULL && aiocbp->__return_value == -1) + *waitlist->result = -1; + +#ifdef DONT_NEED_AIO_MISC_COND + AIO_MISC_NOTIFY (waitlist); +#else + /* Decrement the counter. */ + --*waitlist->counterp; + + pthread_cond_signal(waitlist->cond); +#endif + } else + /* This is part of an asynchronous `lio_listio' operation. If + this request is the last one, send the signal. */ + if (--*waitlist->counterp == 0) { + __aio_notify_only(waitlist->sigevp); + /* This is tricky. See lio_listio.c for the reason why + this works. */ + free((void *) waitlist->counterp); + } + + waitlist = next; + } +} diff --git a/library/aio/aio_read.c b/library/aio/aio_read.c new file mode 100644 index 00000000..8bbf6f54 --- /dev/null +++ b/library/aio/aio_read.c @@ -0,0 +1,17 @@ +/* + * $Id: aio_aio_read.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_read(struct aiocb *aiocbp) { + return (__aio_enqueue_request((aiocb_union *) aiocbp, LIO_READ) == NULL ? -1 : 0); +} + diff --git a/library/aio/aio_read64.c b/library/aio/aio_read64.c new file mode 100644 index 00000000..30084de1 --- /dev/null +++ b/library/aio/aio_read64.c @@ -0,0 +1,17 @@ +/* + * $Id: aio_aio_read64.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_read64 (struct aiocb64 *aiocbp) { + return (__aio_enqueue_request ((aiocb_union *) aiocbp, LIO_READ64) == NULL ? -1 : 0); +} + diff --git a/library/aio/aio_return.c b/library/aio/aio_return.c new file mode 100644 index 00000000..20ff99bd --- /dev/null +++ b/library/aio/aio_return.c @@ -0,0 +1,16 @@ +/* + * $Id: aio_aio_return.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +ssize_t +aio_return(struct aiocb *aiocbp) { + return aiocbp->__return_value; +} \ No newline at end of file diff --git a/library/aio/aio_sigqueue.c b/library/aio/aio_sigqueue.c new file mode 100644 index 00000000..e56b1769 --- /dev/null +++ b/library/aio/aio_sigqueue.c @@ -0,0 +1,18 @@ +/* + * $Id: aio_aio_sigqueue.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +__attribute__ ((visibility ("hidden"))) +__aio_sigqueue(int sig, const union sigval val, pid_t caller_pid) { + __set_errno(ENOSYS); + return -1; +} \ No newline at end of file diff --git a/library/aio/aio_suspend.c b/library/aio/aio_suspend.c new file mode 100644 index 00000000..0ece2eb1 --- /dev/null +++ b/library/aio/aio_suspend.c @@ -0,0 +1,188 @@ +/* + * $Id: aio_aio_suspend.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#ifndef _TIME_HEADERS_H +#include "time_headers.h" +#endif /* _TIME_HEADERS_H */ + +#include +#include +#include + +#include "aio_misc.h" + +struct clparam { + const struct aiocb *const *list; + struct waitlist *waitlist; + struct requestlist **requestlist; + pthread_cond_t *cond; + int nent; +}; + + +static void +cleanup(void *arg) { + const struct clparam *param = (const struct clparam *) arg; + + /* Now remove the entry in the waiting list for all requests which didn't terminate. */ + int cnt = param->nent; + while (cnt-- > 0) { + if (param->list[cnt] != NULL && param->list[cnt]->__error_code == EINPROGRESS) { + struct waitlist **listp; + + assert(param->requestlist[cnt] != NULL); + + /* There is the chance that we cannot find our entry anymore. This + could happen if the request terminated and restarted again. */ + listp = ¶m->requestlist[cnt]->waiting; + while (*listp != NULL && *listp != ¶m->waitlist[cnt]) + listp = &(*listp)->next; + + if (*listp != NULL) + *listp = (*listp)->next; + } + } + + /* Release the conditional variable. */ + pthread_cond_destroy(param->cond); + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); +} + +int +__aio_suspend_time64(const struct aiocb *const list[], int nent, const struct timespec64 *timeout) { + ENTER(); + SHOWVALUE(nent); + + if (nent < 0) { + __set_errno(EINVAL); + RETURN(-1); + return -1; + } + + struct waitlist waitlist[nent]; + struct requestlist *requestlist[nent]; + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + int cnt; + bool any = false; + int result = 0; + unsigned int cntr = 1; + + /* Request the mutex. */ + pthread_mutex_lock(&__aio_requests_mutex); + + /* There is not yet a finished request. Signal the request that we are working for it. */ + for (cnt = 0; cnt < nent; ++cnt) { + if (list[cnt] != NULL) { + SHOWMSG("Find an element to suspend"); + SHOWVALUE(list[cnt]->__error_code); + if (list[cnt]->__error_code == EINPROGRESS) { + SHOWMSG("In it EINPROGRESS"); + requestlist[cnt] = __aio_find_req((aiocb_union *) list[cnt]); + + if (requestlist[cnt] != NULL) { + waitlist[cnt].cond = &cond; + waitlist[cnt].result = NULL; + waitlist[cnt].next = requestlist[cnt]->waiting; + waitlist[cnt].counterp = &cntr; + waitlist[cnt].sigevp = NULL; + requestlist[cnt]->waiting = &waitlist[cnt]; + any = true; + } else + /* We will never suspend. */ + break; + } else + /* We will never suspend. */ + break; + } + } + + struct timespec64 ts; + if (timeout != NULL) { + clock_gettime64(CLOCK_MONOTONIC, &ts); + ts.tv_sec += timeout->tv_sec; + ts.tv_nsec += timeout->tv_nsec; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } + } + SHOWVALUE(cnt); + SHOWVALUE(nent); + SHOWVALUE(any); + /* Only if none of the entries is NULL or finished to be wait. */ + if (cnt == nent && any) { + struct clparam clparam = { + .list = list, + .waitlist = waitlist, + .requestlist = requestlist, + .cond = &cond, + .nent = nent + }; + + SHOWMSG("Call pthread_cleanup_push"); + pthread_cleanup_push(cleanup, &clparam); + + struct timespec ts32 = valid_timespec64_to_timespec(ts); + result = pthread_cond_timedwait(&cond, &__aio_requests_mutex, timeout == NULL ? NULL : &ts32); + + pthread_cleanup_pop(0); + } + + /* Now remove the entry in the waiting list for all requests + which didn't terminate. */ + while (cnt-- > 0) + if (list[cnt] != NULL && list[cnt]->__error_code == EINPROGRESS) { + struct waitlist **listp; + + assert(requestlist[cnt] != NULL); + + /* There is the chance that we cannot find our entry anymore. This + could happen if the request terminated and restarted again. */ + listp = &requestlist[cnt]->waiting; + while (*listp != NULL && *listp != &waitlist[cnt]) + listp = &(*listp)->next; + + if (*listp != NULL) + *listp = (*listp)->next; + } + + /* Release the conditional variable. */ + if (pthread_cond_destroy(&cond) != 0) + /* This must never happen. */ + abort(); + + if (result != 0) { + /* An error occurred. Possibly it's ETIMEDOUT. We have to translate + the timeout error report of `pthread_cond_timedwait' to the + form expected from `aio_suspend'. */ + if (result == ETIMEDOUT) + __set_errno(EAGAIN); + else + __set_errno(result); + + result = -1; + } + + /* Release the mutex. */ + pthread_mutex_unlock(&__aio_requests_mutex); + + RETURN(result); + return result; +} + +int +aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout) { + struct timespec64 ts64; + + if (timeout != NULL) + ts64 = valid_timespec_to_timespec64(*timeout); + + return __aio_suspend_time64(list, nent, timeout != NULL ? &ts64 : NULL); +} diff --git a/library/aio/aio_write.c b/library/aio/aio_write.c new file mode 100644 index 00000000..b5e18515 --- /dev/null +++ b/library/aio/aio_write.c @@ -0,0 +1,16 @@ +/* + * $Id: aio_aio_write.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_write(struct aiocb *aiocbp) { + return (__aio_enqueue_request((aiocb_union *) aiocbp, LIO_WRITE) == NULL ? -1 : 0); +} diff --git a/library/aio/aio_write64.c b/library/aio/aio_write64.c new file mode 100644 index 00000000..ed87d02a --- /dev/null +++ b/library/aio/aio_write64.c @@ -0,0 +1,16 @@ +/* + * $Id: aio_aio_write64.c,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#include +#include +#include "aio_misc.h" + +int +aio_write64(struct aiocb64 *aiocbp) { + return (__aio_enqueue_request((aiocb_union *) aiocbp, LIO_WRITE64) == NULL ? -1 : 0); +} \ No newline at end of file diff --git a/library/crt0.S b/library/crt0.S index 95ac0794..3125895d 100644 --- a/library/crt0.S +++ b/library/crt0.S @@ -1,43 +1,9 @@ // -// $Id: crt0.S,v 1.6 2005-10-11 09:28:29 clib2devs Exp $ +// $Id: crt0.S,v 1.7 2005-10-11 09:28:29 clib2devs Exp $ // // :ts=4 -// -// Portable ISO 'C' (1994) runtime library for the Amiga computer -// Copyright (c) 2002-2015 by Olaf Barthel -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Neither the name of Olaf Barthel nor the names of contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// - .text .globl main /* This enforces linkage against the main() function */ - .globl _main + .globl _main .globl _start - - -_start: - - b _main \ No newline at end of file diff --git a/library/crtbegin.c b/library/crtbegin.c index 944576e9..f706cfdb 100644 --- a/library/crtbegin.c +++ b/library/crtbegin.c @@ -42,36 +42,187 @@ * refer to only the __CTOR_END__ symbol in sh/crtend.o and the __DTOR_LIST__ * symbol in sh/crtbegin.o, where they are defined. */ -typedef void (*func_ptr) (void); +static void (*__CTOR_LIST__[1])(void) __attribute__((section(".ctors"))); +static void (*__DTOR_LIST__[1])(void) __attribute__((section(".dtors"))); -static func_ptr __CTOR_LIST__[1] __attribute__((used, section(".ctors"), aligned(sizeof(func_ptr)))) = { (func_ptr) (-1) };; -static func_ptr __DTOR_LIST__[1] __attribute__((used, section(".dtors"), aligned(sizeof(func_ptr)))) = { (func_ptr) (-1) };; +BOOL open_libraries(void); +void close_libraries(void); + +/* These are used to initialize the shared objects linked to this binary, + and for the dlopen(), dlclose() and dlsym() functions. */ +struct Library *__ElfBase; +struct ElfIFace *__IElf; +static Elf32_Handle elf_handle; void _init(void) { - int num_ctors, i; - int j; + int i = 0; - /* The shared objects need to be set up before any local constructors are invoked. */ - shared_obj_init(); + while (__CTOR_LIST__[i + 1]) { + i++; + } + SHOWVALUE(i); + while (i > 0) { + SHOWMSG("Calling ctor"); + SHOWVALUE(i); + __CTOR_LIST__[i--](); + } +} - for (i = 1, num_ctors = 0; __CTOR_LIST__[i] != NULL; i++) - num_ctors++; +void _fini(void) { + int i = 1; - for (j = 0; j < num_ctors; j++) - __CTOR_LIST__[num_ctors - j](); + while (__DTOR_LIST__[i]) { + SHOWMSG("Calling dtor"); + SHOWVALUE(i); + __DTOR_LIST__[i++](); + } } -void _fini(void) { - int num_dtors, i; - static int j = 0; +void close_libraries(void) { + if (__IUtility != NULL) { + DropInterface((struct Interface *) __IUtility); + __IUtility = NULL; + } - for (i = 1, num_dtors = 0; __DTOR_LIST__[i] != NULL; i++) - num_dtors++; + if (__UtilityBase != NULL) { + CloseLibrary(__UtilityBase); + __UtilityBase = NULL; + } - while (j++ < num_dtors) - __DTOR_LIST__[j](); + if (__IElf != NULL) { + DropInterface((struct Interface *) __IElf); + __IElf = NULL; + } - /* The shared objects need to be cleaned up after all local - destructors have been invoked. */ - shared_obj_exit(); + if (__ElfBase != NULL) { + CloseLibrary(__ElfBase); + __ElfBase = NULL; + } + + if (IDOS != NULL) { + DropInterface((struct Interface *) IDOS); + IDOS = NULL; + } + + if (DOSBase != NULL) { + CloseLibrary(DOSBase); + DOSBase = NULL; + } +} + +BOOL open_libraries(void) { + /* Open the minimum required libraries. */ + BOOL success = FALSE; + + /* Open the minimum required libraries. */ + DOSBase = (struct Library *) OpenLibrary("dos.library", MIN_OS_VERSION); + if (DOSBase == NULL) { + SHOWMSG("Cannot get DOSBase!"); + goto out; + } + + /* Obtain the interfaces for these libraries. */ + IDOS = (struct DOSIFace *) GetInterface(DOSBase, "main", 1, NULL); + if (IDOS == NULL) { + SHOWMSG("Cannot get IDOS!"); + goto out; + } + + /* We need elf.library V52.2 or higher. */ + __ElfBase = OpenLibrary("elf.library", 0); + if (__ElfBase == NULL || (__ElfBase->lib_Version < 52) || (__ElfBase->lib_Version == 52 && __ElfBase->lib_Revision < 2)) { + SHOWMSG("Cannot get __ElfBase >=52.2!"); + goto out; + } + + __IElf = (struct ElfIFace *) GetInterface(__ElfBase, "main", 1, NULL); + if (__IElf == NULL) { + SHOWMSG("Cannot get __IElf!"); + goto out; + } + + __UtilityBase = OpenLibrary("utility.library", MIN_OS_VERSION); + if (__UtilityBase == NULL) + goto out; + + __IUtility = (struct UtilityIFace *) GetInterface(__UtilityBase, "main", 1, 0); + if (__IUtility == NULL) + goto out; + + success = TRUE; + +out: + + return (success); } + +void shared_obj_exit(void) { + struct ElfIFace *IElf = __IElf; + ENTER(); + + /* If we got what we wanted, trigger the destructors, etc. in the shared objects linked to this binary. */ + if (elf_handle != NULL) { + SHOWMSG("Invoking shared object destructors"); + InitSHLibs(elf_handle, FALSE); + elf_handle = NULL; + }; + + close_libraries(); + LEAVE(); +} + +void shared_obj_init(void) { + ENTER(); + + if (open_libraries()) { + struct ElfIFace *IElf = __IElf; + + BPTR segment_list = GetProcSegList(NULL, GPSLF_RUN | GPSLF_SEG); + if (segment_list != ZERO) { + int ret = GetSegListInfoTags(segment_list, GSLI_ElfHandle, &elf_handle, TAG_DONE); + if (ret == 1) { + if (elf_handle != NULL) { + /* Trigger the constructors, etc. in the shared objects linked to this binary. */ + InitSHLibs(elf_handle, TRUE); + } + else { + SHOWMSG("elf_handle == NULL!"); + } + } + else { + SHOWMSG("GetSegListInfoTags fail!"); + } + } + else { + SHOWMSG("GetProcSegList return ZERO!"); + } + } + else { + SHOWMSG("Cannot open libraries!"); + const char *error_message; + + /* If available, use the error message provided by the client. */ + error_message = __minimum_os_lib_error; + + if (error_message == NULL) + error_message = "This program requires AmigaOS 4.0 (52.2) or higher."; + + __show_error(error_message); + } + LEAVE(); +} + +int _start(STRPTR argstring, int32 arglen, struct ExecBase *sysbase) { + SysBase = *(struct Library **) 4; + IExec = (struct ExecIFace *) ((struct ExecBase *) SysBase)->MainInterface; + + /* The shared objects need to be set up before any local constructors are invoked. */ + shared_obj_init(); + + int r = _main(); + + /* The shared objects need to be cleaned up after all local destructors have been invoked. */ + shared_obj_exit(); + + return r; +} \ No newline at end of file diff --git a/library/crtend.c b/library/crtend.c index 3c2ac019..4914609c 100755 --- a/library/crtend.c +++ b/library/crtend.c @@ -2,7 +2,5 @@ * $Id: crtend.c,v 1.3 2023-02-18 21:07:25 clib2devs Exp $ */ -typedef void (*func_ptr)(void); - -static func_ptr __CTOR_END__[1] __attribute__(( used, section(".ctors"), aligned(sizeof(func_ptr)))) = {(func_ptr) 0}; -static func_ptr __DTOR_END__[1] __attribute__(( used, section(".dtors"), aligned(sizeof(func_ptr)))) = {(func_ptr) 0}; +static void (*__CTOR_LIST__[1])(void) __attribute__((used, section(".ctors"))); +static void (*__DTOR_LIST__[1])(void) __attribute__((used, section(".dtors"))); diff --git a/library/dirent/closedir.c b/library/dirent/closedir.c index 76ecb8c5..162e1d59 100644 --- a/library/dirent/closedir.c +++ b/library/dirent/closedir.c @@ -28,8 +28,7 @@ void __dirent_unlock(void) { ReleaseSemaphore(dirent_lock); } -CLIB_CONSTRUCTOR(dirent_init) -{ +CLIB_CONSTRUCTOR(dirent_init) { BOOL success = FALSE; ENTER(); @@ -38,7 +37,7 @@ CLIB_CONSTRUCTOR(dirent_init) dirent_lock = __create_semaphore(); if (dirent_lock == NULL) - goto out; + goto out; success = TRUE; @@ -53,8 +52,7 @@ CLIB_CONSTRUCTOR(dirent_init) CONSTRUCTOR_FAIL(); } -CLIB_DESTRUCTOR(dirent_exit) -{ +CLIB_DESTRUCTOR(dirent_exit) { ENTER(); if (__directory_list.mlh_Head != NULL) diff --git a/library/fcntl/fcntl.c b/library/fcntl/fcntl.c index adf3b1d5..3b1bf400 100644 --- a/library/fcntl/fcntl.c +++ b/library/fcntl/fcntl.c @@ -24,9 +24,11 @@ fcntl(int file_descriptor, int cmd, ... /* int arg */) { SHOWVALUE(file_descriptor); SHOWVALUE(cmd); - assert(file_descriptor >= 0 && file_descriptor < __num_fd); - assert(__fd[file_descriptor] != NULL); - assert(FLAG_IS_SET(__fd[file_descriptor]->fd_Flags, FDF_IN_USE)); + if (__fd[file_descriptor] == NULL || FLAG_IS_CLEAR(__fd[file_descriptor]->fd_Flags, FDF_IN_USE) || file_descriptor < 0 || file_descriptor > __num_fd) { + __set_errno(EINVAL); + goto out; + } + __set_errno(0); __check_abort(); diff --git a/library/fcntl/read.c b/library/fcntl/read.c index 2b0ec4c8..445f58db 100644 --- a/library/fcntl/read.c +++ b/library/fcntl/read.c @@ -50,7 +50,6 @@ read(int file_descriptor, void *buffer, size_t num_bytes) { __set_errno(EINVAL); goto out; } - printf("read\n"); if (num_bytes > 0) { struct file_action_message fam; diff --git a/library/fcntl/write.c b/library/fcntl/write.c index 1df61ddc..a927000a 100644 --- a/library/fcntl/write.c +++ b/library/fcntl/write.c @@ -67,6 +67,10 @@ write(int file_descriptor, const void *buffer, size_t num_bytes) { __set_errno(fam.fam_Error); goto out; } + + if (num_bytes_written != num_bytes) { + __set_errno(__translate_io_error_to_errno(IoErr())); + } } else { num_bytes_written = 0; } diff --git a/library/include/aio.h b/library/include/aio.h new file mode 100644 index 00000000..c4f21049 --- /dev/null +++ b/library/include/aio.h @@ -0,0 +1,154 @@ +#ifndef _AIO_H +#define _AIO_H + +#ifndef __USE_FILE_OFFSET64 +#define _LARGEFILE64_SOURCE +#endif + +#include +#include +#include + +__BEGIN_DECLS + +/* Asynchronous I/O control block. */ +struct aiocb { + int aio_fildes; /* File descriptor. */ + int aio_lio_opcode; /* Operation to be performed. */ + int aio_reqprio; /* Request priority offset. */ + volatile void *aio_buf; /* Location of buffer. */ + size_t aio_nbytes; /* Length of transfer. */ + struct sigevent aio_sigevent; /* Signal number and value. */ + + /* Internal members. */ + struct aiocb *__next_prio; + int __abs_prio; + int __policy; + int __error_code; + ssize_t __return_value; + +#ifndef __USE_FILE_OFFSET64 + off_t aio_offset; /* File offset. */ + char __pad[sizeof (int64_t) - sizeof (off_t)]; +#else + int64_t aio_offset; /* File offset. */ +#endif + char __libc_reserved[32]; +}; + +/* The same for the 64bit offsets. Please note that the members aio_fildes + to __return_value have to be the same in aiocb and aiocb64. */ +#ifdef __USE_LARGEFILE64 +struct aiocb64 { + int aio_fildes; /* File descriptor. */ + int aio_lio_opcode; /* Operation to be performed. */ + int aio_reqprio; /* Request priority offset. */ + volatile void *aio_buf; /* Location of buffer. */ + size_t aio_nbytes; /* Length of transfer. */ + struct sigevent aio_sigevent; /* Signal number and value. */ + + /* Internal members. */ + struct aiocb *__next_prio; + int __abs_prio; + int __policy; + int __error_code; + ssize_t __return_value; + + off64_t aio_offset; /* File offset. */ + char __glibc_reserved[32]; +}; +#endif + + +#ifdef __USE_GNU +/* To optimize the implementation one can use the following struct. */ +struct aioinit { + int aio_threads; /* Maximum number of threads. */ + int aio_num; /* Number of expected simultaneous requests. */ + int aio_locks; /* Not used. */ + int aio_usedba; /* Not used. */ + int aio_debug; /* Not used. */ + int aio_numusers; /* Not used. */ + int aio_idle_time; /* Number of seconds before idle thread terminates. */ + int aio_reserved; +}; +#endif + + +/* Return values of the aio_cancel function. */ +enum { + AIO_CANCELED, +#define AIO_CANCELED AIO_CANCELED + AIO_NOTCANCELED, +#define AIO_NOTCANCELED AIO_NOTCANCELED + AIO_ALLDONE +#define AIO_ALLDONE AIO_ALLDONE +}; + + +/* Operation codes for `aio_lio_opcode'. */ +enum { + LIO_READ, +#define LIO_READ LIO_READ + LIO_WRITE, +#define LIO_WRITE LIO_WRITE + LIO_NOP +#define LIO_NOP LIO_NOP +}; + + +/* Synchronization options for `lio_listio' function. */ +enum { + LIO_WAIT, +#define LIO_WAIT LIO_WAIT + LIO_NOWAIT +#define LIO_NOWAIT LIO_NOWAIT +}; + + +/* Allow user to specify optimization. */ +#ifdef __USE_GNU +extern void aio_init (const struct aioinit *init); +#endif + +/* Enqueue read request for given number of bytes and the given priority. */ +extern int aio_read(struct aiocb *aiocbp); +/* Enqueue write request for given number of bytes and the given priority. */ +extern int aio_write(struct aiocb *aiocbp); + +/* Initiate list of I/O requests. */ +extern int lio_listio(int mode, struct aiocb *const list[restrict], int nent, struct sigevent * sig); + +/* Retrieve error status associated with AIOCBP. */ +extern int aio_error(const struct aiocb *aiocbp); +/* Return status associated with AIOCBP. */ +extern ssize_t aio_return(struct aiocb *aiocbp); + +/* Try to cancel asynchronous I/O requests outstanding against file descriptor FILDES. */ +extern int aio_cancel(int fildes, struct aiocb *aiocbp); + +/* Suspend calling thread until at least one of the asynchronous I/O + operations referenced by LIST has completed. + This function is a cancellation point and therefore not marked with. +*/ +extern int aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout); + +/* Force all operations associated with file desriptor described by + `aio_fildes' member of AIOCBP. */ +extern int aio_fsync(int operation, struct aiocb *aiocbp); + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +extern int aio_read64 (struct aiocb64 *aiocbp); +extern int aio_write64 (struct aiocb64 *aiocbp); +# define aio_error64 aio_error +# define aio_return64 aio_return +# define aio_cancel64 aio_cancel +# define aio_suspend64 aio_suspend +# define aio_fsync64 aio_fsync +# define lio_listio64 lio_listio +#endif + +__END_DECLS + + +#endif diff --git a/library/include/dos.h b/library/include/dos.h index 84726657..2ffd3ad7 100755 --- a/library/include/dos.h +++ b/library/include/dos.h @@ -19,6 +19,8 @@ #include #include +#include "misc/clist.h" + __BEGIN_DECLS /* @@ -460,8 +462,7 @@ struct _wchar * and populated with all its fields. At moment it holds just global fields */ -struct _clib2 -{ +struct _clib2 { struct ExecIFace *IExec; /* Main IExec interface */ struct TimeVal clock; /* Populated when clib starts with current time */ @@ -488,7 +489,7 @@ struct _clib2 int __mb_cur_max; /* used by tmpnam */ - int inc; + int inc; /* CPU Family to enable optimized functions */ uint32 optimizedCPUFunctions; @@ -513,6 +514,10 @@ struct _clib2 struct itimerval tmr_time; struct timeval tmr_start_time; struct Process *tmr_real_task; + + /* Used by aio functions */ + struct SignalSemaphore *__aio_lock; + CList *aio_threads; }; extern struct _clib2 *__global_clib2; diff --git a/library/include/endian.h b/library/include/endian.h index 6f8ac716..562aae1a 100644 --- a/library/include/endian.h +++ b/library/include/endian.h @@ -86,7 +86,7 @@ __bswap_32 (unsigned int __bsx) #define __BYTE_ORDER__ BYTE_ORDER #endif -#ifndef __BYTE_ORDER__ +#ifndef __BYTE_ORDER #define __BYTE_ORDER BYTE_ORDER #endif diff --git a/library/include/fcntl.h b/library/include/fcntl.h index 15503f18..180a19f1 100755 --- a/library/include/fcntl.h +++ b/library/include/fcntl.h @@ -21,11 +21,12 @@ __BEGIN_DECLS #define O_TRUNC (1<<5) #define O_NONBLOCK (1<<6) #define O_NDELAY O_NONBLOCK -#define O_SYNC (0) #define O_NOCTTY (0) #define O_ASYNC (1<<7) #define O_PATH (1<<8) #define O_DIRECTORY (1<<9) +#define O_DSYNC (1<<10) +#define O_SYNC (1<<11) #define O_CLOEXEC (0) #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) diff --git a/library/include/pthread.h b/library/include/pthread.h index e2b5faa4..926793b7 100644 --- a/library/include/pthread.h +++ b/library/include/pthread.h @@ -103,6 +103,7 @@ struct pthread_attr { struct sched_param param; int inheritsched; int contentionscope; + size_t guardsize; }; typedef struct pthread_attr pthread_attr_t; @@ -251,6 +252,8 @@ int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched); int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope); int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope); +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); +int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize); // // Thread functions // diff --git a/library/include/setjmp.h b/library/include/setjmp.h index 7a2e815d..eab23b8e 100755 --- a/library/include/setjmp.h +++ b/library/include/setjmp.h @@ -1,27 +1,69 @@ /* - * $Id: setjmp.h,v 1.5 2006-01-08 12:06:14 clib2devs Exp $ + * $Id: setjmp.h,v 1.5 2006-01-08 12:0__sigset_t6:14 clib2devs Exp $ */ #ifndef _SETJMP_H #define _SETJMP_H #include +#include __BEGIN_DECLS -struct __jmp_buf -{ - void * jb_ReturnAddress; - unsigned long jb_CondCode; - void * jb_StackPointer; - unsigned long jb_GPR[19]; - double jb_FPR[18]; +typedef unsigned long long __jmp_buf[58]; + +/* Calling environment, plus possibly a saved signal mask. */ +struct __jmp_buf_tag { + /* NOTE: The machine-dependent definitions of `__sigsetjmp' + assume that a `jmp_buf' begins with a `__jmp_buf' and that + `__mask_was_saved' follows it. Do not move these members + or add others before it. */ + __jmp_buf __jmpbuf; /* Calling environment. */ + int __mask_was_saved; /* Saved the signal mask? */ + sigset_t __saved_mask; /* Saved signal mask. */ }; -typedef struct __jmp_buf jmp_buf[1]; +typedef struct __jmp_buf_tag jmp_buf[1]; + +/* Store the calling environment in ENV, also saving the signal mask. Return 0. */ +extern int setjmp(jmp_buf __env); + +/* Store the calling environment in ENV, also saving the + signal mask if SAVEMASK is nonzero. Return 0. + This is the internal name for `sigsetjmp'. */ +extern int __sigsetjmp(struct __jmp_buf_tag __env[1], int __savemask); + +/* Store the calling environment in ENV, not saving the signal mask. Return 0. */ +extern int _setjmp(struct __jmp_buf_tag __env[1]); + +/* Jump to the environment saved in ENV, making the `setjmp' call there return VAL, or 1 if VAL is 0. */ +extern void longjmp(jmp_buf __env, int __val) __attribute__ ((__noreturn__)); + +#if defined __USE_MISC || defined __USE_XOPEN +/* Same. Usually `_longjmp' is used with `_setjmp', which does not save + the signal mask. But it is how ENV was saved that determines whether + `longjmp' restores the mask; `_longjmp' is just an alias. */ +extern void _longjmp(struct __jmp_buf_tag __env[1], int __val) __attribute__ ((__noreturn__)); +#endif + +#ifdef __USE_POSIX +/* Use the same type for `jmp_buf' and `sigjmp_buf'. + The `__mask_was_saved' flag determines whether + or not `longjmp' will restore the signal mask. */ +typedef struct __jmp_buf_tag sigjmp_buf[1]; + +/* Store the calling environment in ENV, also saving the + signal mask if SAVEMASK is nonzero. Return 0. */ +# define sigsetjmp(env, savemask) __sigsetjmp (env, savemask) + +/* Jump to the environment saved in ENV, making the + sigsetjmp call there return VAL, or 1 if VAL is 0. + Restore the signal mask if that sigsetjmp call saved it. + This is just an alias `longjmp'. */ +extern void siglongjmp (sigjmp_buf __env, int __val) __attribute__ ((__noreturn__)); +#endif /* Use POSIX. */ -extern int setjmp(jmp_buf env); -extern void longjmp(jmp_buf env,int status); +extern int __sigjmp_save (jmp_buf __env, int __savemask); __END_DECLS diff --git a/library/include/signal.h b/library/include/signal.h index 09f77180..f7c39ad7 100755 --- a/library/include/signal.h +++ b/library/include/signal.h @@ -6,6 +6,7 @@ #define _SIGNAL_H #include +#include __BEGIN_DECLS @@ -77,6 +78,8 @@ typedef int sigset_t; #define SIG_UNBLOCK 1 #define SIG_SETMASK 2 +#define SI_ASYNCIO (-4) + extern int sigmask(int signum); extern int sigblock(int signal_mask); extern int sigsetmask(int signal_mask); @@ -99,6 +102,7 @@ typedef struct { #define SA_RESETHAND 1 #define SA_NODEFER 2 #define SA_RESTART 4 +#define SA_SIGINFO 8 #define sa_handler _sa_func._sa_handler #define sa_sigaction _sa_func._sa_sigaction @@ -139,6 +143,37 @@ struct sigaction { extern int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); +typedef union sigval sigval_t; + + +struct sigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + union { + char __pad[64 - 2*sizeof(int) - sizeof(union sigval)]; + pid_t sigev_notify_thread_id; + struct { + void (*sigev_notify_function)(union sigval); + pthread_attr_t *sigev_notify_attributes; + } __sev_thread; + } __sev_fields; +}; + +#define sigev_notify_thread_id __sev_fields.sigev_notify_thread_id +#define sigev_notify_function __sev_fields.__sev_thread.sigev_notify_function +#define sigev_notify_attributes __sev_fields.__sev_thread.sigev_notify_attributes + +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define MINSIGSTKSZ 4096 +#define SIGSTKSZ 10240 +#endif + __END_DECLS #endif /* _SIGNAL_H */ diff --git a/library/include/sys/clib2_io.h b/library/include/sys/clib2_io.h index 7ed6e5b1..9d5f1099 100755 --- a/library/include/sys/clib2_io.h +++ b/library/include/sys/clib2_io.h @@ -43,6 +43,7 @@ struct file_action_message struct MsgPort * fam_FileSystem; /* File system pointer to be filled in */ int fam_Error; /* Error code, if any... */ + int fam_DOSMode; /* Canonical or Raw mode */ }; /****************************************************************************/ diff --git a/library/include/sys/param.h b/library/include/sys/param.h index 330986bd..02e1f8ba 100755 --- a/library/include/sys/param.h +++ b/library/include/sys/param.h @@ -49,6 +49,26 @@ __BEGIN_DECLS +/* Bit map related macros. */ +#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) + +/* Macros for counting and rounding. */ +#ifndef howmany +# define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif +#ifdef __GNUC__ +# define roundup(x, y) (__builtin_constant_p (y) && powerof2 (y) \ + ? (((x) + (y) - 1) & ~((y) - 1)) \ + : ((((x) + ((y) - 1)) / (y)) * (y))) +#else +# define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#endif +#define powerof2(x) ((((x) - 1) & (x)) == 0) + +/* Macros for min/max. */ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) diff --git a/library/include/sys/time.h b/library/include/sys/time.h index f397d53a..4ea617ae 100755 --- a/library/include/sys/time.h +++ b/library/include/sys/time.h @@ -2,9 +2,13 @@ #define _SYS_TIME_H #include +#include __BEGIN_DECLS +typedef int64_t time64_t; +typedef int64_t suseconds64_t; + #if defined(__TIMEVAL_ALREADY_DEFINED) #ifdef __USE_OLD_TIMEVAL__ #define tv_sec tv_secs @@ -23,6 +27,11 @@ struct timeval { #endif /* __USE_OLD_TIMEVAL__ */ #endif /* !__TIMEVAL_ALREADY_DEFINED */ +struct timeval64 { + time64_t tv_sec; /* Seconds */ + suseconds64_t tv_usec; /* Microseconds */ +}; + struct timezone { int tz_minuteswest; /* of Greenwich */ int tz_dsttime; /* type of dst correction to apply */ diff --git a/library/include/sys/timeb.h b/library/include/sys/timeb.h index 98fff0cf..aa5837f3 100755 --- a/library/include/sys/timeb.h +++ b/library/include/sys/timeb.h @@ -1,13 +1,11 @@ /* - * $Id: timeb.h,v 1.3 2006-07-28 14:02:32 clib2devs Exp $ + * $Id: timeb.h,v 1.4 2006-07-28 14:02:32 clib2devs Exp $ */ #ifndef _SYS_TIMEB_H #define _SYS_TIMEB_H -#ifndef _TIME_H #include /* For the definition of time_t */ -#endif /* _TIME_H */ #include diff --git a/library/include/sys/types.h b/library/include/sys/types.h index 1090d782..0694b236 100755 --- a/library/include/sys/types.h +++ b/library/include/sys/types.h @@ -25,7 +25,7 @@ typedef uint64_t fsblkcnt_t; typedef uint64_t fsfilcnt_t; #ifdef __USE_LARGEFILE64 typedef int64_t _off64_t; - typedef _off64_t off64_t; + typedef int64_t off64_t; typedef int64_t _fpos64_t; typedef uint64_t ino64_t; typedef int64_t blkcnt64_t; diff --git a/library/include/time.h b/library/include/time.h index d53c831d..a3f2de5f 100755 --- a/library/include/time.h +++ b/library/include/time.h @@ -12,6 +12,9 @@ #endif /* _STDDEF_H */ #include +#include +#include +#include __BEGIN_DECLS @@ -44,17 +47,16 @@ typedef _CLOCKID_T_ clockid_t; typedef unsigned long clock_t; typedef long long time_t; -struct tm -{ - int tm_sec; /* Number of seconds past the minute (0..59) */ - int tm_min; /* Number of minutes past the hour (0..59) */ - int tm_hour; /* Number of hours past the day (0..23) */ - int tm_mday; /* Day of the month (1..31) */ - int tm_mon; /* Month number (0..11) */ - int tm_year; /* Year number minus 1900 */ - int tm_wday; /* Day of the week (0..6; 0 is Sunday) */ - int tm_yday; /* Day of the year (0..365) */ - int tm_isdst; /* Is this date using daylight savings time? */ +struct tm { + int tm_sec; /* Number of seconds past the minute (0..59) */ + int tm_min; /* Number of minutes past the hour (0..59) */ + int tm_hour; /* Number of hours past the day (0..23) */ + int tm_mday; /* Day of the month (1..31) */ + int tm_mon; /* Month number (0..11) */ + int tm_year; /* Year number minus 1900 */ + int tm_wday; /* Day of the week (0..6; 0 is Sunday) */ + int tm_yday; /* Day of the year (0..365) */ + int tm_isdst; /* Is this date using daylight savings time? */ }; extern clock_t clock(void); @@ -69,16 +71,21 @@ extern size_t strftime(char *s, size_t maxsize, const char *format, const struct extern char *strptime(const char *buf, const char *fmt, struct tm *timeptr); /* Timespec declaration */ -struct timespec -{ - time_t tv_sec; - long tv_nsec; +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +struct timespec64 { + time64_t tv_sec; /* Seconds */ + int32_t : 32; /* Padding */ + int32_t tv_nsec; /* Nanoseconds */ }; /* BSD time macros used by RTEMS code */ /* Convenience macros for operations on timevals. NOTE: `timercmp' does not work for >= or <=. */ -#ifdef __USE_OLD_TIMEVAL__ +#ifndef __USE_OLD_TIMEVAL__ #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) #define timercmp(a, b, CMP) \ @@ -142,19 +149,115 @@ extern struct tm *gmtime_r(const time_t *t, struct tm *tm_ptr); extern struct tm *localtime_r(const time_t *t, struct tm *tm_ptr); extern void tzset(void); extern int nanosleep(const struct timespec *req, struct timespec *rem); - extern int clock_gettime(clockid_t clk_id, struct timespec *t); extern int clock_settime(clockid_t clk_id, const struct timespec *t); extern int clock_getres(clockid_t clock_id, struct timespec *res); extern int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); +extern unsigned long long rdtsc(void); -extern uint64_t rdtsc(void); +extern int clock_gettime64 (clockid_t clock_id, struct timespec64 *tp); /* Defined in localtime.c. */ extern char *tzname[2]; /* Current timezone names. */ extern int daylight; /* If daylight-saving time is ever in use. */ extern long int timezone; /* Seconds west of UTC. */ +/* Check whether T fits in time_t. */ +static inline bool +in_time_t_range (time64_t t) { + time_t s = t; + return s == t; +} + +/* Convert a known valid struct timeval into a struct timespec64. */ +static inline struct timespec64 +valid_timeval_to_timespec64 (const struct timeval tv) { + struct timespec64 ts64; + + ts64.tv_sec = tv.tv_sec; + ts64.tv_nsec = tv.tv_usec * 1000; + + return ts64; +} + +/* Convert a known valid struct timeval into a struct timeval64. */ +static inline struct timeval64 +valid_timeval_to_timeval64(const struct timeval tv) { + struct timeval64 tv64; + + tv64.tv_sec = tv.tv_sec; + tv64.tv_usec = tv.tv_usec; + + return tv64; +} + + +/* Convert a valid and within range of struct timeval, struct timeval64 into a struct timeval. */ +static inline struct timeval +valid_timeval64_to_timeval (const struct timeval64 tv64) { + struct timeval tv; + + tv.tv_sec = (long) tv64.tv_sec; + tv.tv_usec = (long) tv64.tv_usec; + + return tv; +} + +/* Convert a struct timeval64 into a struct timespec64. */ +static inline struct timespec64 +timeval64_to_timespec64 (const struct timeval64 tv64) { + struct timespec64 ts64; + + ts64.tv_sec = tv64.tv_sec; + ts64.tv_nsec = tv64.tv_usec * 1000; + + return ts64; +} + +/* Convert a known valid struct timespec into a struct timespec64. */ +static inline struct timespec64 +valid_timespec_to_timespec64 (const struct timespec ts) { + struct timespec64 ts64; + + ts64.tv_sec = ts.tv_sec; + ts64.tv_nsec = ts.tv_nsec; + + return ts64; +} + +/* Convert a valid and within range of struct timespec, struct timespec64 into a struct timespec. */ +static inline struct timespec +valid_timespec64_to_timespec (const struct timespec64 ts64) { + struct timespec ts; + + ts.tv_sec = (time_t) ts64.tv_sec; + ts.tv_nsec = ts64.tv_nsec; + + return ts; +} + +/* Convert a valid and within range of struct timeval struct timespec64 into a struct timeval. */ +static inline struct timeval +valid_timespec64_to_timeval (const struct timespec64 ts64) { + struct timeval tv; + + tv.tv_sec = (time_t) ts64.tv_sec; + tv.tv_usec = ts64.tv_nsec / 1000; + + return tv; +} + +/* Convert a struct timespec64 into a struct timeval64. */ +static inline struct timeval64 +timespec64_to_timeval64 (const struct timespec64 ts64) { + struct timeval64 tv64; + + tv64.tv_sec = ts64.tv_sec; + tv64.tv_usec = ts64.tv_nsec / 1000; + + return tv64; +} + __END_DECLS #endif /* _TIME_H */ diff --git a/library/include/unistd.h b/library/include/unistd.h index ececfbf2..305880a4 100755 --- a/library/include/unistd.h +++ b/library/include/unistd.h @@ -164,7 +164,6 @@ extern int setuid(uid_t uid); /* Amiga Specific */ #define _PC_DOSTYPE 300 -#define _POSIX_THREADS 1 #define _POSIX_MONOTONIC_CLOCK 1 /* The following is for use with sysconf(). Only the implemented one */ @@ -188,6 +187,24 @@ extern int pipe2 (int fd[2], int flags); extern ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset); extern ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset); +#ifdef __USE_LARGEFILE64 +extern ssize_t pread64(int fd, void *buf, size_t nbytes, off64_t offset); +extern ssize_t pwrite64(int fd, const void *buf, size_t nbytes, off64_t offset); +#endif + +#ifdef __USE_GNU +/* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno' set to EINTR. */ + +# define TEMP_FAILURE_RETRY(exp) \ + ({ \ + long int __result = 0; \ + do { \ + __result = (long int)(exp); \ + } while ((__result == -1) && (errno == EINTR)); \ + __result; \ + }) +#endif + #define _P_WAIT 1 #define _P_NOWAIT 2 #define _P_OVERLAY 3 diff --git a/library/libc_init_global.c b/library/libc_init_global.c index 757e9a4f..9d2ee67f 100755 --- a/library/libc_init_global.c +++ b/library/libc_init_global.c @@ -29,6 +29,8 @@ #include #include +#include "aio/aio_misc.h" + static APTR hook_function(struct Hook *hook, APTR userdata, struct Process *process) { uint32 pid = (uint32) userdata; @@ -50,7 +52,8 @@ static uint32_t _random_init[] = { 0x8ae16fd9, 0x742d2f7a, 0x0d1f0796, 0x76035e09, 0x40f7702c, 0x6fa72ca5, 0xaaa84157, 0x58a0df74, 0xc74a0364, 0xae533cc4, 0x04185faf, 0x6de3b115, - 0x0cab8628, 0xf043bfa4, 0x398150e9, 0x37521657}; + 0x0cab8628, 0xf043bfa4, 0x398150e9, 0x37521657 +}; /* These are used to initialize the shared objects linked to this binary, and for the dlopen(), dlclose() and dlsym() functions. */ @@ -66,13 +69,15 @@ reent_init() { ENTER(); /* Initialize global structure */ - __global_clib2 = (struct _clib2 *) AllocVecTags(sizeof(struct _clib2), AVT_Type, MEMF_SHARED, AVT_ClearWithValue, 0, - TAG_END); + __global_clib2 = (struct _clib2 *) AllocVecTags(sizeof(struct _clib2), AVT_Type, MEMF_SHARED, AVT_ClearWithValue, 0, TAG_END); if (__global_clib2 == NULL) { goto out; } else { struct ElfIFace *IElf = __IElf; + /* Get the current task pointer */ + __global_clib2->self = (struct Process *) FindTask(NULL); + /* Initialize wchar stuff */ __global_clib2->wide_status = AllocVecTags(sizeof(struct _wchar), AVT_Type, MEMF_SHARED, TAG_DONE); if (!__global_clib2->wide_status) { @@ -128,9 +133,6 @@ reent_init() { __global_clib2->_current_locale = "C-UTF-8"; __global_clib2->__mb_cur_max = 1; - /* Get the current task pointer */ - __global_clib2->self = (struct Process *) FindTask(0); - /* Init memalign list */ __global_clib2->__memalign_pool = AllocSysObjectTags(ASOT_ITEMPOOL, ASO_NoTrack, FALSE, @@ -165,6 +167,9 @@ reent_init() { __global_clib2->tmr_start_time.tv_usec = 0; __global_clib2->tmr_real_task = NULL; + /* Initialize aio pthread list */ + __global_clib2->__aio_lock = __create_semaphore(); + /* Check if .unix file exists in the current dir. If the file exists enable * unix path semantics */ @@ -192,18 +197,23 @@ reent_init() { * call_main() */ + SHOWMSG("Try to get elf handle for dl* operations"); if (__ElfBase != NULL) { - BPTR segment_list = GetProcSegList(NULL, GPSLF_CLI | GPSLF_SEG); + SHOWMSG("Calling GetProcSegList"); + BPTR segment_list = GetProcSegList(NULL, GPSLF_RUN | GPSLF_SEG); if (segment_list != ZERO) { Elf32_Handle handle = NULL; + SHOWMSG("Calling GetSegListInfoTags"); if (GetSegListInfoTags(segment_list, GSLI_ElfHandle, &handle, TAG_DONE) == 1) { if (handle != NULL) { - __global_clib2->__dl_elf_handle = OpenElfTags(OET_ElfHandle, handle, TAG_DONE); + SHOWMSG("Calling OpenElfTags"); + __global_clib2->__dl_elf_handle = OpenElfTags(OET_ElfHandle, handle, OET_ReadOnlyCopy, TRUE, TAG_DONE); } } } } + SHOWPOINTER(__global_clib2->__dl_elf_handle); } success = TRUE; @@ -221,32 +231,6 @@ reent_init() { __global_clib2->__memalign_pool = NULL; } - /* Remove timer tasks */ - if (__global_clib2->tmr_real_task != NULL) { - struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; - int32 pid, process; - - /* Block SIGALRM signal from raise */ - sigblock(SIGALRM); - /* Get itimer process ID */ - pid = __global_clib2->tmr_real_task->pr_ProcessID; - - Forbid(); - /* Scan for process */ - process = ProcessScan(&h, (CONST_APTR) pid, 0); - /* If we find the process send a signal to kill it */ - while (process > 0) { - /* Send a SIGBREAKF_CTRL_F signal until the timer task return to Wait state - * and can get the signal */ - Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); - process = ProcessScan(&h, (CONST_APTR) pid, 0); - usleep(100); - } - Permit(); - WaitForChildExit(pid); - __global_clib2->tmr_real_task = NULL; - } - /* Free library */ if (__global_clib2) { FreeVec(__global_clib2); @@ -275,7 +259,7 @@ reent_exit() { /* Check if we have something created with posix_memalign and not freed yet. * But this is a good point also to free something allocated with memalign or * aligned_alloc and all other functions are using memalign_tree to allocate memory - * This seems to cure also the memory leaks found sometimes (but not 100& sure..) + * This seems to cure also the memory leaks found sometimes (but not 100% sure..) */ struct MemalignEntry *e = (struct MemalignEntry *) AVL_FindFirstNode(__global_clib2->__memalign_tree); while (e) { @@ -295,6 +279,17 @@ reent_exit() { FreeSysObject(ASOT_ITEMPOOL, __global_clib2->__memalign_pool); } + /* Free wchar stuff */ + if (__global_clib2->wide_status != NULL) { + FreeVec(__global_clib2->wide_status); + __global_clib2->wide_status = NULL; + } + /* Remove random semaphore */ + __delete_semaphore(__global_clib2->__random_lock); + + /* Remove aio semaphore. */ + __delete_semaphore(__global_clib2->__aio_lock); + if (__ISysVIPC != NULL) { DropInterface((struct Interface *) __ISysVIPC); __ISysVIPC = NULL; @@ -305,20 +300,15 @@ reent_exit() { __SysVBase = NULL; } - /* Free wchar stuff */ - if (__global_clib2->wide_status != NULL) { - FreeVec(__global_clib2->wide_status); - __global_clib2->wide_status = NULL; - } - /* Remove random semaphore */ - __delete_semaphore(__global_clib2->__random_lock); - /* Free dl stuff */ if (__IElf != NULL && __global_clib2->__dl_elf_handle != NULL) { + SHOWMSG("Closing elf handle"); CloseElfTags(__global_clib2->__dl_elf_handle, CET_ReClose, TRUE, TAG_DONE); __global_clib2->__dl_elf_handle = NULL; } - + else { + SHOWMSG("Cannot close elf handle: __IElf == NULL || __global_clib2->__dl_elf_handle == NULL"); + } FreeVec(__global_clib2); __global_clib2 = NULL; } diff --git a/library/locale/init_exit.c b/library/locale/init_exit.c index 7f62d077..9aa6da43 100644 --- a/library/locale/init_exit.c +++ b/library/locale/init_exit.c @@ -23,24 +23,19 @@ struct Locale *NOCOMMON __locale_table[NUM_LOCALES]; char NOCOMMON __locale_name_table[NUM_LOCALES][MAX_LOCALE_NAME_LEN]; - -void __close_all_locales(void) -{ +void __close_all_locales(void) { __locale_lock(); - if (__LocaleBase != NULL) - { + if (__LocaleBase != NULL) { DECLARE_LOCALEBASE(); int i; - for (i = 0; i < NUM_LOCALES; i++) - { + for (i = 0; i < NUM_LOCALES; i++) { if (i == LC_ALL) continue; - if (__locale_table[i] != NULL) - { + if (__locale_table[i] != NULL) { if (__locale_table[i] != __locale_table[LC_ALL]) CloseLocale(__locale_table[i]); @@ -55,25 +50,21 @@ void __close_all_locales(void) __locale_unlock(); } -void __locale_exit(void) -{ +void __locale_exit(void) { ENTER(); __locale_lock(); - if (__LocaleBase != NULL) - { + if (__LocaleBase != NULL) { DECLARE_LOCALEBASE(); __close_all_locales(); - if (__default_locale != NULL) - { + if (__default_locale != NULL) { CloseLocale(__default_locale); __default_locale = NULL; } - if (__ILocale != NULL) - { + if (__ILocale != NULL) { DropInterface((struct Interface *)__ILocale); __ILocale = NULL; } diff --git a/library/math/asinl.c b/library/math/asinl.c index 76239018..6697bb55 100644 --- a/library/math/asinl.c +++ b/library/math/asinl.c @@ -20,15 +20,20 @@ #include "math_headers.h" #endif /* _MATH_HEADERS_H */ +#ifndef _STDLIB_HEADERS_H +#include "stdlib_headers.h" +#endif /* _STDLIB_HEADERS_H */ + #include "invtrig.h" static const long double one = 1.00000000000000000000e+00, huge = 1.000e+300; -INLINE STATIC long double +inline static long double __asinl(long double x) { union IEEEl2bits u; + memset(&u, 0, sizeof(u)); long double t = 0.0, w, p, q, c, r, s; int16_t expsign, expt; u.e = x; diff --git a/library/math/ledf2.c b/library/math/ledf2.c deleted file mode 100644 index c91784ab..00000000 --- a/library/math/ledf2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_ledf2.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___ledf2 - -___ledf2: - - moveml d2/d3/a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(16),d0/d1/d2/d3 - jsr a6@(-42:W) - moveml sp@+,d2/d3/a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/lesf2.c b/library/math/lesf2.c deleted file mode 100644 index fea22713..00000000 --- a/library/math/lesf2.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_lesf2.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__lesf2(float x,float y) -{ - float result; - - result = IEEESPCmp(x,y); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/ltdf2.c b/library/math/ltdf2.c deleted file mode 100644 index 78a00f8b..00000000 --- a/library/math/ltdf2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_ltdf2.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___ltdf2 - -___ltdf2: - - moveml d2/d3/a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(16),d0/d1/d2/d3 - jsr a6@(-42:W) - moveml sp@+,d2/d3/a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/ltsf2.c b/library/math/ltsf2.c deleted file mode 100644 index 3df08e35..00000000 --- a/library/math/ltsf2.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_ltsf2.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__ltsf2(float x,float y) -{ - float result; - - result = IEEESPCmp(x,y); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/muldf3.c b/library/math/muldf3.c deleted file mode 100644 index 8b41c701..00000000 --- a/library/math/muldf3.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_muldf3.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___muldf3 - -___muldf3: - - moveml d2/d3/a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(16),d0/d1/d2/d3 - jsr a6@(-78:W) - moveml sp@+,d2/d3/a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/mulsf3.c b/library/math/mulsf3.c deleted file mode 100644 index a3407239..00000000 --- a/library/math/mulsf3.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_mulsf3.c,v 1.3 2006-01-08 12:04:23 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__mulsf3(float x,float y) -{ - float result; - - result = IEEESPMul(x,y); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/nedf2.c b/library/math/nedf2.c deleted file mode 100644 index b39df0e1..00000000 --- a/library/math/nedf2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_nedf2.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___nedf2 - -___nedf2: - - moveml d2/d3/a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(16),d0/d1/d2/d3 - jsr a6@(-42:W) - moveml sp@+,d2/d3/a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/negdf2.c b/library/math/negdf2.c deleted file mode 100644 index 3b595158..00000000 --- a/library/math/negdf2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_negdf2.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___negdf2 - -___negdf2: - - movel a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(8),d0/d1 - jsr a6@(-60:W) - movel sp@+,a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/negsf2.c b/library/math/negsf2.c deleted file mode 100644 index 1f01be5c..00000000 --- a/library/math/negsf2.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_negsf2.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__negsf2(float x) -{ - float result; - - result = IEEESPNeg(x); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/nesf2.c b/library/math/nesf2.c deleted file mode 100644 index f8e377a6..00000000 --- a/library/math/nesf2.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_nesf2.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__nesf2(float x,float y) -{ - float result; - - result = IEEESPCmp(x,y); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/subdf3.c b/library/math/subdf3.c deleted file mode 100644 index 0223235a..00000000 --- a/library/math/subdf3.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_subdf3.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubBasBase - .globl ___subdf3 - -___subdf3: - - moveml d2/d3/a6,sp@- - movel "A4(_MathIeeeDoubBasBase)",a6 - moveml sp@(16),d0/d1/d2/d3 - jsr a6@(-72:W) - moveml sp@+,d2/d3/a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/subsf3.c b/library/math/subsf3.c deleted file mode 100644 index ab22d418..00000000 --- a/library/math/subsf3.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * $Id: math_subsf3.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -float -__subsf3(float x,float y) -{ - float result; - - result = IEEESPSub(x,y); - - return(result); -} - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/math/truncdfsf2.c b/library/math/truncdfsf2.c deleted file mode 100644 index b3745d9c..00000000 --- a/library/math/truncdfsf2.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * $Id: math_truncdfsf2.c,v 1.3 2006-01-08 12:04:24 clib2devs Exp $ -*/ - -#ifndef _MATH_HEADERS_H -#include "math_headers.h" -#endif /* _MATH_HEADERS_H */ - -/****************************************************************************/ - -#if defined(IEEE_FLOATING_POINT_SUPPORT) && defined(__GNUC__) - -/****************************************************************************/ - -#if defined(SMALL_DATA) -#define A4(x) "a4@(" #x ":W)" -#elif defined(SMALL_DATA32) -#define A4(x) "a4@(" #x ":L)" -#else -#define A4(x) #x -#endif /* SMALL_DATA */ - -/****************************************************************************/ - -asm(" - - .text - .even - - .globl _MathIeeeDoubTransBase - .globl ___truncdfsf2 - -___truncdfsf2: - - movel a6,sp@- - movel "A4(_MathIeeeDoubTransBase)",a6 - moveml sp@(8),d0/d1 - jsr a6@(-102:W) - movel sp@+,a6 - rts - -"); - -/****************************************************************************/ - -#endif /* IEEE_FLOATING_POINT_SUPPORT */ diff --git a/library/misc/clist.c b/library/misc/clist.c new file mode 100644 index 00000000..d9b40a93 --- /dev/null +++ b/library/misc/clist.c @@ -0,0 +1,369 @@ +/* + * $Id: misc_clist.c,v 1.0 2023-03-03 14:15:37 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#ifndef _STDLIB_HEADERS_H +#include "stdlib_headers.h" +#endif /* _STDLIB_HEADERS_H */ + +#include "clist.h" + +typedef struct { + int count; /* Number of items in the list. */ + int alloc_size; /* Allocated size in quantity of items */ + int lastSearchPos; /* Position of last search - firstMatch or LastMatch */ + size_t item_size; /* Size of each item in bytes. */ + void *items; /* Pointer to the list */ +} cListPriv; + +int cListRealloc(CList *l, int n) { + cListPriv *p = (cListPriv *) l->priv; + if (n < p->count) { + D(("CList: ERROR! Can not realloc to '%i' size - count is '%i'\n", n, p->count)); + assert(n >= p->count); + return 0; + } + + if (n == 0 && p->alloc_size == 0) + n = 2; + + void *ptr = realloc(p->items, p->item_size * n); + if (ptr == NULL) { + D(("CList: ERROR! Can not reallocate memory!\n")); + return 0; + } + p->items = ptr; + p->alloc_size = n; + return 1; +} + +void *cListAdd(CList *l, void *o) { + cListPriv *p = (cListPriv *) l->priv; + if (p->count == p->alloc_size && + cListRealloc(l, p->alloc_size * 2) == 0) + return NULL; + + char *data = (char *) p->items; + data = data + p->count * p->item_size; + memcpy(data, o, p->item_size); + p->count++; + return data; +} + +void *cListInsert(CList *l, void *o, int n) { + cListPriv *p = (cListPriv *) l->priv; + if (n < 0 || n > p->count) { + D(("CList: ERROR! Insert position outside range - %d; n - %d.\n", p->count, n)); + assert(n >= 0 && n <= p->count); + return NULL; + } + + if (p->count == p->alloc_size && + cListRealloc(l, p->alloc_size * 2) == 0) + return NULL; + + size_t step = p->item_size; + char *data = (char *) p->items + n * step; + memmove(data + step, data, (p->count - n) * step); + memcpy(data, o, step); + p->count++; + return data; +} + +void *cListReplace(CList *l, void *o, int n) { + cListPriv *p = (cListPriv *) l->priv; + if (n < 0 || n >= p->count) { + D(("CList: ERROR! Replace position outside range - %d; n - %d.\n", p->count, n)); + assert(n >= 0 && n < p->count); + return NULL; + } + + char *data = (char *) p->items; + data = data + n * p->item_size; + memcpy(data, o, p->item_size); + return data; +} + +void cListRemove(CList *l, int n) { + cListPriv *p = (cListPriv *) l->priv; + if (n < 0 || n >= p->count) { + D(("CList: ERROR! Remove position outside range - %d; n - %d.\n", p->count, n)); + assert(n >= 0 && n < p->count); + return; + } + + size_t step = p->item_size; + char *data = (char *) p->items + n * step; + memmove(data, data + step, (p->count - n - 1) * step); + p->count--; + + if (p->alloc_size > 3 * p->count && p->alloc_size >= 4) /* Dont hold much memory */ + cListRealloc(l, p->alloc_size / 2); +} + +void *cListAt(CList *l, int n) { + cListPriv *p = (cListPriv *) l->priv; + if (n < 0 || n >= p->count) { + D(("CList: ERROR! Get position outside range - %d; n - %d.\n", p->count, n)); + assert(n >= 0 && n < p->count); + return NULL; + } + + char *data = (char *) p->items; + data = data + n * p->item_size; + return data; +} + +void *cListFirstMatch(CList *l, const void *o, size_t shift, size_t size, int string) { + cListPriv *p = (cListPriv *) l->priv; + char *data = (char *) p->items; + size_t step = p->item_size; + p->lastSearchPos = -1; + + if (shift + size > p->item_size) { + D(("CList: ERROR! Wrong ranges for firstMatch - shift '%zu', size '%zu', item_size '%zu'\n", shift, size, p->item_size)); + assert(shift + size <= p->item_size); + return NULL; + } + + if (shift == 0 && size == 0) + size = p->item_size; + + size_t i = shift; + size_t end = p->count * step; + int index = 0; + + if (string) { + for (; i < end; i += step, index++) { + if (strncmp(data + i, o, size) == 0) { + p->lastSearchPos = index; + return (data + i - shift); + } + } + } else { + for (; i < end; i += step, index++) { + if (memcmp(data + i, o, size) == 0) { + p->lastSearchPos = index; + return (data + i - shift); + } + } + } + + return NULL; +} + +void *cListLastMatch(struct CList *l, const void *o, size_t shift, size_t size, int string) { + cListPriv *p = (cListPriv *) l->priv; + char *data = (char *) p->items; + size_t step = p->item_size; + p->lastSearchPos = -1; + + if (shift + size > p->item_size) { + D(("CList: ERROR! Wrong ranges for lastMatch - shift '%zu', size '%zu', item_size '%zu'\n", shift, size, p->item_size)); + assert(shift + size <= p->item_size); + return NULL; + } + + if (shift == 0 && size == 0) + size = p->item_size; + + int index = p->count - 1; + long i = index * step + shift; + if (string) { + for (; i >= 0; i -= step, index--) { + if (strncmp(data + i, o, size) == 0) { + p->lastSearchPos = index; + return (data + i - shift); + } + } + } else { + for (; i >= 0; i -= step, index--) { + if (memcmp(data + i, o, size) == 0) { + p->lastSearchPos = index; + return (data + i - shift); + } + } + } + + return NULL; +} + +int cListIndex(CList *l) { + cListPriv *p = (cListPriv *) l->priv; + return p->lastSearchPos; +} + +int cListSwap(CList *l, int a, int b) { + cListPriv *p = (cListPriv *) l->priv; + + if (a < 0 || a >= p->count || b < 0 || b >= p->count) { + D(("CList: ERROR! Swap position outside range - %i, %i; count - %d.\n", a, b, p->count)); + assert(a >= 0 && a < p->count && b >= 0 && b < p->count); + return 0; + } + + if (a == b) return 1; /* ? Good ? :D */ + + char *data = (char *) p->items; + size_t step = p->item_size; + + if (p->count == p->alloc_size && + cListRealloc(l, p->alloc_size + 1) == 0) + return 0; + + memcpy(data + p->count * step, data + a * step, step); + memcpy(data + a * step, data + b * step, step); + memcpy(data + b * step, data + p->count * step, step); + return 1; +} + +int cListCount(CList *l) { + cListPriv *p = (cListPriv *) l->priv; + return p->count; +} + +int cListAllocSize(CList *l) { + cListPriv *p = (cListPriv *) l->priv; + return p->alloc_size; +} + +size_t cListItemSize(CList *l) { + cListPriv *p = (cListPriv *) l->priv; + return p->item_size; +} + +void cListClear(CList *l) { + cListPriv *p = (cListPriv *) l->priv; + free(p->items); + p->items = NULL; + p->alloc_size = 0; + p->count = 0; +} + +void cListFree(CList *l) { + ENTER(); + SHOWPOINTER(l); + + cListPriv *p = (cListPriv *) l->priv; + if (p->items) { + free(p->items); + p->items = NULL; + } + if (p) { + free(p); + p = NULL; + } + + free(l); + l = NULL; + + LEAVE(); +} + +void cListPrint(CList *l, size_t shift, int n, const char *type) { + cListPriv *p = (cListPriv *) l->priv; + + if (shift >= p->item_size) { + D(("CList: ERROR! Wrong shift value for list print - " "shift '%zu', item_size '%zu'\n", shift, p->item_size)); + assert(shift < p->item_size); + return; + } + + printf("\nCList: count = %i item_size = %zu alloc_size = %i type = %s\n", + p->count, p->item_size, p->alloc_size, type); + + if (n > 0) { + int tp = -1; + if (type == NULL) tp = 0; /* Print out pointers */ + else if (strcmp(type, "char") == 0) tp = 1; + else if (strcmp(type, "short") == 0) tp = 2; + else if (strcmp(type, "int") == 0) tp = 3; + else if (strcmp(type, "long") == 0) tp = 4; + else if (strcmp(type, "uintptr_t") == 0) tp = 5; + else if (strcmp(type, "size_t") == 0) tp = 6; + else if (strcmp(type, "double") == 0) tp = 7; + else if (strcmp(type, "string") == 0) tp = 8; + + if (tp == -1) { + D(("CList: Can not print - not supported type - %s\n\n", type)); + return; + } + + n = (n > p->count) ? p->count : n; + char *data = (char *) p->items + shift; + size_t step = p->item_size; + int i = 0; + for (; i < n; i++) { + switch (tp) { + case 0: + printf("%p ", data); + break; + case 1: + printf("%c ", *(char *) data); + break; + case 2: + printf("%hi ", *(short *) data); + break; + case 3: + printf("%i ", *(int *) data); + break; + case 4: + printf("%li ", *(long *) data); + break; + case 5: + printf("0x%lx ", *(uintptr_t *) data); + break; + case 6: + printf("%zu ", *(size_t *) data); + break; + case 7: + printf("%f ", *(double *) data); + break; + case 8: + printf("%s\n", data); + break; + default: + return; + } + + data += step; + } + printf("\n\n"); + } +} + +CList *CList_init(size_t objSize) { + CList *lst = malloc(sizeof(CList)); + cListPriv *p = malloc(sizeof(cListPriv)); + if (!lst || !p) { + D(("CList: ERROR! Can not allocate CList!\n")); + return NULL; + } + p->count = 0; + p->alloc_size = 0; + p->lastSearchPos = -1; + p->item_size = objSize; + p->items = NULL; + lst->add = &cListAdd; + lst->insert = &cListInsert; + lst->replace = &cListReplace; + lst->remove = &cListRemove; + lst->at = &cListAt; + lst->realloc = &cListRealloc; + lst->count = &cListCount; + lst->firstMatch = &cListFirstMatch; + lst->lastMatch = &cListLastMatch; + lst->index = &cListIndex; + lst->swap = &cListSwap; + lst->allocSize = &cListAllocSize; + lst->itemSize = &cListItemSize; + lst->print = &cListPrint; + lst->clear = &cListClear; + lst->free = &cListFree; + lst->priv = p; + return lst; +} diff --git a/library/misc/clist.h b/library/misc/clist.h new file mode 100644 index 00000000..19d12f31 --- /dev/null +++ b/library/misc/clist.h @@ -0,0 +1,54 @@ +/* + * $Id: misc_clist.h,v 1.0 2023-03-03 07:15:37 clib2devs Exp $ +*/ + +#ifndef CLIST_H +#define CLIST_H + +#include + +__BEGIN_DECLS + +typedef struct CList { + void * (* add) (struct CList *l, void *o); /* Add object to the end of a list */ + void * (* insert) (struct CList *l, void *o, int n); /* Insert object at position 'n' */ + void * (* replace) (struct CList *l, void *o, int n); /* Replace object at position 'n' */ + void (* remove) (struct CList *l, int n); /* Remove object at position 'n' */ + void * (* at) (struct CList *l, int n); /* Get object at position 'n' */ + int (* realloc) (struct CList *l, int n); /* Reallocate list to 'size' items */ + int (* count) (struct CList *l); /* Get list size in items */ + void * (* firstMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); + /* Returns object with first match of string or byte compare */ + void * (* lastMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); + /* Returns object with last match of string or byte compare */ + int (* index) (struct CList *l); /* Get index of previos search match */ + int (* swap) (struct CList *l, int a, int b); /* Swap, replace two items with index a b */ + int (* allocSize) (struct CList *l); /* Get allocated size in items */ + size_t (* itemSize) (struct CList *l); /* Get item size in bytes */ + void (* print) (struct CList *l, size_t shift, int n, const char *type); /* Print list data */ + void (* clear) (struct CList *l); /* Clear list */ + void (* free) (struct CList *l); /* Destroy struct CList and all data */ + void *priv; /* NOT FOR USE, private data */ +} CList; + +CList *CList_init(size_t objSize); /* Set list object size in bytes */ +void *cListAdd(CList *l, void *o) __attribute__ ((visibility ("hidden"))); +int cListAllocSize(CList *l) __attribute__ ((visibility ("hidden"))); +void *cListAt(CList *l, int n) __attribute__ ((visibility ("hidden"))); +void cListClear(CList *l) __attribute__ ((visibility ("hidden"))); +int cListCount(CList *l) __attribute__ ((visibility ("hidden"))); +void *cListFirstMatch(CList *l, const void *o, size_t shift, size_t size, int string) __attribute__ ((visibility ("hidden"))); +void cListFree(CList *l) __attribute__ ((visibility ("hidden"))); +int cListIndex(CList *l) __attribute__ ((visibility ("hidden"))); +void *cListInsert(CList *l, void *o, int n) __attribute__ ((visibility ("hidden"))); +size_t cListItemSize(CList *l) __attribute__ ((visibility ("hidden"))); +void *cListLastMatch(struct CList *l, const void *o, size_t shift, size_t size, int string) __attribute__ ((visibility ("hidden"))); +void cListPrint(CList *l, size_t shift, int n, const char *type) __attribute__ ((visibility ("hidden"))); +int cListRealloc(CList *l, int n) __attribute__ ((visibility ("hidden"))); +void cListRemove(CList *l, int n) __attribute__ ((visibility ("hidden"))); +void *cListReplace(CList *l, void *o, int n) __attribute__ ((visibility ("hidden"))); +int cListSwap(CList *l, int a, int b) __attribute__ ((visibility ("hidden"))); + +__END_DECLS + +#endif /* CLIST_H */ \ No newline at end of file diff --git a/library/posix/basename.c b/library/posix/basename.c index d7b5937b..ca8ca0fb 100644 --- a/library/posix/basename.c +++ b/library/posix/basename.c @@ -1,5 +1,5 @@ /* - * $Id: libgen_basename.c,v 1.8 2006-10-02 07:15:37 clib2devs Exp $ + * $Id: posix_basename.c,v 1.8 2006-10-02 07:15:37 clib2devs Exp $ */ #include diff --git a/library/posix/kill.c b/library/posix/kill.c index 0699afa1..84f31a70 100644 --- a/library/posix/kill.c +++ b/library/posix/kill.c @@ -37,8 +37,11 @@ kill(pid_t pid, int signal_number) { if (pid > 0) { if (pid == getpid()) { + SHOWMSG("This is a kill for our process"); result = raise(signal_number); + SHOWVALUE(result); } else { + SHOWMSG("This is a kill for a different process. Search it"); struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; Forbid(); diff --git a/library/posix/raise.c b/library/posix/raise.c index 7c40fce6..5cbffcd9 100644 --- a/library/posix/raise.c +++ b/library/posix/raise.c @@ -10,6 +10,9 @@ #include "stdio_headers.h" #endif /* _STDIO_HEADERS_H */ +#include "aio/aio_misc.h" +#include "pthread/common.h" + static APTR hook_function(struct Hook *hook, APTR userdata, struct Process *process) { uint32 pid = (uint32) userdata; @@ -68,20 +71,25 @@ raise(int sig) { static int local_signals_blocked; int result = ERROR; - ENTER(); SHOWVALUE(sig); - /* This has to be a well-known and supported signal. */ - if (sig < SIGHUP || sig > NSIG) { + /* This has to be a well-known and supported signal. 0 is a valid signal*/ + if (sig < 0 || sig > NSIG) { SHOWMSG("unknown signal number"); __set_errno(EINVAL); goto out; } + /* If sig is 0 just set result to OK and go out */ + if (sig == 0) { + result = OK; + goto out; + } + /* Can we deliver the signal? */ - if (FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) && FLAG_IS_CLEAR(local_signals_blocked, (1 << sig))) { + if ((FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) && FLAG_IS_CLEAR(local_signals_blocked, (1 << sig))) || sig == SIGKILL) { signal_handler_t handler; /* Which handler is installed for this signal? */ @@ -90,14 +98,16 @@ raise(int sig) { /* Should we ignore this signal? */ if (handler != SIG_IGN) { /* Block delivery of this signal to prevent recursion. */ - SET_FLAG(local_signals_blocked, (1 << sig)); + SHOWMSG("Blocking signal if it isn't a kill signal"); + if (sig != SIGINT && sig != SIGTERM && sig != SIGKILL) + SET_FLAG(local_signals_blocked, (1 << sig)); /* The default behaviour is to drop into abort(), or do something very much like it. */ if (handler == SIG_DFL) { SHOWMSG("this is the default handler"); - if (sig == SIGINT || sig == SIGTERM) { + if (sig == SIGINT || sig == SIGTERM || sig == SIGKILL) { /* Check ig we have timer terminal running. If so let's kill it */ if (__global_clib2->tmr_real_task != NULL) { struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; @@ -124,6 +134,23 @@ raise(int sig) { __global_clib2->tmr_real_task = NULL; } + /* Check if we have some aio threads */ + SHOWMSG("Check if we have some aio pthreads created"); + AioThread *aioThread; + SHOWMSG("Obtain aio semaphore"); + ObtainSemaphore(__global_clib2->__aio_lock); + int streams = __global_clib2->aio_threads->count(__global_clib2->aio_threads); + D(("AIO list has %ld items", streams)); + if (streams > 0) { + for (int i = 0; i < streams; i++) { + aioThread = __global_clib2->aio_threads->at(__global_clib2->aio_threads, i); + D(("Cancel AIO stream with filedes %ld", aioThread->fileDes)); + aio_cancel(aioThread->fileDes, aioThread->aiocbp); + Signal(aioThread->thread, SIGBREAKF_CTRL_C); + } + } + ReleaseSemaphore(__global_clib2->__aio_lock); + char break_string[80]; /* Turn off ^C checking for good. */ @@ -159,20 +186,20 @@ raise(int sig) { } else { SHOWMSG("calling the handler"); - (*handler)(sig); - if (sig == SIGINT) + if (sig == SIGINT || sig == SIGTERM || sig == SIGKILL) SetSignal(0, SIGBREAKF_CTRL_C); SHOWMSG("done."); } /* Unblock signal delivery again. */ + SHOWMSG("Unblocking signal"); CLEAR_FLAG(local_signals_blocked, (1 << sig)); } else { - if (sig == SIGINT) { + if (sig == SIGINT || sig == SIGTERM || sig == SIGKILL) { // Reset the signal bit cleared by __check_abort() SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); } diff --git a/library/posix/signal.c b/library/posix/signal.c index 2c33c341..0c871523 100644 --- a/library/posix/signal.c +++ b/library/posix/signal.c @@ -15,13 +15,16 @@ void (*signal(int sig, void (*handler)(int)))(int) { SHOWVALUE(sig); SHOWPOINTER(handler); - if (sig < SIGHUP || sig > NSIG || handler == SIG_ERR) { + if (sig < 0 || sig > NSIG || handler == SIG_ERR) { SHOWMSG("unsupported signal"); __set_errno(EINVAL); goto out; } + if (table_entry < 0) + table_entry = 0; + result = (void (*)(int)) __signal_handler_table[table_entry]; __signal_handler_table[table_entry] = (signal_handler_t) handler; diff --git a/library/profile/_mcount.c b/library/profile/_mcount.c index 379cb71c..01dd3aad 100644 --- a/library/profile/_mcount.c +++ b/library/profile/_mcount.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: profile__mcount.c,v 1.0 2022-08-06 10:36:26 clib2devs Exp $ */ #include "profile_gmon.h" @@ -11,100 +11,94 @@ void __mcount(uint32 frompc, uint32 selfpc); void -__mcount(uint32 frompc, uint32 selfpc) -{ - uint16 *frompcindex; - struct tostruct *top, *prevtop; - struct gmonparam *p; - - int32 toindex; - - p = &_gmonparam; - - if (p->state != kGmonProfOn) return; - - p->state = kGmonProfBusy; - - /* - * Check if the PC is inside our text segment. - * Really should be... - */ - frompc -= p->lowpc; - selfpc -= p->lowpc; - if (frompc > p->textsize) goto done; - -#if (HASHFRACTION & (HASHFRACTION-1)) == 0 - if (p->hashfraction == HASHFRACTION) - { - frompcindex = &p->froms[(size_t)(frompc / (HASHFRACTION * - sizeof(*p->froms)))]; - } - else +__mcount(uint32 frompc, uint32 selfpc) { + uint16 *frompcindex; + struct tostruct *top, *prevtop; + struct gmonparam *p; + + int32 toindex; + + p = &_gmonparam; + + if (p->state != kGmonProfOn) + return; + + p->state = kGmonProfBusy; + + /* + * Check if the PC is inside our text segment. + * Really should be... + */ + frompc -= p->lowpc; + selfpc -= p->lowpc; + if (frompc > p->textsize) + goto done; + +#if (HASHFRACTION & (HASHFRACTION - 1)) == 0 + if (p->hashfraction == HASHFRACTION) { + frompcindex = &p->froms[(size_t)(frompc / (HASHFRACTION * + sizeof(*p->froms)))]; + } else #endif - { - frompcindex = &p->froms[(size_t)(frompc / (p->hashfraction * - sizeof(*p->froms)))]; - } - - toindex = *frompcindex; - - if (toindex == 0) - { - /* first time down this arc */ - toindex = ++p->tos[0].link; - if (toindex >= p->tolimit) - /* Ouch! Overflow */ - goto overflow; - - *frompcindex = (uint16)toindex; - top = &p->tos[toindex]; - top->selfpc = selfpc; - top->count = 1; - top->link = 0; - goto done; - } - - top = &p->tos[toindex]; - if (top->selfpc == selfpc) - { - /* arc at front of chain */ - top->count++; - goto done; - } - - for (;;) - { - if (top->link == 0) - { - toindex = ++p->tos[0].link; - if (toindex >= p->tolimit) - goto overflow; - - top = &p->tos[toindex]; - top->selfpc = selfpc; - top->count = 1; - top->link = *frompcindex; - *frompcindex = (uint16)toindex; - goto done; - } - prevtop = top; - top = &p->tos[top->link]; - if (top->selfpc == selfpc) - { - top->count++; - toindex = prevtop->link; - prevtop->link = top->link; - top->link = *frompcindex; - *frompcindex = (uint16)toindex; - goto done; - } - } + { + frompcindex = &p->froms[(size_t)(frompc / (p->hashfraction * + sizeof(*p->froms)))]; + } + + toindex = *frompcindex; + + if (toindex == 0) { + /* first time down this arc */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + /* Ouch! Overflow */ + goto overflow; + + *frompcindex = (uint16) toindex; + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + + top = &p->tos[toindex]; + if (top->selfpc == selfpc) { + /* arc at front of chain */ + top->count++; + goto done; + } + + for (;;) { + if (top->link == 0) { + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + goto overflow; + + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = *frompcindex; + *frompcindex = (uint16) toindex; + goto done; + } + prevtop = top; + top = &p->tos[top->link]; + if (top->selfpc == selfpc) { + top->count++; + toindex = prevtop->link; + prevtop->link = top->link; + top->link = *frompcindex; + *frompcindex = (uint16) toindex; + goto done; + } + } done: - p->state = kGmonProfOn; - return; + p->state = kGmonProfOn; + return; overflow: - p->state = kGmonProfError; - return; + p->state = kGmonProfError; + return; } diff --git a/library/profile/gmon.c b/library/profile/gmon.c index 2c457fe0..b5f115e7 100644 --- a/library/profile/gmon.c +++ b/library/profile/gmon.c @@ -1,5 +1,5 @@ /* - * $Id: profile_gmn.c,v 1.0 2021-01-18 12:04:26 clib2devs Exp $ + * $Id: profile_gmon.c,v 1.0 2021-01-18 12:04:26 clib2devs Exp $ */ #include @@ -13,13 +13,17 @@ #define SCALE_1_TO_1 0x10000L #include "profile_gmon.h" + #undef DebugPrintF #define dprintf(format, args...) ((struct ExecIFace *)((*(struct ExecBase **)4)->MainInterface))->DebugPrintF("[%s] " format, __PRETTY_FUNCTION__, ##args) -struct gmonparam _gmonparam = - { - state : kGmonProfOn - }; +struct gmonparam _gmonparam = { + state : kGmonProfOn +}; + +/* Use __executable_start as the lowest address to keep profiling records + if it provided by the linker. */ +extern const char __executable_start[] __attribute__ ((visibility ("hidden"))); static unsigned int s_scale; @@ -27,253 +31,223 @@ void moncontrol(int); void monstartup(uint32, uint32); void moncleanup(void); void mongetpcs(uint32 *lowpc, uint32 *highpc); - -extern int profil(uint16 *buffer, uint32 bufSize, - uint32 offset, uint32 scale); - -void monstartup(uint32 low_pc, uint32 high_pc) -{ - uint8 *cp; - uint32 lowpc, highpc; - struct gmonparam *p = &_gmonparam; - dprintf("in monstartup)\n"); - /* - * If we don't get proper lowpc and highpc, then - * we'll try to get them from the elf handle. - */ - if (low_pc == 0 && high_pc == 0) - { - mongetpcs(&lowpc, &highpc); - } - else - { - lowpc = low_pc; - highpc = high_pc; - } - - /* - * Round lowpc and highpc to multiples of the density - * to prevent using floating point scaling - */ - p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); - p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); - - /* Size of the text segment */ - p->textsize = p->highpc - p->lowpc; - - /* - * Size of the histogram. Due to the nature of PowerPC code, - * we can safely use a histogram fraction of at least 4, since - * every instruction is exactly one word wide and always aligned. - */ - p->kcountsize = p->textsize / HISTFRACTION; - - /* - * The hash table size - */ - p->hashfraction = HASHFRACTION; - p->fromssize = p->textsize / p->hashfraction; - - p->tolimit = p->textsize * ARCDENSITY / 100; - if (p->tolimit < MINARCS) - p->tolimit = MINARCS; - else if (p->tolimit > MAXARCS) - p->tolimit = MAXARCS; - - p->tossize = p->tolimit * sizeof(struct tostruct); - - dprintf("lowpc = %p, highpc = %p\n", lowpc, highpc); - dprintf("textsize = %d\n", p->textsize); - dprintf("kcountsize = %d\n", p->kcountsize); - dprintf("fromssize = %d\n", p->fromssize); - dprintf("tolimit = %d, tossize = %d\n", p->tolimit, p->tossize); - - cp = (uint8 *)AllocVecTags(p->kcountsize + p->fromssize + p->tossize, AVT_Type, MEMF_SHARED, AVT_ClearWithValue, 0, TAG_DONE); - if (!cp) - { - p->state = kGmonProfError; - return; - } - - p->memory = cp; - p->tos = (struct tostruct *)cp; - cp += p->tossize; - - p->kcount = (uint16 *)cp; - cp += p->kcountsize; - - p->froms = (uint16 *)cp; - - p->tos[0].link = 0; - - /* Verify granularity for sampling */ - if (p->kcountsize < p->textsize) - /* FIXME Avoid floating point */ - s_scale = ((float)p->kcountsize / p->textsize) * SCALE_1_TO_1; - else - s_scale = SCALE_1_TO_1; - - s_scale >>= 1; - dprintf("Enabling monitor\n"); - moncontrol(1); +extern int profil(uint16 *buffer, uint32 bufSize, uint32 offset, uint32 scale); + +void monstartup(uint32 low_pc, uint32 high_pc) { + uint8 *cp; + uint32 lowpc, highpc; + struct gmonparam *p = &_gmonparam; + dprintf("in monstartup)\n"); + /* + * If we don't get proper lowpc and highpc, then + * we'll try to get them from the elf handle. + */ + if (low_pc == 0 && high_pc == 0) { + mongetpcs(&lowpc, &highpc); + } else { + lowpc = low_pc; + highpc = high_pc; + } + + /* + * Round lowpc and highpc to multiples of the density + * to prevent using floating point scaling + */ + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + + /* Size of the text segment */ + p->textsize = p->highpc - p->lowpc; + + /* + * Size of the histogram. Due to the nature of PowerPC code, + * we can safely use a histogram fraction of at least 4, since + * every instruction is exactly one word wide and always aligned. + */ + p->kcountsize = p->textsize / HISTFRACTION; + + /* + * The hash table size + */ + p->hashfraction = HASHFRACTION; + p->fromssize = p->textsize / p->hashfraction; + + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) + p->tolimit = MINARCS; + else if (p->tolimit > MAXARCS) + p->tolimit = MAXARCS; + + p->tossize = p->tolimit * sizeof(struct tostruct); + + dprintf("lowpc = %p, highpc = %p\n", lowpc, highpc); + dprintf("textsize = %d\n", p->textsize); + dprintf("kcountsize = %d\n", p->kcountsize); + dprintf("fromssize = %d\n", p->fromssize); + dprintf("tolimit = %d, tossize = %d\n", p->tolimit, p->tossize); + + cp = (uint8 *) AllocVecTags(p->kcountsize + p->fromssize + p->tossize, AVT_Type, MEMF_SHARED, AVT_ClearWithValue, 0, TAG_DONE); + if (!cp) { + p->state = kGmonProfError; + return; + } + + p->memory = cp; + p->tos = (struct tostruct *) cp; + cp += p->tossize; + + p->kcount = (uint16 *) cp; + cp += p->kcountsize; + + p->froms = (uint16 *) cp; + + p->tos[0].link = 0; + + /* Verify granularity for sampling */ + if (p->kcountsize < p->textsize) + /* FIXME Avoid floating point */ + s_scale = ((float) p->kcountsize / p->textsize) * SCALE_1_TO_1; + else + s_scale = SCALE_1_TO_1; + + s_scale >>= 1; + dprintf("Enabling monitor\n"); + moncontrol(1); } -void moncontrol(int mode) -{ - struct gmonparam *p = &_gmonparam; - - if (mode) - { - /* Start profiling. */ - profil((uint16 *)p->kcount, (size_t)p->kcountsize, - p->lowpc, s_scale); - p->state = kGmonProfOn; - } - else - { - /* Stop Profiling. */ - profil(NULL, 0, (uint32)0, 0); - p->state = kGmonProfOff; - } +void moncontrol(int mode) { + struct gmonparam *p = &_gmonparam; + + if (mode) { + /* Start profiling. */ + profil((uint16 *) p->kcount, (size_t) p->kcountsize, p->lowpc, s_scale); + p->state = kGmonProfOn; + } else { + /* Stop Profiling. */ + profil(NULL, 0, (uint32) 0, 0); + p->state = kGmonProfOff; + } } -void moncleanup(void) -{ - BPTR fd; - int fromindex; - int endfrom; - uint32 frompc; - int toindex; - struct rawarc rawarc; - struct gmonparam *p = &_gmonparam; - struct gmonhdr gmonhdr, *hdr; +void moncleanup(void) { + BPTR fd; + int fromindex; + int endfrom; + uint32 frompc; + int toindex; + struct rawarc rawarc; + struct gmonparam *p = &_gmonparam; + struct gmonhdr gmonhdr, *hdr; #ifdef DEBUG - FILE *log; + FILE *log; #endif - moncontrol(0); + moncontrol(0); - if (p->state == kGmonProfError) - { - fprintf(stderr, "WARNING: Overflow during profiling\n"); - } + if (p->state == kGmonProfError) { + fprintf(stderr, "WARNING: Overflow during profiling\n"); + } - fd = Open("gmon.out", MODE_NEWFILE); - if (!fd) - { - fprintf(stderr, "ERROR: could not open gmon.out\n"); - return; - } + fd = Open("gmon.out", MODE_NEWFILE); + if (!fd) { + fprintf(stderr, "ERROR: could not open gmon.out\n"); + return; + } - hdr = (struct gmonhdr *)&gmonhdr; + hdr = (struct gmonhdr *) &gmonhdr; - hdr->lpc = 0; //p->lowpc; - hdr->hpc = p->highpc - p->lowpc; - hdr->ncnt = (int)p->kcountsize + sizeof(gmonhdr); - hdr->version = GMONVERSION; - hdr->profrate = 100; //FIXME:!! + hdr->lpc = 0; //p->lowpc; + hdr->hpc = p->highpc - p->lowpc; + hdr->ncnt = (int) p->kcountsize + sizeof(gmonhdr); + hdr->version = GMONVERSION; + hdr->profrate = 100; //FIXME:!! - Write(fd, hdr, sizeof(*hdr)); - Write(fd, p->kcount, p->kcountsize); + Write(fd, hdr, sizeof(*hdr)); + Write(fd, p->kcount, p->kcountsize); - endfrom = p->fromssize / sizeof(*p->froms); + endfrom = p->fromssize / sizeof(*p->froms); #ifdef DEBUG - log = fopen("gmon.log", "w"); + log = fopen("gmon.log", "w"); #endif - for (fromindex = 0; fromindex < endfrom; fromindex++) - { - if (p->froms[fromindex] == 0) - continue; - - frompc = 0; /* FIXME: was p->lowpc; needs to be 0 and assumes - -Ttext=0 on compile. Better idea? */ - frompc += fromindex * p->hashfraction * sizeof(*p->froms); - for (toindex = p->froms[fromindex]; toindex != 0; - toindex = p->tos[toindex].link) - { + for (fromindex = 0; fromindex < endfrom; fromindex++) { + if (p->froms[fromindex] == 0) + continue; + + frompc = 0; /* FIXME: was p->lowpc; needs to be 0 and assumes -Ttext=0 on compile. Better idea? */ + frompc += fromindex * p->hashfraction * sizeof(*p->froms); + for (toindex = p->froms[fromindex]; toindex != 0; + toindex = p->tos[toindex].link) { #ifdef DEBUG - if (log) - fprintf(log, "%p called from %p: %d times\n", frompc, - p->tos[toindex].selfpc, - p->tos[toindex].count); + if (log) + fprintf(log, "%p called from %p: %d times\n", frompc, + p->tos[toindex].selfpc, + p->tos[toindex].count); #endif - rawarc.raw_frompc = frompc; - rawarc.raw_selfpc = p->tos[toindex].selfpc; - rawarc.raw_count = p->tos[toindex].count; - Write(fd, &rawarc, sizeof(rawarc)); - } - } + rawarc.raw_frompc = frompc; + rawarc.raw_selfpc = p->tos[toindex].selfpc; + rawarc.raw_count = p->tos[toindex].count; + Write(fd, &rawarc, sizeof(rawarc)); + } + } #ifdef DEBUG - if (log) - fclose(log); + if (log) + fclose(log); #endif - Close(fd); + Close(fd); } -void mongetpcs(uint32 *lowpc, uint32 *highpc) -{ - struct Library *ElfBase = NULL; - struct ElfIFace *IElf = NULL; - struct Process *self; - BPTR seglist; - Elf32_Handle elfHandle; - uint32 i; - Elf32_Shdr *shdr; - uint32 numSections; - - *lowpc = 0; - *highpc = 0; - - ElfBase = OpenLibrary("elf.library", 0L); - if (!ElfBase) - goto out; - - IElf = (struct ElfIFace *)GetInterface(ElfBase, "main", 1, NULL); - if (!IElf) - goto out; - - self = (struct Process *)FindTask(0); - seglist = GetProcSegList(self, GPSLF_CLI | GPSLF_SEG); - - GetSegListInfoTags(seglist, - GSLI_ElfHandle, &elfHandle, - TAG_DONE); - - elfHandle = OpenElfTags( - OET_ElfHandle, elfHandle, - TAG_DONE); - - if (!elfHandle) - goto out; - - GetElfAttrsTags(elfHandle, EAT_NumSections, &numSections, TAG_DONE); - - for (i = 0; i < numSections; i++) - { - shdr = GetSectionHeaderTags(elfHandle, - GST_SectionIndex, i, - TAG_DONE); - if (shdr && (shdr->sh_flags & SWF_EXECINSTR)) - { - uint32 base = (uint32)GetSectionTags(elfHandle, - GST_SectionIndex, i, - TAG_DONE); - *lowpc = base; - *highpc = base + shdr->sh_size; - break; - } - } - - CloseElfTags(elfHandle, CET_ReClose, TRUE, TAG_DONE); +void mongetpcs(uint32 *lowpc, uint32 *highpc) { + struct Library *ElfBase = NULL; + struct ElfIFace *IElf = NULL; + struct Process *self; + BPTR seglist; + Elf32_Handle elfHandle; + uint32 i; + Elf32_Shdr *shdr; + uint32 numSections; + + *lowpc = 0; + *highpc = 0; + + ElfBase = OpenLibrary("elf.library", 0L); + if (!ElfBase) + goto out; + + IElf = (struct ElfIFace *) GetInterface(ElfBase, "main", 1, NULL); + if (!IElf) + goto out; + + self = (struct Process *) FindTask(0); + seglist = GetProcSegList(self, GPSLF_CLI | GPSLF_SEG); + + GetSegListInfoTags(seglist, GSLI_ElfHandle, &elfHandle, TAG_DONE); + elfHandle = OpenElfTags(OET_ElfHandle, elfHandle, TAG_DONE); + + if (!elfHandle) + goto out; + + GetElfAttrsTags(elfHandle, EAT_NumSections, &numSections, TAG_DONE); + + for (i = 0; i < numSections; i++) { + shdr = GetSectionHeaderTags(elfHandle, GST_SectionIndex, i, TAG_DONE); + if (shdr && (shdr->sh_flags & SWF_EXECINSTR)) { + uint32 base = (uint32) GetSectionTags(elfHandle, GST_SectionIndex, i, TAG_DONE); + *lowpc = base; + *highpc = base + shdr->sh_size; + break; + } + } + + CloseElfTags(elfHandle, CET_ReClose, TRUE, TAG_DONE); out: - if (IElf) - DropInterface((struct Interface *)IElf); - if (ElfBase) - CloseLibrary(ElfBase); + if (IElf) + DropInterface((struct Interface *) IElf); + if (ElfBase) + CloseLibrary(ElfBase); } #include "macros.h" @@ -281,13 +255,11 @@ void mongetpcs(uint32 *lowpc, uint32 *highpc) int __profiler_init(void) __attribute__((constructor)); void __profiler_exit(void) __attribute__((destructor)); -int __profiler_init(void) -{ - monstartup(0, 0); - return OK; +int __profiler_init(void) { + monstartup(0, 0); + return OK; } -void __profiler_exit(void) -{ - moncleanup(); +void __profiler_exit(void) { + moncleanup(); } diff --git a/library/profile/mcount.S b/library/profile/mcount.S index 672cba88..e35f961d 100644 --- a/library/profile/mcount.S +++ b/library/profile/mcount.S @@ -1,34 +1,5 @@ // -// $Id$ -// -// :ts=4 -// -// Portable ISO 'C' (1994) runtime library for the Amiga computer -// Copyright (c) 2002-2015 by Olaf Barthel -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// - Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// - Neither the name of Olaf Barthel nor the names of contributors -// may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. +// $Id: profile_mcount.S,v 1.0 2021-01-18 12:04:26 clib2devs Exp $ // .globl _mcount diff --git a/library/profile/profil.c b/library/profile/profil.c index bf1c1ec2..f46252b6 100644 --- a/library/profile/profil.c +++ b/library/profile/profil.c @@ -1,4 +1,5 @@ -/* $Id$ profile_profil.c,v 1.0 2021-01-21 10:08:32 clib2devs Exp $ +/* + * $Id: profile_profil.c,v 1.0 2021-01-21 10:08:32 clib2devs Exp $ */ #include @@ -10,67 +11,62 @@ static struct Interrupt CounterInt; static struct PerformanceMonitorIFace *IPM; -static struct IntData -{ - struct PerformanceMonitorIFace *IPM; - uint16 *Buffer; - uint32 BufferSize; - uint32 Offset; - uint32 Scale; - uint32 CounterStart; +static struct IntData { + struct PerformanceMonitorIFace *IPM; + uint16 *Buffer; + uint32 BufferSize; + uint32 Offset; + uint32 Scale; + uint32 CounterStart; } ProfileData; uint32 GetCounterStart(void); + uint32 CounterIntFn(struct ExceptionContext *, struct ExecBase *, struct IntData *); uint32 -GetCounterStart(void) -{ - uint64 fsb; - double bit0time; - uint32 count; +GetCounterStart(void) { + uint64 fsb; + double bit0time; + uint32 count; - GetCPUInfoTags( - GCIT_FrontsideSpeed, &fsb, - TAG_DONE); + GetCPUInfoTags( + GCIT_FrontsideSpeed, &fsb, + TAG_DONE); - /* Timebase ticks at 1/4 of FSB */ - bit0time = 8.0 / (double)fsb; - count = (uint32)(0.01 / bit0time); + /* Timebase ticks at 1/4 of FSB */ + bit0time = 8.0 / (double) fsb; + count = (uint32)(0.01 / bit0time); - return 0x80000000 - count; + return 0x80000000 - count; } uint32 -CounterIntFn(struct ExceptionContext *ctx, struct ExecBase *ExecBase, struct IntData *profileData) -{ - APTR sampledAddress = profileData->IPM->GetSampledAddress(); - uint32 sia = (uint32)sampledAddress; +CounterIntFn(struct ExceptionContext *ctx, struct ExecBase *ExecBase, struct IntData *profileData) { + APTR sampledAddress = profileData->IPM->GetSampledAddress(); + uint32 sia = (uint32) sampledAddress; - /* Silence compiler */ - (void)ExecBase; - (void)ctx; + /* Silence compiler */ + (void) ExecBase; + (void) ctx; - sia = ((sia - profileData->Offset) * profileData->Scale) >> 16; + sia = ((sia - profileData->Offset) * profileData->Scale) >> 16; - if (sia <= (profileData->BufferSize >> 1)) - { - //if (ProfileData->Buffer[sia] != 0xffff) - profileData->Buffer[sia]++; - } + if (sia <= (profileData->BufferSize >> 1)) { + //if (ProfileData->Buffer[sia] != 0xffff) + profileData->Buffer[sia]++; + } - IPM->CounterControl(1, profileData->CounterStart, PMCI_Transition); + IPM->CounterControl(1, profileData->CounterStart, PMCI_Transition); - return 1; + return 1; } -int -profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale) -{ - APTR Stack; +int +profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale) { + APTR Stack; - if (buffer == 0) - { + if (buffer == 0) { /* * On systems with with a processor that does not support performancemonitor.resource, e.g. the AMCC PowerPC 440EP, profil() generates a DSI at process termination when buffer == 0. * A pointer to PerformanceMonitorIFace is never obtained, and the call to IPM->EventControlTags() when buffer == 0 attempts to dereference a NULL pointer @@ -79,60 +75,57 @@ profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale if (!IPM) return 0; - Stack = SuperState(); - IPM->EventControlTags( - PMECT_Disable, PMEC_MasterInterrupt, - TAG_DONE); - - IPM->SetInterruptVector(1, 0); + Stack = SuperState(); + IPM->EventControlTags( + PMECT_Disable, PMEC_MasterInterrupt, + TAG_DONE); - IPM->Unmark(0); - IPM->Release(); - if (Stack) - UserState(Stack); + IPM->SetInterruptVector(1, 0); - return 0; - } + IPM->Unmark(0); + IPM->Release(); + if (Stack) + UserState(Stack); - IPM = (struct PerformanceMonitorIFace *) - OpenResource("performancemonitor.resource"); + return 0; + } - if (!IPM || IPM->Obtain() != 1) - { - return 0; - } + IPM = (struct PerformanceMonitorIFace *) OpenResource("performancemonitor.resource"); + if (!IPM || IPM->Obtain() != 1) { + return 0; + } - Stack = SuperState(); + Stack = SuperState(); - /* Init IntData */ - ProfileData.IPM = IPM; - ProfileData.Buffer = buffer; - ProfileData.BufferSize = bufSize; - ProfileData.Offset = offset; - ProfileData.Scale = scale; - ProfileData.CounterStart = GetCounterStart(); + /* Init IntData */ + ProfileData.IPM = IPM; + ProfileData.Buffer = buffer; + ProfileData.BufferSize = bufSize; + ProfileData.Offset = offset; + ProfileData.Scale = scale; + ProfileData.CounterStart = GetCounterStart(); - /* Set interrupt vector */ - CounterInt.is_Code = (void (*)(void))CounterIntFn; - CounterInt.is_Data = &ProfileData; - IPM->SetInterruptVector(1, &CounterInt); + /* Set interrupt vector */ + CounterInt.is_Code = (void (*)(void)) CounterIntFn; + CounterInt.is_Data = &ProfileData; + IPM->SetInterruptVector(1, &CounterInt); - /* Prepare Performance Monitor */ - IPM->MonitorControlTags( - PMMCT_FreezeCounters, PMMC_Unmarked, - PMMCT_RTCBitSelect, PMMC_BIT0, - TAG_DONE); - IPM->CounterControl(1, ProfileData.CounterStart, PMCI_Transition); + /* Prepare Performance Monitor */ + IPM->MonitorControlTags( + PMMCT_FreezeCounters, PMMC_Unmarked, + PMMCT_RTCBitSelect, PMMC_BIT0, + TAG_DONE); + IPM->CounterControl(1, ProfileData.CounterStart, PMCI_Transition); - IPM->EventControlTags( - PMECT_Enable, 1, - PMECT_Enable, PMEC_MasterInterrupt, - TAG_DONE); + IPM->EventControlTags( + PMECT_Enable, 1, + PMECT_Enable, PMEC_MasterInterrupt, + TAG_DONE); - IPM->Mark(0); + IPM->Mark(0); - if (Stack) - UserState(Stack); + if (Stack) + UserState(Stack); - return 0; + return 0; } diff --git a/library/profile/profile_gmon.h b/library/profile/profile_gmon.h index eede85f8..1d5a5280 100755 --- a/library/profile/profile_gmon.h +++ b/library/profile/profile_gmon.h @@ -1,5 +1,5 @@ /* -* $Id$ +* $Id: profile_gmon.h,v 1.0 2021-01-18 12:04:26 clib2devs Exp $ */ #ifndef _GMON_H @@ -7,14 +7,13 @@ #include -struct gmonhdr -{ - uint32 lpc; - uint32 hpc; - int ncnt; - int version; - int profrate; - int reserved[3]; +struct gmonhdr { + uint32 lpc; + uint32 hpc; + int ncnt; + int version; + int profrate; + int reserved[3]; }; #define GMONVERSION 0x00051879 @@ -24,62 +23,57 @@ struct gmonhdr #define HISTFRACTION 2 #define HASHFRACTION 4 -#define ARCDENSITY 2 -#define MINARCS 50 -#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER)))-2) +#define ARCDENSITY 2 +#define MINARCS 50 +#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER)))-2) -struct tostruct -{ - uint32 selfpc; - int32 count; - uint16 link; - uint16 pad; +struct tostruct { + uint32 selfpc; + int32 count; + uint16 link; + uint16 pad; }; -struct rawarc -{ - uint32 raw_frompc; - uint32 raw_selfpc; - int32 raw_count; +struct rawarc { + uint32 raw_frompc; + uint32 raw_selfpc; + int32 raw_count; }; -#define ROUNDDOWN(x,y) (((x)/(y))*(y)) -#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) +#define ROUNDDOWN(x, y) (((x)/(y))*(y)) +#define ROUNDUP(x, y) ((((x)+(y)-1)/(y))*(y)) -struct gmonparam -{ - int state; - uint16 * kcount; - uint32 kcountsize; - uint16 * froms; - uint32 fromssize; - struct tostruct * tos; - uint32 tossize; - int32 tolimit; - uint32 lowpc; - uint32 highpc; - uint32 textsize; - uint32 hashfraction; - uint8 * memory; +struct gmonparam { + int state; + uint16 *kcount; + uint32 kcountsize; + uint16 *froms; + uint32 fromssize; + struct tostruct *tos; + uint32 tossize; + int32 tolimit; + uint32 lowpc; + uint32 highpc; + uint32 textsize; + uint32 hashfraction; + uint8 *memory; }; extern struct gmonparam _gmonparam; -enum -{ - kGmonProfOn = 0, - kGmonProfBusy = 1, - kGmonProfError = 2, - kGmonProfOff = 3 +enum { + kGmonProfOn = 0, + kGmonProfBusy = 1, + kGmonProfError = 2, + kGmonProfOff = 3 }; -enum -{ - kGprofState = 0, - kGprofCount = 1, - kGprofFroms = 2, - kGprofTos = 3, - kGprofGmonParam = 4 +enum { + kGprofState = 0, + kGprofCount = 1, + kGprofFroms = 2, + kGprofTos = 3, + kGprofGmonParam = 4 }; #endif diff --git a/library/pthread/common.h b/library/pthread/common.h index ff0f1253..d5fa475f 100644 --- a/library/pthread/common.h +++ b/library/pthread/common.h @@ -2,6 +2,7 @@ #define _COMMON_H #include "pthread.h" +#include #undef NEWLIST #define NEWLIST(_l) \ @@ -15,9 +16,12 @@ do \ l->lh_Head = (struct Node *)&l->lh_Tail; \ } while (0) -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ +#define TIMESPEC_TO_OLD_TIMEVAL(tv, ts) { \ (tv)->Seconds = (ts)->tv_sec; \ (tv)->Microseconds = (ts)->tv_nsec / 1000; } +#define OLD_TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->Seconds; \ + (ts)->tv_nsec = (tv)->Microseconds * 1000; } enum threadState { diff --git a/library/pthread/pthread.c b/library/pthread/pthread.c index 71479e0c..e8d881e6 100644 --- a/library/pthread/pthread.c +++ b/library/pthread/pthread.c @@ -22,6 +22,7 @@ 3. This notice may not be removed or altered from any source distribution. */ +#define __USE_OLD_TIMEVAL__ #ifndef _TIME_HEADERS_H #include "time_headers.h" #endif /* _TIME_HEADERS_H */ @@ -83,7 +84,7 @@ _pthread_obtain_sema_timed(struct SignalSemaphore *sema, const struct timespec * timerio.Request.io_Command = TR_ADDREQUEST; timerio.Request.io_Flags = 0; - TIMESPEC_TO_TIMEVAL(&timerio.Time, abstime); + TIMESPEC_TO_OLD_TIMEVAL(&timerio.Time, abstime); //if (!relative) { struct TimeVal starttime; @@ -151,7 +152,7 @@ _pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const stru // prepare the device command and send it timerio.Request.io_Command = TR_ADDREQUEST; timerio.Request.io_Flags = 0; - TIMESPEC_TO_TIMEVAL(&timerio.Time, abstime); + TIMESPEC_TO_OLD_TIMEVAL(&timerio.Time, abstime); if (!relative) { struct TimeVal starttime; // absolute time has to be converted to relative diff --git a/library/pthread.lib_rev.c b/library/pthread/pthread.lib_rev.c similarity index 100% rename from library/pthread.lib_rev.c rename to library/pthread/pthread.lib_rev.c diff --git a/library/pthread.lib_rev.h b/library/pthread/pthread.lib_rev.h similarity index 100% rename from library/pthread.lib_rev.h rename to library/pthread/pthread.lib_rev.h diff --git a/library/pthread.lib_rev.rev b/library/pthread/pthread.lib_rev.rev similarity index 100% rename from library/pthread.lib_rev.rev rename to library/pthread/pthread.lib_rev.rev diff --git a/library/pthread/pthread_attr_getguardsize.c b/library/pthread/pthread_attr_getguardsize.c new file mode 100644 index 00000000..ee1393a9 --- /dev/null +++ b/library/pthread/pthread_attr_getguardsize.c @@ -0,0 +1,15 @@ +/* + $Id: pthread_attr_getguardsize.c,v 1.00 2023-03-03 12:09:49 clib2devs Exp $ +*/ + +#include "pthread.h" + +int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) { + if (attr == NULL) + return EINVAL; + + if (guardsize != NULL) + *guardsize = attr->guardsize; + + return 0; +} \ No newline at end of file diff --git a/library/pthread/pthread_attr_setguardsize.c b/library/pthread/pthread_attr_setguardsize.c new file mode 100644 index 00000000..52e5544c --- /dev/null +++ b/library/pthread/pthread_attr_setguardsize.c @@ -0,0 +1,14 @@ +/* + $Id: pthread_attr_setguardsize.c,v 1.00 2023-03-03 12:09:49 clib2devs Exp $ +*/ + +#include "pthread.h" + +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) { + if (attr == NULL || guardsize < 0) + return EINVAL; + + attr->guardsize = guardsize; + + return 0; +} \ No newline at end of file diff --git a/library/pthread/pthread_create.c b/library/pthread/pthread_create.c index be96c4d6..0aee05cc 100644 --- a/library/pthread/pthread_create.c +++ b/library/pthread/pthread_create.c @@ -48,6 +48,10 @@ StarterFunc() { // custom stack requires special handling if (inf->attr.stackaddr != NULL && inf->attr.stacksize > 0) { + // Check if we have a guardsize + if (inf->attr.guardsize > 0) + inf->attr.stacksize += inf->attr.guardsize; + stack.stk_Lower = inf->attr.stackaddr; stack.stk_Upper = (ULONG)((APTR) stack.stk_Lower) + inf->attr.stacksize; stack.stk_Pointer = (APTR) stack.stk_Upper; @@ -144,6 +148,10 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start)(voi if (inf->attr.stacksize < minStack) inf->attr.stacksize = minStack; + // Check if we have a guardsize + if (inf->attr.guardsize > 0) + inf->attr.stacksize += inf->attr.guardsize; + // let's trick CreateNewProc into allocating a larger buffer for the name snprintf(name, sizeof(name), "pthread id #%d", threadnew); oldlen = strlen(name); diff --git a/library/setjmp/__longjmp-common.S b/library/setjmp/__longjmp-common.S new file mode 100644 index 00000000..0aec91cd --- /dev/null +++ b/library/setjmp/__longjmp-common.S @@ -0,0 +1,74 @@ +/* longjmp for PowerPC. + Copyright (C) 1995-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include "../cpu/4xx/ppc4xx.inc" +#include "stap-probe.h" + +#define _ASM +#ifdef __NO_VMX__ +/* The following definitions are needed by ASM implementations of the old (novmx) __longjmp/__setjmp functions. */ +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total. */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total. */ +# define JB_SIZE (58 * 4) +#else +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total. */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total. */ +# define JB_SIZE ((64 + (12 * 4)) * 4) +# define JB_VRSAVE 62 +# define JB_VRS 64 +#endif + +function_prolog (__longjmp_symbol) + lwz r1,(JB_GPR1*4)(r3) + lwz r0,(JB_LR*4)(r3) + lwz r14,((JB_GPRS+14-14)*4)(r3) + lwz r15,((JB_GPRS+15-14)*4)(r3) + lwz r16,((JB_GPRS+16-14)*4)(r3) + lwz r17,((JB_GPRS+17-14)*4)(r3) + lwz r18,((JB_GPRS+18-14)*4)(r3) + lwz r19,((JB_GPRS+19-14)*4)(r3) + lwz r20,((JB_GPRS+20-14)*4)(r3) + /* longjmp/longjmp_target probe expects longjmp first argument (4@3), + second argument (-4@4), and target address (4@0), respectively. */ + LIBC_PROBE (longjmp, 3, 4@3, -4@4, 4@0) + mtlr r0 + lwz r21,((JB_GPRS+21-14)*4)(r3) + lwz r22,((JB_GPRS+22-14)*4)(r3) + lwz r5,(JB_CR*4)(r3) + lwz r23,((JB_GPRS+23-14)*4)(r3) + lwz r24,((JB_GPRS+24-14)*4)(r3) + lwz r25,((JB_GPRS+25-14)*4)(r3) + mtcrf 0xFF,r5 + lwz r26,((JB_GPRS+26-14)*4)(r3) + lwz r27,((JB_GPRS+27-14)*4)(r3) + lwz r28,((JB_GPRS+28-14)*4)(r3) + lwz r29,((JB_GPRS+29-14)*4)(r3) + lwz r30,((JB_GPRS+30-14)*4)(r3) + lwz r31,((JB_GPRS+31-14)*4)(r3) + LIBC_PROBE (longjmp_target, 3, 4@3, -4@4, 4@0) + mr r3,r4 + blr +function_epilog (__longjmp_symbol) diff --git a/library/setjmp/_longjmp.S b/library/setjmp/_longjmp.S new file mode 100644 index 00000000..3e54f8a5 --- /dev/null +++ b/library/setjmp/_longjmp.S @@ -0,0 +1,10 @@ +/* + * $Id: setjmp_longjmp.S,v 1.0 2023-03-02 12:04:24 clib2devs Exp $ +*/ + +#define __NO_VMX__ +#undef JB_SIZE +#undef __longjmp_symbol +#define __longjmp_symbol _longjmp +#include "__longjmp-common.S" + diff --git a/library/stdlib/setjmp.c b/library/setjmp/longjmp.c similarity index 50% rename from library/stdlib/setjmp.c rename to library/setjmp/longjmp.c index 2c398e88..f7e274fb 100644 --- a/library/stdlib/setjmp.c +++ b/library/setjmp/longjmp.c @@ -1,43 +1,7 @@ /* - * $Id: stdlib_setjmp.c,v 1.6 2010-10-20 13:50:17 clib2devs Exp $ + * $Id: stdlib_longjmp.c,v 1.6 2010-10-20 13:50:17 clib2devs Exp $ */ -__asm(" \n\ - \n\ - .text \n\ - .align 2 \n\ - \n\ - .globl setjmp \n\ - \n\ -setjmp: \n\ - \n\ - mflr r10 \n\ - mfcr r11 \n\ - mr r12, r1 \n\ - stmw r10, 0(r3) \n\ - stfd f14, 88(r3) \n\ - stfd f15, 96(r3) \n\ - stfd f16, 104(r3) \n\ - stfd f17, 112(r3) \n\ - stfd f18, 120(r3) \n\ - stfd f19, 128(r3) \n\ - stfd f20, 136(r3) \n\ - stfd f21, 144(r3) \n\ - stfd f22, 152(r3) \n\ - stfd f23, 160(r3) \n\ - stfd f24, 168(r3) \n\ - stfd f25, 176(r3) \n\ - stfd f26, 184(r3) \n\ - stfd f27, 192(r3) \n\ - stfd f28, 200(r3) \n\ - stfd f29, 208(r3) \n\ - stfd f30, 216(r3) \n\ - stfd f31, 224(r3) \n\ - li r3, 0 \n\ - blr \n\ - \n\ -"); - __asm(" \n\ .text \n\ .align 2 \n\ diff --git a/library/setjmp/sdt.h b/library/setjmp/sdt.h new file mode 100644 index 00000000..508596ec --- /dev/null +++ b/library/setjmp/sdt.h @@ -0,0 +1,507 @@ +/* - Systemtap static probe definition macros. + + This file is dedicated to the public domain, pursuant to CC0 + (https://creativecommons.org/publicdomain/zero/1.0/) +*/ + +#ifndef _SYS_SDT_H +#define _SYS_SDT_H 1 + +/* + This file defines a family of macros + + STAP_PROBEn(op1, ..., opn) + + that emit a nop into the instruction stream, and some data into an auxiliary + note section. The data in the note section describes the operands, in terms + of size and location. Each location is encoded as assembler operand string. + Consumer tools such as gdb or systemtap insert breakpoints on top of + the nop, and decode the location operand-strings, like an assembler, + to find the values being passed. + + The operand strings are selected by the compiler for each operand. + They are constrained by gcc inline-assembler codes. The default is: + + #define STAP_SDT_ARG_CONSTRAINT nor + + This is a good default if the operands tend to be integral and + moderate in number (smaller than number of registers). In other + cases, the compiler may report "'asm' requires impossible reload" or + similar. In this case, consider simplifying the macro call (fewer + and simpler operands), reduce optimization, or override the default + constraints string via: + + #define STAP_SDT_ARG_CONSTRAINT g + #include + + See also: + https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + https://gcc.gnu.org/onlinedocs/gcc/Constraints.html + */ + + + +#ifdef __ASSEMBLER__ +# define _SDT_PROBE(provider, name, n, arglist) \ + _SDT_ASM_BODY(provider, name, _SDT_ASM_SUBSTR_1, (_SDT_DEPAREN_##n arglist)) \ + _SDT_ASM_BASE +# define _SDT_ASM_1(x) x; +# define _SDT_ASM_2(a, b) a,b; +# define _SDT_ASM_3(a, b, c) a,b,c; +# define _SDT_ASM_5(a, b, c, d, e) a,b,c,d,e; +# define _SDT_ASM_STRING_1(x) .asciz #x; +# define _SDT_ASM_SUBSTR_1(x) .ascii #x; +# define _SDT_DEPAREN_0() /* empty */ +# define _SDT_DEPAREN_1(a) a +# define _SDT_DEPAREN_2(a,b) a b +# define _SDT_DEPAREN_3(a,b,c) a b c +# define _SDT_DEPAREN_4(a,b,c,d) a b c d +# define _SDT_DEPAREN_5(a,b,c,d,e) a b c d e +# define _SDT_DEPAREN_6(a,b,c,d,e,f) a b c d e f +# define _SDT_DEPAREN_7(a,b,c,d,e,f,g) a b c d e f g +# define _SDT_DEPAREN_8(a,b,c,d,e,f,g,h) a b c d e f g h +# define _SDT_DEPAREN_9(a,b,c,d,e,f,g,h,i) a b c d e f g h i +# define _SDT_DEPAREN_10(a,b,c,d,e,f,g,h,i,j) a b c d e f g h i j +# define _SDT_DEPAREN_11(a,b,c,d,e,f,g,h,i,j,k) a b c d e f g h i j k +# define _SDT_DEPAREN_12(a,b,c,d,e,f,g,h,i,j,k,l) a b c d e f g h i j k l +#else +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) \ + __asm__ __volatile__ ("" :: "m" (provider##_##name##_semaphore)); +#else +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) +#endif + +# define _SDT_PROBE(provider, name, n, arglist) \ + do { \ + _SDT_NOTE_SEMAPHORE_USE(provider, name); \ + __asm__ __volatile__ (_SDT_ASM_BODY(provider, name, _SDT_ASM_ARGS, (n)) \ + :: _SDT_ASM_OPERANDS_##n arglist); \ + __asm__ __volatile__ (_SDT_ASM_BASE); \ + } while (0) +# define _SDT_S(x) #x +# define _SDT_ASM_1(x) _SDT_S(x) "\n" +# define _SDT_ASM_2(a, b) _SDT_S(a) "," _SDT_S(b) "\n" +# define _SDT_ASM_3(a, b, c) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "\n" +# define _SDT_ASM_5(a, b, c, d, e) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "," _SDT_S(d) "," \ + _SDT_S(e) "\n" +# define _SDT_ASM_ARGS(n) _SDT_ASM_TEMPLATE_##n +# define _SDT_ASM_STRING_1(x) _SDT_ASM_1(.asciz #x) +# define _SDT_ASM_SUBSTR_1(x) _SDT_ASM_1(.ascii #x) + +# define _SDT_ARGFMT(no) _SDT_ASM_1(_SDT_SIGN %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_SIZE %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_TYPE %n[_SDT_S##no]) \ + _SDT_ASM_SUBSTR(_SDT_ARGTMPL(_SDT_A##no)) + + +# ifndef STAP_SDT_ARG_CONSTRAINT +# if defined __powerpc__ +# define STAP_SDT_ARG_CONSTRAINT nZr +# elif defined __arm__ +# define STAP_SDT_ARG_CONSTRAINT g +# else +# define STAP_SDT_ARG_CONSTRAINT nor +# endif +# endif + +# define _SDT_STRINGIFY(x) #x +# define _SDT_ARG_CONSTRAINT_STRING(x) _SDT_STRINGIFY(x) +/* _SDT_S encodes the size and type as 0xSSTT which is decoded by the assembler + macros _SDT_SIZE and _SDT_TYPE */ +# define _SDT_ARG(n, x) \ + [_SDT_S##n] "n" ((_SDT_ARGSIGNED (x) ? (int)-1 : 1) * (-(((int) _SDT_ARGSIZE (x)) << 8) + (-(0x7f & __builtin_classify_type (x))))), \ + [_SDT_A##n] _SDT_ARG_CONSTRAINT_STRING (STAP_SDT_ARG_CONSTRAINT) (_SDT_ARGVAL (x)) +#endif +#define _SDT_ASM_STRING(x) _SDT_ASM_STRING_1(x) +#define _SDT_ASM_SUBSTR(x) _SDT_ASM_SUBSTR_1(x) + +#define _SDT_ARGARRAY(x) (__builtin_classify_type (x) == 14 \ + || __builtin_classify_type (x) == 5) + +#ifdef __cplusplus +# define _SDT_ARGSIGNED(x) (!_SDT_ARGARRAY (x) \ + && __sdt_type<__typeof (x)>::__sdt_signed) +# define _SDT_ARGSIZE(x) (_SDT_ARGARRAY (x) \ + ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) + +# include + +template +struct __sdt_type +{ + static const bool __sdt_signed = false; +}; + +#define __SDT_ALWAYS_SIGNED(T) \ +template<> struct __sdt_type { static const bool __sdt_signed = true; }; +#define __SDT_COND_SIGNED(T,CT) \ +template<> struct __sdt_type { static const bool __sdt_signed = ((CT)(-1) < 1); }; +__SDT_ALWAYS_SIGNED(signed char) +__SDT_ALWAYS_SIGNED(short) +__SDT_ALWAYS_SIGNED(int) +__SDT_ALWAYS_SIGNED(long) +__SDT_ALWAYS_SIGNED(long long) +__SDT_ALWAYS_SIGNED(volatile signed char) +__SDT_ALWAYS_SIGNED(volatile short) +__SDT_ALWAYS_SIGNED(volatile int) +__SDT_ALWAYS_SIGNED(volatile long) +__SDT_ALWAYS_SIGNED(volatile long long) +__SDT_ALWAYS_SIGNED(const signed char) +__SDT_ALWAYS_SIGNED(const short) +__SDT_ALWAYS_SIGNED(const int) +__SDT_ALWAYS_SIGNED(const long) +__SDT_ALWAYS_SIGNED(const long long) +__SDT_ALWAYS_SIGNED(const volatile signed char) +__SDT_ALWAYS_SIGNED(const volatile short) +__SDT_ALWAYS_SIGNED(const volatile int) +__SDT_ALWAYS_SIGNED(const volatile long) +__SDT_ALWAYS_SIGNED(const volatile long long) +__SDT_COND_SIGNED(char, char) +__SDT_COND_SIGNED(wchar_t, wchar_t) +__SDT_COND_SIGNED(volatile char, char) +__SDT_COND_SIGNED(volatile wchar_t, wchar_t) +__SDT_COND_SIGNED(const char, char) +__SDT_COND_SIGNED(const wchar_t, wchar_t) +__SDT_COND_SIGNED(const volatile char, char) +__SDT_COND_SIGNED(const volatile wchar_t, wchar_t) +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) +/* __SDT_COND_SIGNED(char16_t) */ +/* __SDT_COND_SIGNED(char32_t) */ +#endif + +template +struct __sdt_type<__sdt_E[]> : public __sdt_type<__sdt_E *> {}; + +template +struct __sdt_type<__sdt_E[__sdt_N]> : public __sdt_type<__sdt_E *> {}; + +#elif !defined(__ASSEMBLER__) +__extension__ extern unsigned long long __sdt_unsp; +# define _SDT_ARGINTTYPE(x) \ + __typeof (__builtin_choose_expr (((__builtin_classify_type (x) \ + + 3) & -4) == 4, (x), 0U)) +# define _SDT_ARGSIGNED(x) \ + (!__extension__ \ + (__builtin_constant_p ((((unsigned long long) \ + (_SDT_ARGINTTYPE (x)) __sdt_unsp) \ + & ((unsigned long long)1 << (sizeof (unsigned long long) \ + * __CHAR_BIT__ - 1))) == 0) \ + || (_SDT_ARGINTTYPE (x)) -1 > (_SDT_ARGINTTYPE (x)) 0)) +# define _SDT_ARGSIZE(x) \ + (_SDT_ARGARRAY (x) ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) +#endif + +#if defined __powerpc__ || defined __powerpc64__ +# define _SDT_ARGTMPL(id) %I[id]%[id] +#elif defined __i386__ +# define _SDT_ARGTMPL(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ +#else +# define _SDT_ARGTMPL(id) %[id] +#endif + +/* NB: gdb PR24541 highlighted an unspecified corner of the sdt.h + operand note format. + + The named register may be a longer or shorter (!) alias for the + storage where the value in question is found. For example, on + i386, 64-bit value may be put in register pairs, and the register + name stored would identify just one of them. Previously, gcc was + asked to emit the %w[id] (16-bit alias of some registers holding + operands), even when a wider 32-bit value was used. + + Bottom line: the byte-width given before the @ sign governs. If + there is a mismatch between that width and that of the named + register, then a sys/sdt.h note consumer may need to employ + architecture-specific heuristics to figure out where the compiler + has actually put the complete value. +*/ + +#ifdef __LP64__ +# define _SDT_ASM_ADDR .8byte +#else +# define _SDT_ASM_ADDR .4byte +#endif + +/* The ia64 and s390 nop instructions take an argument. */ +#if defined(__ia64__) || defined(__s390__) || defined(__s390x__) +#define _SDT_NOP nop 0 +#else +#define _SDT_NOP nop +#endif + +#define _SDT_NOTE_NAME "stapsdt" +#define _SDT_NOTE_TYPE 3 + +/* If the assembler supports the necessary feature, then we can play + nice with code in COMDAT sections, which comes up in C++ code. + Without that assembler support, some combinations of probe placements + in certain kinds of C++ code may produce link-time errors. */ +#define _SDT_ASM_SECTION_AUTOGROUP_SUPPORT 1 +#if _SDT_ASM_SECTION_AUTOGROUP_SUPPORT +# define _SDT_ASM_AUTOGROUP "?" +#else +# define _SDT_ASM_AUTOGROUP "" +#endif + +#define _SDT_DEF_MACROS \ + _SDT_ASM_1(.altmacro) \ + _SDT_ASM_1(.macro _SDT_SIGN x) \ + _SDT_ASM_1(.iflt \\x) \ + _SDT_ASM_1(.ascii "-") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE_ x) \ + _SDT_ASM_1(.ascii "\x") \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE x) \ + _SDT_ASM_1(_SDT_SIZE_ %%((-(-\\x*((-\\x>0)-(-\\x<0))))>>8)) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE_ x) \ + _SDT_ASM_2(.ifc 8,\\x) \ + _SDT_ASM_1(.ascii "f") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.ascii "@") \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE x) \ + _SDT_ASM_1(_SDT_TYPE_ %%((\\x)&(0xff))) \ + _SDT_ASM_1(.endm) + +#define _SDT_UNDEF_MACROS \ + _SDT_ASM_1(.purgem _SDT_SIGN) \ + _SDT_ASM_1(.purgem _SDT_SIZE_) \ + _SDT_ASM_1(.purgem _SDT_SIZE) \ + _SDT_ASM_1(.purgem _SDT_TYPE_) \ + _SDT_ASM_1(.purgem _SDT_TYPE) + +#define _SDT_ASM_BODY(provider, name, pack_args, args, ...) \ + _SDT_DEF_MACROS \ + _SDT_ASM_1(990: _SDT_NOP) \ + _SDT_ASM_3( .pushsection .note.stapsdt,_SDT_ASM_AUTOGROUP,"note") \ + _SDT_ASM_1( .balign 4) \ + _SDT_ASM_3( .4byte 992f-991f, 994f-993f, _SDT_NOTE_TYPE) \ + _SDT_ASM_1(991: .asciz _SDT_NOTE_NAME) \ + _SDT_ASM_1(992: .balign 4) \ + _SDT_ASM_1(993: _SDT_ASM_ADDR 990b) \ + _SDT_ASM_1( _SDT_ASM_ADDR _.stapsdt.base) \ + _SDT_SEMAPHORE(provider,name) \ + _SDT_ASM_STRING(provider) \ + _SDT_ASM_STRING(name) \ + pack_args args \ + _SDT_ASM_SUBSTR(\x00) \ + _SDT_UNDEF_MACROS \ + _SDT_ASM_1(994: .balign 4) \ + _SDT_ASM_1( .popsection) + +#define _SDT_ASM_BASE \ + _SDT_ASM_1(.ifndef _.stapsdt.base) \ + _SDT_ASM_5( .pushsection .stapsdt.base,"aG","progbits", \ + .stapsdt.base,comdat) \ + _SDT_ASM_1( .weak _.stapsdt.base) \ + _SDT_ASM_1( .hidden _.stapsdt.base) \ + _SDT_ASM_1( _.stapsdt.base: .space 1) \ + _SDT_ASM_2( .size _.stapsdt.base, 1) \ + _SDT_ASM_1( .popsection) \ + _SDT_ASM_1(.endif) + +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_SEMAPHORE(p,n) \ + _SDT_ASM_1( _SDT_ASM_ADDR p##_##n##_semaphore) +#else +#define _SDT_SEMAPHORE(p,n) _SDT_ASM_1( _SDT_ASM_ADDR 0) +#endif + +#define _SDT_ASM_BLANK _SDT_ASM_SUBSTR(\x20) +#define _SDT_ASM_TEMPLATE_0 /* no arguments */ +#define _SDT_ASM_TEMPLATE_1 _SDT_ARGFMT(1) +#define _SDT_ASM_TEMPLATE_2 _SDT_ASM_TEMPLATE_1 _SDT_ASM_BLANK _SDT_ARGFMT(2) +#define _SDT_ASM_TEMPLATE_3 _SDT_ASM_TEMPLATE_2 _SDT_ASM_BLANK _SDT_ARGFMT(3) +#define _SDT_ASM_TEMPLATE_4 _SDT_ASM_TEMPLATE_3 _SDT_ASM_BLANK _SDT_ARGFMT(4) +#define _SDT_ASM_TEMPLATE_5 _SDT_ASM_TEMPLATE_4 _SDT_ASM_BLANK _SDT_ARGFMT(5) +#define _SDT_ASM_TEMPLATE_6 _SDT_ASM_TEMPLATE_5 _SDT_ASM_BLANK _SDT_ARGFMT(6) +#define _SDT_ASM_TEMPLATE_7 _SDT_ASM_TEMPLATE_6 _SDT_ASM_BLANK _SDT_ARGFMT(7) +#define _SDT_ASM_TEMPLATE_8 _SDT_ASM_TEMPLATE_7 _SDT_ASM_BLANK _SDT_ARGFMT(8) +#define _SDT_ASM_TEMPLATE_9 _SDT_ASM_TEMPLATE_8 _SDT_ASM_BLANK _SDT_ARGFMT(9) +#define _SDT_ASM_TEMPLATE_10 _SDT_ASM_TEMPLATE_9 _SDT_ASM_BLANK _SDT_ARGFMT(10) +#define _SDT_ASM_TEMPLATE_11 _SDT_ASM_TEMPLATE_10 _SDT_ASM_BLANK _SDT_ARGFMT(11) +#define _SDT_ASM_TEMPLATE_12 _SDT_ASM_TEMPLATE_11 _SDT_ASM_BLANK _SDT_ARGFMT(12) +#define _SDT_ASM_OPERANDS_0() [__sdt_dummy] "g" (0) +#define _SDT_ASM_OPERANDS_1(arg1) _SDT_ARG(1, arg1) +#define _SDT_ASM_OPERANDS_2(arg1, arg2) \ + _SDT_ASM_OPERANDS_1(arg1), _SDT_ARG(2, arg2) +#define _SDT_ASM_OPERANDS_3(arg1, arg2, arg3) \ + _SDT_ASM_OPERANDS_2(arg1, arg2), _SDT_ARG(3, arg3) +#define _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4) \ + _SDT_ASM_OPERANDS_3(arg1, arg2, arg3), _SDT_ARG(4, arg4) +#define _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5) \ + _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4), _SDT_ARG(5, arg5) +#define _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5), _SDT_ARG(6, arg6) +#define _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6), _SDT_ARG(7, arg7) +#define _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7), \ + _SDT_ARG(8, arg8) +#define _SDT_ASM_OPERANDS_9(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) \ + _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), \ + _SDT_ARG(9, arg9) +#define _SDT_ASM_OPERANDS_10(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_ASM_OPERANDS_9(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), \ + _SDT_ARG(10, arg10) +#define _SDT_ASM_OPERANDS_11(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_ASM_OPERANDS_10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10), \ + _SDT_ARG(11, arg11) +#define _SDT_ASM_OPERANDS_12(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_ASM_OPERANDS_11(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11), \ + _SDT_ARG(12, arg12) + +/* These macros can be used in C, C++, or assembly code. + In assembly code the arguments should use normal assembly operand syntax. */ + +#define STAP_PROBE(provider, name) \ + _SDT_PROBE(provider, name, 0, ()) +#define STAP_PROBE1(provider, name, arg1) \ + _SDT_PROBE(provider, name, 1, (arg1)) +#define STAP_PROBE2(provider, name, arg1, arg2) \ + _SDT_PROBE(provider, name, 2, (arg1, arg2)) +#define STAP_PROBE3(provider, name, arg1, arg2, arg3) \ + _SDT_PROBE(provider, name, 3, (arg1, arg2, arg3)) +#define STAP_PROBE4(provider, name, arg1, arg2, arg3, arg4) \ + _SDT_PROBE(provider, name, 4, (arg1, arg2, arg3, arg4)) +#define STAP_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) \ + _SDT_PROBE(provider, name, 5, (arg1, arg2, arg3, arg4, arg5)) +#define STAP_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_PROBE(provider, name, 6, (arg1, arg2, arg3, arg4, arg5, arg6)) +#define STAP_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_PROBE(provider, name, 7, (arg1, arg2, arg3, arg4, arg5, arg6, arg7)) +#define STAP_PROBE8(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) \ + _SDT_PROBE(provider, name, 8, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) +#define STAP_PROBE9(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\ + _SDT_PROBE(provider, name, 9, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)) +#define STAP_PROBE10(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_PROBE(provider, name, 10, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)) +#define STAP_PROBE11(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_PROBE(provider, name, 11, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)) +#define STAP_PROBE12(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_PROBE(provider, name, 12, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)) + +/* This STAP_PROBEV macro can be used in variadic scenarios, where the + number of probe arguments is not known until compile time. Since + variadic macro support may vary with compiler options, you must + pre-#define SDT_USE_VARIADIC to enable this type of probe. + + The trick to count __VA_ARGS__ was inspired by this post by + Laurent Deniau : + http://groups.google.com/group/comp.std.c/msg/346fc464319b1ee5 + + Note that our _SDT_NARG is called with an extra 0 arg that's not + counted, so we don't have to worry about the behavior of macros + called without any arguments. */ + +#define _SDT_NARG(...) __SDT_NARG(__VA_ARGS__, 12,11,10,9,8,7,6,5,4,3,2,1,0) +#define __SDT_NARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, N, ...) N +#ifdef SDT_USE_VARIADIC +#define _SDT_PROBE_N(provider, name, N, ...) \ + _SDT_PROBE(provider, name, N, (__VA_ARGS__)) +#define STAP_PROBEV(provider, name, ...) \ + _SDT_PROBE_N(provider, name, _SDT_NARG(0, ##__VA_ARGS__), ##__VA_ARGS__) +#endif + +/* These macros are for use in asm statements. You must compile + with -std=gnu99 or -std=c99 to use the STAP_PROBE_ASM macro. + + The STAP_PROBE_ASM macro generates a quoted string to be used in the + template portion of the asm statement, concatenated with strings that + contain the actual assembly code around the probe site. + + For example: + + asm ("before\n" + STAP_PROBE_ASM(provider, fooprobe, %eax 4(%esi)) + "after"); + + emits the assembly code for "before\nafter", with a probe in between. + The probe arguments are the %eax register, and the value of the memory + word located 4 bytes past the address in the %esi register. Note that + because this is a simple asm, not a GNU C extended asm statement, these + % characters do not need to be doubled to generate literal %reg names. + + In a GNU C extended asm statement, the probe arguments can be specified + using the macro STAP_PROBE_ASM_TEMPLATE(n) for n arguments. The paired + macro STAP_PROBE_ASM_OPERANDS gives the C values of these probe arguments, + and appears in the input operand list of the asm statement. For example: + + asm ("someinsn %0,%1\n" // %0 is output operand, %1 is input operand + STAP_PROBE_ASM(provider, fooprobe, STAP_PROBE_ASM_TEMPLATE(3)) + "otherinsn %[namedarg]" + : "r" (outvar) + : "g" (some_value), [namedarg] "i" (1234), + STAP_PROBE_ASM_OPERANDS(3, some_value, some_ptr->field, 1234)); + + This is just like writing: + + STAP_PROBE3(provider, fooprobe, some_value, some_ptr->field, 1234)); + + but the probe site is right between "someinsn" and "otherinsn". + + The probe arguments in STAP_PROBE_ASM can be given as assembly + operands instead, even inside a GNU C extended asm statement. + Note that these can use operand templates like %0 or %[name], + and likewise they must write %%reg for a literal operand of %reg. */ + +#define _SDT_ASM_BODY_1(p,n,...) _SDT_ASM_BODY(p,n,_SDT_ASM_SUBSTR,(__VA_ARGS__)) +#define _SDT_ASM_BODY_2(p,n,...) _SDT_ASM_BODY(p,n,/*_SDT_ASM_STRING */,__VA_ARGS__) +#define _SDT_ASM_BODY_N2(p,n,no,...) _SDT_ASM_BODY_ ## no(p,n,__VA_ARGS__) +#define _SDT_ASM_BODY_N1(p,n,no,...) _SDT_ASM_BODY_N2(p,n,no,__VA_ARGS__) +#define _SDT_ASM_BODY_N(p,n,...) _SDT_ASM_BODY_N1(p,n,_SDT_NARG(0, __VA_ARGS__),__VA_ARGS__) + +#if __STDC_VERSION__ >= 199901L +# define STAP_PROBE_ASM(provider, name, ...) \ + _SDT_ASM_BODY_N(provider, name, __VA_ARGS__) \ + _SDT_ASM_BASE +# define STAP_PROBE_ASM_OPERANDS(n, ...) _SDT_ASM_OPERANDS_##n(__VA_ARGS__) +#else +# define STAP_PROBE_ASM(provider, name, args) \ + _SDT_ASM_BODY(provider, name, /* _SDT_ASM_STRING */, (args)) \ + _SDT_ASM_BASE +#endif +#define STAP_PROBE_ASM_TEMPLATE(n) _SDT_ASM_TEMPLATE_##n,"use _SDT_ASM_TEMPLATE_" + + +/* DTrace compatible macro names. */ +#define DTRACE_PROBE(provider,probe) \ + STAP_PROBE(provider,probe) +#define DTRACE_PROBE1(provider,probe,parm1) \ + STAP_PROBE1(provider,probe,parm1) +#define DTRACE_PROBE2(provider,probe,parm1,parm2) \ + STAP_PROBE2(provider,probe,parm1,parm2) +#define DTRACE_PROBE3(provider,probe,parm1,parm2,parm3) \ + STAP_PROBE3(provider,probe,parm1,parm2,parm3) +#define DTRACE_PROBE4(provider,probe,parm1,parm2,parm3,parm4) \ + STAP_PROBE4(provider,probe,parm1,parm2,parm3,parm4) +#define DTRACE_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) \ + STAP_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) +#define DTRACE_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) \ + STAP_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) +#define DTRACE_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \ + STAP_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) +#define DTRACE_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \ + STAP_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) +#define DTRACE_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \ + STAP_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) +#define DTRACE_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \ + STAP_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) +#define DTRACE_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) \ + STAP_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) +#define DTRACE_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) \ + STAP_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) + + +#endif /* sys/sdt.h */ \ No newline at end of file diff --git a/library/setjmp/setjmp.c b/library/setjmp/setjmp.c new file mode 100644 index 00000000..2f655a77 --- /dev/null +++ b/library/setjmp/setjmp.c @@ -0,0 +1,39 @@ +/* + * $Id: stdlib_setjmp.c,v 1.6 2010-10-20 13:50:17 clib2devs Exp $ + */ + +__asm(" \n\ + \n\ + .text \n\ + .align 2 \n\ + \n\ + .globl setjmp \n\ + \n\ +setjmp: \n\ + \n\ + mflr r10 \n\ + mfcr r11 \n\ + mr r12, r1 \n\ + stmw r10, 0(r3) \n\ + stfd f14, 88(r3) \n\ + stfd f15, 96(r3) \n\ + stfd f16, 104(r3) \n\ + stfd f17, 112(r3) \n\ + stfd f18, 120(r3) \n\ + stfd f19, 128(r3) \n\ + stfd f20, 136(r3) \n\ + stfd f21, 144(r3) \n\ + stfd f22, 152(r3) \n\ + stfd f23, 160(r3) \n\ + stfd f24, 168(r3) \n\ + stfd f25, 176(r3) \n\ + stfd f26, 184(r3) \n\ + stfd f27, 192(r3) \n\ + stfd f28, 200(r3) \n\ + stfd f29, 208(r3) \n\ + stfd f30, 216(r3) \n\ + stfd f31, 224(r3) \n\ + li r3, 0 \n\ + blr \n\ + \n\ +"); diff --git a/library/setjmp/sigjmp.c b/library/setjmp/sigjmp.c new file mode 100644 index 00000000..fc177644 --- /dev/null +++ b/library/setjmp/sigjmp.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1992-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _SIGNAL_HEADERS_H +#include "signal_headers.h" +#endif /* _SIGNAL_HEADERS_H */ + +/* This function is called by the `sigsetjmp' macro + before doing a `__setjmp' on ENV[0].__jmpbuf. + Always return zero. */ + +int +__sigjmp_save(sigjmp_buf env, int savemask) { + ENTER(); + SHOWVALUE(savemask); + env[0].__mask_was_saved = (savemask + && sigprocmask(SIG_BLOCK, (sigset_t *) NULL, + (sigset_t * ) & env[0].__saved_mask) == 0); + + SHOWVALUE(env[0].__mask_was_saved); + RETURN(0); + return 0; +} diff --git a/library/setjmp/siglongjmp.c b/library/setjmp/siglongjmp.c new file mode 100644 index 00000000..24bc291e --- /dev/null +++ b/library/setjmp/siglongjmp.c @@ -0,0 +1,21 @@ +/* + * $Id: stdlib_siglongjmp.c,v 1.0 2023-02-28 14:12:15 clib2devs Exp $ +*/ + +#ifndef _SIGNAL_HEADERS_H +#include "signal_headers.h" +#endif /* _SIGNAL_HEADERS_H */ + +void siglongjmp(sigjmp_buf env, int val) { + ENTER(); + SHOWVALUE(val); + + if (env[0].__mask_was_saved) + /* Restore the saved signal mask. */ + (void) sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (sigset_t *) NULL); + + SHOWVALUE(env[0].__mask_was_saved); + /* Call the machine-dependent function to restore machine state. */ + _longjmp(env, val ?: 1); + LEAVE(); +} diff --git a/library/setjmp/sigsetjmp-common.S b/library/setjmp/sigsetjmp-common.S new file mode 100644 index 00000000..6d0335e3 --- /dev/null +++ b/library/setjmp/sigsetjmp-common.S @@ -0,0 +1,77 @@ +/* setjmp for PowerPC. + Copyright (C) 1995-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include "../cpu/4xx/ppc4xx.inc" +#include "stap-probe.h" + +#define _ASM +#ifdef __NO_VMX__ +/* The following definitions are needed by ASM implementations of the old (novmx) __longjmp/__setjmp functions. */ +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total. */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total. */ +# define JB_SIZE (58 * 4) +#else +# define JB_GPR1 0 /* Also known as the stack pointer */ +# define JB_GPR2 1 +# define JB_LR 2 /* The address we will return to */ +# define JB_GPRS 3 /* GPRs 14 through 31 are saved, 18 in total. */ +# define JB_CR 21 /* Condition code registers. */ +# define JB_FPRS 22 /* FPRs 14 through 31 are saved, 18*2 words total. */ +# define JB_SIZE ((64 + (12 * 4)) * 4) +# define JB_VRSAVE 62 +# define JB_VRS 64 +#endif + +function_prolog(_setjmp) + li r4,0 /* Set second argument to 0. */ + b __sigsetjmp@local +function_epilog(_setjmp) + +function_prolog(__sigsetjmp_symbol) + stw r1,(JB_GPR1*4)(3) + mflr r0 + /* setjmp probe expects longjmp first argument (4@3), second argument + (-4@4), and target address (4@0), respectively. */ + LIBC_PROBE (setjmp, 3, 4@3, -4@4, 4@0) + stw r14,((JB_GPRS+14-14)*4)(3) + stw r0,(JB_LR*4)(3) + stw r15,((JB_GPRS+15-14)*4)(3) + mfcr r0 + stw r16,((JB_GPRS+16-14)*4)(3) + stw r0,(JB_CR*4)(3) + stw r17,((JB_GPRS+17-14)*4)(3) + stw r18,((JB_GPRS+18-14)*4)(3) + stw r19,((JB_GPRS+19-14)*4)(3) + stw r20,((JB_GPRS+20-14)*4)(3) + stw r21,((JB_GPRS+21-14)*4)(3) + stw r22,((JB_GPRS+22-14)*4)(3) + stw r23,((JB_GPRS+23-14)*4)(3) + stw r24,((JB_GPRS+24-14)*4)(3) + stw r25,((JB_GPRS+25-14)*4)(3) + stw r26,((JB_GPRS+26-14)*4)(3) + stw r27,((JB_GPRS+27-14)*4)(3) + stw r28,((JB_GPRS+28-14)*4)(3) + stw r29,((JB_GPRS+29-14)*4)(3) + stw r30,((JB_GPRS+30-14)*4)(3) + stw r31,((JB_GPRS+31-14)*4)(3) + b __sigjmp_save_symbol@local +function_epilog(__sigsetjmp_symbol) diff --git a/library/setjmp/sigsetjmp.S b/library/setjmp/sigsetjmp.S new file mode 100644 index 00000000..b2a9d82b --- /dev/null +++ b/library/setjmp/sigsetjmp.S @@ -0,0 +1,25 @@ +/* non altivec (old) version of setjmp for PowerPC. + Copyright (C) 1995-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#define __NO_VMX__ +#undef __sigsetjmp_symbol +#undef __sigjmp_save_symbol +#undef JB_SIZE +#define __sigsetjmp_symbol __sigsetjmp +#define __sigjmp_save_symbol __sigjmp_save +#include "sigsetjmp-common.S" diff --git a/library/setjmp/stap-probe.h b/library/setjmp/stap-probe.h new file mode 100644 index 00000000..1db0e525 --- /dev/null +++ b/library/setjmp/stap-probe.h @@ -0,0 +1,78 @@ +/* Macros for defining Systemtap static probe points. + Copyright (C) 2012-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _STAP_PROBE_H +#define _STAP_PROBE_H 1 + +#define USE_STAP_PROBE 1 +#ifdef USE_STAP_PROBE + +# include "sdt.h" + +/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn). + + Without USE_STAP_PROBE, that does nothing but evaluates all + its arguments (to prevent bit rot, unlike e.g. assert). + + Systemtap's header defines the macros STAP_PROBE (provider, name) and + STAP_PROBEn (provider, name, arg1, ..., argn). For "provider" we paste + in MODULE_NAME (libc, libpthread, etc.) automagically. + + The format of the arg parameters is discussed here: + + https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + + The precise details of how register names are specified is + architecture specific and can be found in the gdb and SystemTap + source code. */ + +# define LIBC_PROBE(name, n, ...) \ + LIBC_PROBE_1 (MODULE_NAME, name, n, ## __VA_ARGS__) + +# define LIBC_PROBE_1(lib, name, n, ...) \ + STAP_PROBE##n (lib, name, ## __VA_ARGS__) + +# define STAP_PROBE0 STAP_PROBE + +# define LIBC_PROBE_ASM(name, template) \ + STAP_PROBE_ASM (MODULE_NAME, name, template) + +# define LIBC_PROBE_ASM_OPERANDS STAP_PROBE_ASM_OPERANDS + +#else /* Not USE_STAP_PROBE. */ + +# ifndef __ASSEMBLER__ +/* Evaluate all the arguments and verify that N matches their number. */ +# define LIBC_PROBE(name, n, ...) STAP_PROBE##n (__VA_ARGS__) + +# define STAP_PROBE0() do {} while (0) +# define STAP_PROBE1(a1) do {} while (0) +# define STAP_PROBE2(a1, a2) do {} while (0) +# define STAP_PROBE3(a1, a2, a3) do {} while (0) +# define STAP_PROBE4(a1, a2, a3, a4) do {} while (0) + +# else +# define LIBC_PROBE(name, n, ...) /* Nothing. */ +# endif + +# define LIBC_PROBE_ASM(name, template) /* Nothing. */ +# define LIBC_PROBE_ASM_OPERANDS(n, ...) /* Nothing. */ + +#endif /* USE_STAP_PROBE. */ + +#endif /* stap-probe.h */ diff --git a/library/shcrtbegin.c b/library/shcrtbegin.c index ecd196dd..0fd295d6 100755 --- a/library/shcrtbegin.c +++ b/library/shcrtbegin.c @@ -3,6 +3,7 @@ */ #include +#include "debug.h" void __shlib_call_constructors(void); void __shlib_call_destructors(void); @@ -20,29 +21,33 @@ void __shlib_call_destructors(void); * symbol in sh/crtbegin.o, where they are defined. */ -typedef void (*func_ptr) (void); - -static func_ptr __CTOR_LIST__[1] __attribute__((used, section(".ctors"), aligned(sizeof(func_ptr)))) = { (func_ptr) (-1) };; -static func_ptr __DTOR_LIST__[1] __attribute__((used, section(".dtors"), aligned(sizeof(func_ptr)))) = { (func_ptr) (-1) };; +static void (*__CTOR_LIST__[1])(void) __attribute__((section(".ctors"))); +static void (*__DTOR_LIST__[1])(void) __attribute__((section(".dtors"))); void __shlib_call_constructors(void) { extern void (*__CTOR_LIST__[])(void); int i = 0; + ENTER(); while (__CTOR_LIST__[i + 1]) { i++; } - + SHOWVALUE(i); while (i > 0) { + D(("Calling constructor %ld", i)); __CTOR_LIST__[i--](); } + LEAVE(); } void __shlib_call_destructors(void) { extern void (*__DTOR_LIST__[])(void); int i = 1; + ENTER(); while (__DTOR_LIST__[i]) { + D(("Calling destructor %ld", i)); __DTOR_LIST__[i++](); } + LEAVE(); } diff --git a/library/shcrtend.c b/library/shcrtend.c index 6f00bab0..cdd0681d 100755 --- a/library/shcrtend.c +++ b/library/shcrtend.c @@ -2,7 +2,5 @@ * $Id: shcrtend.c,v 1.1 2023-02-18 19:35:03 clib2devs Exp $ */ -typedef void (*func_ptr)(void); - -static func_ptr __CTOR_END__[1] __attribute__(( used, section(".ctors"), aligned(sizeof(func_ptr)))) = {(func_ptr) 0}; -static func_ptr __DTOR_END__[1] __attribute__(( used, section(".dtors"), aligned(sizeof(func_ptr)))) = {(func_ptr) 0}; +static void (*__CTOR_LIST__[1])(void) __attribute__((used, section(".ctors"))); +static void (*__DTOR_LIST__[1])(void) __attribute__((used, section(".dtors"))); diff --git a/library/socket/gethostbyaddr.c b/library/socket/gethostbyaddr.c index 21214265..2f69c6e5 100644 --- a/library/socket/gethostbyaddr.c +++ b/library/socket/gethostbyaddr.c @@ -42,6 +42,6 @@ gethostbyaddr(const void *addr, socklen_t len, int type) { __check_abort(); - RETURN(err ? 0 : h); + RETURN(err ? 0 : 1); return err ? 0 : h; } diff --git a/library/socket/init_exit.c b/library/socket/init_exit.c index 17048915..60bd663b 100644 --- a/library/socket/init_exit.c +++ b/library/socket/init_exit.c @@ -14,7 +14,6 @@ #include "stdlib_constructor.h" #endif /* _STDLIB_CONSTRUCTOR_H */ -/****************************************************************************/ struct Library *NOCOMMON __SocketBase; struct SocketIFace *NOCOMMON __ISocket; @@ -22,20 +21,15 @@ struct SocketIFace *NOCOMMON __ISocket; int NOCOMMON h_errno; /* Call-back hook for use with SBTC_ERROR_HOOK */ -struct _ErrorHookMsg -{ - ULONG ehm_Size; /* Size of this data structure; this - must be >= 12 */ - ULONG ehm_Action; /* See below for a list of definitions */ - - LONG ehm_Code; /* The error code to use */ +struct _ErrorHookMsg { + ULONG ehm_Size; /* Size of this data structure; this must be >= 12 */ + ULONG ehm_Action; /* See below for a list of definitions */ + LONG ehm_Code; /* The error code to use */ }; /* Which action the hook is to perform */ -#define EHMA_Set_errno 1 /* Set the local 'errno' to what is \ - found in ehm_Code */ -#define EHMA_Set_h_errno 2 /* Set the local 'h_errno' to what is \ - found in ehm_Code */ +#define EHMA_Set_errno 1 /* Set the local 'errno' to what is found in ehm_Code */ +#define EHMA_Set_h_errno 2 /* Set the local 'h_errno' to what is found in ehm_Code */ /****************************************************************************/ @@ -50,174 +44,157 @@ BOOL NOCOMMON __thread_safe_errno_h_errno; the library will also be the one will eventually call the hook function. You can key off this in your own __set_errno() or __set_h_errno() functions, setting a Process-specific set of variables. */ -STATIC LONG ASM - error_hook_function( - REG(a0, struct Hook *unused_hook), - REG(a2, APTR unused_reserved), - REG(a1, struct _ErrorHookMsg *ehm)) -{ +static LONG ASM +error_hook_function( + REG(a0, struct Hook *unused_hook), + REG(a2, APTR unused_reserved), + REG(a1, struct _ErrorHookMsg *ehm) +) { (void) (unused_hook); (void) (unused_reserved); - if (ehm != NULL && ehm->ehm_Size >= 12) - { - if (ehm->ehm_Action == EHMA_Set_errno) - __set_errno(ehm->ehm_Code); - else if (ehm->ehm_Action == EHMA_Set_h_errno) - __set_h_errno(ehm->ehm_Code); - } + if (ehm != NULL && ehm->ehm_Size >= 12) { + if (ehm->ehm_Action == EHMA_Set_errno) + __set_errno(ehm->ehm_Code); + else if (ehm->ehm_Action == EHMA_Set_h_errno) + __set_h_errno(ehm->ehm_Code); + } - return (0); + return (0); } -STATIC struct Hook error_hook = - { - {NULL, NULL}, - (HOOKFUNC)error_hook_function, - (HOOKFUNC)NULL, - NULL}; - -SOCKET_DESTRUCTOR(socket_exit) -{ - ENTER(); - - /* Disable ^C checking. */ - if (__SocketBase != NULL) - { - struct TagItem tags[2]; - - tags[0].ti_Tag = SBTM_SETVAL(SBTC_BREAKMASK); - tags[0].ti_Data = 0; - tags[1].ti_Tag = TAG_END; - - __SocketBaseTagList(tags); - } - - /* - * Careful: if this function is ever invoked, it must make sure that - * the socket file descriptors are invalidated. If that - * does not happen, the stdio cleanup function will - * crash (with bells on). - */ - __close_all_files(); - if (__ISocket != NULL) - { - DropInterface((struct Interface *)__ISocket); - __ISocket = NULL; - } - if (__SocketBase != NULL) - { - CloseLibrary(__SocketBase); - __SocketBase = NULL; - } - - LEAVE(); +STATIC struct Hook error_hook = { + {NULL, NULL}, + (HOOKFUNC) error_hook_function, + (HOOKFUNC) NULL, + NULL +}; + +SOCKET_DESTRUCTOR(socket_exit) { + ENTER(); + + /* Disable ^C checking. */ + if (__SocketBase != NULL) { + struct TagItem tags[2]; + + tags[0].ti_Tag = SBTM_SETVAL(SBTC_BREAKMASK); + tags[0].ti_Data = 0; + tags[1].ti_Tag = TAG_END; + + __SocketBaseTagList(tags); + } + + /* + * Careful: if this function is ever invoked, it must make sure that + * the socket file descriptors are invalidated. If that + * does not happen, the stdio cleanup function will + * crash (with bells on). + */ + __close_all_files(); + if (__ISocket != NULL) { + DropInterface((struct Interface *) __ISocket); + __ISocket = NULL; + } + if (__SocketBase != NULL) { + CloseLibrary(__SocketBase); + __SocketBase = NULL; + } + + LEAVE(); } -/****************************************************************************/ +SOCKET_CONSTRUCTOR(socket_init) { + struct TagItem tags[5]; + BOOL success = FALSE; + LONG status; + + ENTER(); + + /* bsdsocket.library V3 is sufficient for all the tasks we may have to perform. */ + __SocketBase = OpenLibrary("bsdsocket.library", 3); + if (__SocketBase != NULL) { + __ISocket = (struct SocketIFace *) GetInterface(__SocketBase, "main", 1, 0); + if (__ISocket == NULL) { + CloseLibrary(__SocketBase); + __SocketBase = NULL; + } + } + + if (__SocketBase == NULL) { + SHOWMSG("bsdsocket.library V3 didn't open"); + __show_error("\"bsdsocket.library\" V3 could not be opened."); + goto out; + } + + /* Wire the library's errno variable to our local errno. */ + tags[0].ti_Tag = SBTM_SETVAL(SBTC_ERRNOLONGPTR); + tags[0].ti_Data = (ULONG)&errno; + + /* Also enable ^C checking if desired. */ + tags[1].ti_Tag = SBTM_SETVAL(SBTC_BREAKMASK); + + if (__check_abort_enabled) + tags[1].ti_Data = __break_signal_mask; + else + tags[1].ti_Data = 0; + + tags[2].ti_Tag = SBTM_SETVAL(SBTC_LOGTAGPTR); + tags[2].ti_Data = (ULONG)__program_name; + + /* Wire the library's h_errno variable to our local h_errno. */ + tags[3].ti_Tag = SBTM_SETVAL(SBTC_HERRNOLONGPTR); + tags[3].ti_Data = (ULONG)&h_errno; + + tags[4].ti_Tag = TAG_END; + + status = __SocketBaseTagList(tags); + if (status != 0) { + SHOWMSG("couldn't initialize the library"); -SOCKET_CONSTRUCTOR(socket_init) -{ - struct TagItem tags[5]; - BOOL success = FALSE; - LONG status; - - ENTER(); - - /* bsdsocket.library V3 is sufficient for all the tasks we - may have to perform. */ - __SocketBase = OpenLibrary("bsdsocket.library", 3); - if (__SocketBase != NULL) - { - __ISocket = (struct SocketIFace *)GetInterface(__SocketBase, "main", 1, 0); - if (__ISocket == NULL) - { - CloseLibrary(__SocketBase); - __SocketBase = NULL; - } - } - - if (__SocketBase == NULL) - { - SHOWMSG("bsdsocket.library V3 didn't open"); - - __show_error("\"bsdsocket.library\" V3 could not be opened."); - goto out; - } - - /* Wire the library's errno variable to our local errno. */ - tags[0].ti_Tag = SBTM_SETVAL(SBTC_ERRNOLONGPTR); - tags[0].ti_Data = (ULONG)&errno; - - /* Also enable ^C checking if desired. */ - tags[1].ti_Tag = SBTM_SETVAL(SBTC_BREAKMASK); - - if (__check_abort_enabled) - tags[1].ti_Data = __break_signal_mask; - else - tags[1].ti_Data = 0; - - tags[2].ti_Tag = SBTM_SETVAL(SBTC_LOGTAGPTR); - tags[2].ti_Data = (ULONG)__program_name; - - /* Wire the library's h_errno variable to our local h_errno. */ - tags[3].ti_Tag = SBTM_SETVAL(SBTC_HERRNOLONGPTR); - tags[3].ti_Data = (ULONG)&h_errno; - - tags[4].ti_Tag = TAG_END; - - status = __SocketBaseTagList(tags); - if (status != 0) - { - SHOWMSG("couldn't initialize the library"); - - __show_error("\"bsdsocket.library\" could not be initialized."); - goto out; - } + __show_error("\"bsdsocket.library\" could not be initialized."); + goto out; + } /* In the thread-safe library we try to enable two features which so - far only the Roadshow TCP/IP stack supports: allow more than one - Process to use the same bsdsocket.library base and to propagate - changes to the errno and h_errno variable through a call-back - hook. If either of these features are supported can be checked - by looking at the global __can_share_socket_library_base and - __thread_safe_errno_h_errno variables. */ - if (__SocketBase->lib_Version >= 4) - { - tags[0].ti_Tag = SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES); - tags[0].ti_Data = TRUE; + far only the Roadshow TCP/IP stack supports: allow more than one + Process to use the same bsdsocket.library base and to propagate + changes to the errno and h_errno variable through a call-back + hook. If either of these features are supported can be checked + by looking at the global __can_share_socket_library_base and + __thread_safe_errno_h_errno variables. */ + if (__SocketBase->lib_Version >= 4) { + tags[0].ti_Tag = SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES); + tags[0].ti_Data = TRUE; - tags[1].ti_Tag = TAG_END; + tags[1].ti_Tag = TAG_END; - if (__SocketBaseTagList(tags) == 0) - __can_share_socket_library_base = TRUE; + if (__SocketBaseTagList(tags) == 0) + __can_share_socket_library_base = TRUE; - if (__can_share_socket_library_base) - { - tags[0].ti_Tag = SBTM_SETVAL(SBTC_ERROR_HOOK); - tags[0].ti_Data = (ULONG)&error_hook; + if (__can_share_socket_library_base) { + tags[0].ti_Tag = SBTM_SETVAL(SBTC_ERROR_HOOK); + tags[0].ti_Data = (ULONG) &error_hook; - tags[1].ti_Tag = TAG_END; + tags[1].ti_Tag = TAG_END; - if (__SocketBaseTagList(tags) == 0) - __thread_safe_errno_h_errno = TRUE; - } - } + if (__SocketBaseTagList(tags) == 0) + __thread_safe_errno_h_errno = TRUE; + } + } - /* Check if this program was launched as a server by the Internet - superserver. */ - if (CANNOT __obtain_daemon_message()) - goto out; + /* Check if this program was launched as a server by the Internet superserver. */ + if (CANNOT __obtain_daemon_message()) + goto out; - success = TRUE; + success = TRUE; out: - SHOWVALUE(success); - LEAVE(); + SHOWVALUE(success); + LEAVE(); - if (success) - CONSTRUCTOR_SUCCEED(); - else - CONSTRUCTOR_FAIL(); + if (success) + CONSTRUCTOR_SUCCEED(); + else + CONSTRUCTOR_FAIL(); } diff --git a/library/socket/select_signal.c b/library/socket/select_signal.c index 29b6e4fc..c22e9398 100644 --- a/library/socket/select_signal.c +++ b/library/socket/select_signal.c @@ -722,8 +722,6 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s * if the write will block. */ if (FLAG_IS_SET(fd->fd_Flags, FDF_WRITE)) { - assert(FLAG_IS_CLEAR(fd->fd_Flags, FDF_IS_SOCKET)); - got_output = TRUE; } if (FLAG_IS_SET(fd->fd_Flags, FDF_POLL)) { @@ -814,13 +812,22 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s goto out; } } - - if (timeout != NULL) { + BOOL pollMode = FALSE; + if (timeout != NULL && (timeout->tv_sec > 0 || timeout->tv_usec > 0)) { struct DateStamp datestamp_timeout; DateStamp(&stop_when); add_dates(&stop_when, timeval_to_datestamp(&datestamp_timeout, timeout)); - } else { + } + /* If timeout is != NULL but seconds and useconds are == 0 we need to act like + * an FDF_POLL so, set gotInput = TRUE and use WaitChar to see if we get really a char. + * If so, exit from select but set gotInput = FALSE after increasing result value. + * This will clear FD and the poll will work correctly + */ + else if (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0) { + pollMode = TRUE; + } + else { memset(&stop_when, 0, sizeof(stop_when)); } @@ -828,6 +835,7 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s __check_abort(); Delay(1); + BOOL gotChar = FALSE; result = 0; for (i = 0; i < total_file_fd; i++) { @@ -838,19 +846,30 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s if (file_read_fds != NULL && FD_ISSET(i, file_read_fds)) { if (FLAG_IS_SET(fd->fd_Flags, FDF_READ)) { BPTR readFile = i == STDIN_FILENO ? Input() : fd->fd_File; - - assert(FLAG_IS_CLEAR(fd->fd_Flags, FDF_IS_SOCKET) && FLAG_IS_CLEAR(fd->fd_Flags, FDF_STDIO)); - + SHOWVALUE(FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS)); + if (pollMode) { + /* Set FDF_POLL to file */ + SET_FLAG(fd->fd_Flags, FDF_POLL); + } /* Check first if this is a POLL/TERMIOS FD * In this case don't wait for char */ - if (FLAG_IS_SET(fd->fd_Flags, FDF_POLL)) { + if (FLAG_IS_SET(fd->fd_Flags, FDF_POLL) && !pollMode) { + SHOWVALUE("FLAG_IS_SET(fd->fd_Flags, FDF_POLL) && !pollMode"); got_input = TRUE; } + else if (FLAG_IS_SET(fd->fd_Flags, FDF_POLL) && pollMode) { + SHOWVALUE("FLAG_IS_SET(fd->fd_Flags, FDF_POLL) && pollMode"); + got_input = TRUE; + gotChar = WaitForChar(readFile, 1); + } else if (FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS)) { + SHOWVALUE("FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS"); struct termios *tios = fd->fd_Aux; - SetMode(readFile, DOSTRUE); - if (FLAG_IS_CLEAR(tios->c_cflag, ICANON) && FLAG_IS_SET(tios->c_cflag, NCURSES)) { + SHOWVALUE(FLAG_IS_SET(tios->c_lflag, NCURSES)); + SHOWVALUE(FLAG_IS_CLEAR(tios->c_lflag, ICANON)); + + if (FLAG_IS_CLEAR(tios->c_lflag, ICANON) && FLAG_IS_SET(tios->c_lflag, NCURSES)) { got_input = TRUE; } else { @@ -860,17 +879,10 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s } } else if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) { - if (i == STDIN_FILENO) { - /* For STDIN stream, ask input. */ - if (WaitForChar(readFile, 1)) { - got_input = TRUE; - } - } - else { - /* For an interactive stream, we simply ask. */ - if (WaitForChar(readFile, 1)) { - got_input = TRUE; - } + SHOWVALUE("FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE"); + SHOWVALUE(i); + if (WaitForChar(readFile, 1)) { + got_input = TRUE; } } else { struct ExamineData *fib = ExamineObjectTags(EX_FileHandleInput, fd->fd_File, TAG_DONE); @@ -895,10 +907,18 @@ __select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, s } } } + SHOWVALUE(got_input); + SHOWVALUE(got_output); if (got_input || got_output) result++; + /* After increasing result check if we get a char and we are in POLL mode + * If we didn't get any char set back got_input to FALSE + */ + if (pollMode && !gotChar) + got_input = FALSE; + if (file_read_fds != NULL && NOT got_input) { FD_CLR(i, file_read_fds); } diff --git a/library/stdio/fclose.c b/library/stdio/fclose.c index d7012584..8a9f9a0b 100644 --- a/library/stdio/fclose.c +++ b/library/stdio/fclose.c @@ -22,6 +22,8 @@ fclose(FILE *stream) { assert(stream != NULL); + DECLARE_UTILITYBASE(); + __check_abort(); if (stream == NULL) { @@ -83,12 +85,16 @@ fclose(FILE *stream) { } /* Get rid of any custom file buffer allocated. */ - if (file->iob_CustomBuffer != NULL) - free(file->iob_CustomBuffer); + if (file->iob_CustomBuffer != NULL) { + SHOWMSG("Delete allocated buffer"); + FreeVec(file->iob_CustomBuffer); + } /* Free the lock semaphore now. */ + SHOWMSG("Delete iob_Lock"); __delete_semaphore(file->iob_Lock); + SHOWMSG("Clear file structure"); memset(file, 0, sizeof(*file)); out: diff --git a/library/stdio/fdhookentry.c b/library/stdio/fdhookentry.c index 8f197f27..c0cd3783 100644 --- a/library/stdio/fdhookentry.c +++ b/library/stdio/fdhookentry.c @@ -125,8 +125,7 @@ int64_t __fd_hook_entry(struct fd *fd, struct file_action_message *fam) { } } - D(("write %ld bytes to position %ld from 0x%08lx", fam->fam_Size, GetFilePosition( - file), fam->fam_Data)); + D(("write %ld bytes to position %ld from 0x%08lx", fam->fam_Size, GetFilePosition(file), fam->fam_Data)); result = Write(file, fam->fam_Data, fam->fam_Size); if (result == -1) { @@ -155,8 +154,13 @@ int64_t __fd_hook_entry(struct fd *fd, struct file_action_message *fam) { __remove_fd_alias(fd); } else if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_STDIO)) { /* Should we reset this file into line buffered mode? */ - if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) - SetMode(fd->fd_File, DOSFALSE); + if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) { + /* Set canonical mode. */ + if (fam->fam_DOSMode == DOSTRUE) { + SetMode(fd->fd_File, DOSFALSE); + fam->fam_DOSMode = DOSFALSE; + } + } /* Are we allowed to close this file? */ if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_NO_CLOSE)) { @@ -401,8 +405,6 @@ int64_t __fd_hook_entry(struct fd *fd, struct file_action_message *fam) { } fd->fd_Position = new_position; - - printf("fd->fd_Position = %lld\n", fd->fd_Position); } result = new_position; diff --git a/library/stdio/file_init.c b/library/stdio/file_init.c index 6c29f5e1..a5ea4727 100644 --- a/library/stdio/file_init.c +++ b/library/stdio/file_init.c @@ -36,8 +36,7 @@ struct WBStartup *NOCOMMON __WBenchMsg; /* CPU cache line size; used to align I/O buffers for best performance. */ ULONG __cache_line_size = 32; -FILE_DESTRUCTOR(workbench_exit) -{ +FILE_DESTRUCTOR(workbench_exit) { ENTER(); /* Now clean up after the streams set up for Workbench startup... */ @@ -143,8 +142,7 @@ wb_file_init(void) { return (result); } -FILE_CONSTRUCTOR(stdio_file_init) -{ +FILE_CONSTRUCTOR(stdio_file_init) { struct SignalSemaphore *stdio_lock; struct SignalSemaphore *fd_lock; BPTR default_file; @@ -159,7 +157,7 @@ FILE_CONSTRUCTOR(stdio_file_init) uint32 physical_alignment = 0; GetCPUInfoTags(GCIT_CacheLineSize, &physical_alignment, TAG_DONE); - + SHOWVALUE(physical_alignment); if (__cache_line_size < physical_alignment) { __cache_line_size = physical_alignment; } @@ -198,7 +196,7 @@ FILE_CONSTRUCTOR(stdio_file_init) } /* Allocate a little more memory than necessary. */ - buffer = calloc(1, BUFSIZ + (__cache_line_size - 1)); + buffer = AllocVecTags(BUFSIZ + (__cache_line_size - 1), AVT_Type, MEMF_SHARED, AVT_ClearWithValue, 0, TAG_END); if (buffer == NULL) goto out; @@ -230,6 +228,7 @@ FILE_CONSTRUCTOR(stdio_file_init) i, iob_flags, stdio_lock); + } success = TRUE; diff --git a/library/stdio/fwrite.c b/library/stdio/fwrite.c index 7719a712..286e14b6 100644 --- a/library/stdio/fwrite.c +++ b/library/stdio/fwrite.c @@ -78,6 +78,7 @@ fwrite(const void *ptr, size_t element_size, size_t count, FILE *stream) { } switch (buffer_mode) { case IOBF_BUFFER_MODE_LINE: + SHOWMSG("IOBF_BUFFER_MODE_LINE"); assert(file->iob_BufferSize > 0); while (total_size > 0) { /* Is there still room in the write buffer to store @@ -133,6 +134,7 @@ fwrite(const void *ptr, size_t element_size, size_t count, FILE *stream) { } break; case IOBF_BUFFER_MODE_NONE: { + SHOWMSG("IOBF_BUFFER_MODE_NONE"); ssize_t num_bytes_written; /* We bypass the buffer entirely. */ @@ -146,6 +148,7 @@ fwrite(const void *ptr, size_t element_size, size_t count, FILE *stream) { } break; default: + SHOWMSG("IOBF_BUFFER_MODE_FULL"); assert(file->iob_BufferSize > 0); while (total_size > 0) { /* If there is more data to be written than the write buffer will hold @@ -187,6 +190,7 @@ fwrite(const void *ptr, size_t element_size, size_t count, FILE *stream) { } total_bytes_written += num_buffer_bytes; + SHOWVALUE(total_bytes_written); /* Stop as soon as no further data needs to be written. */ total_size -= num_buffer_bytes; @@ -207,7 +211,6 @@ fwrite(const void *ptr, size_t element_size, size_t count, FILE *stream) { } } - if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE) { if (__iob_write_buffer_is_valid(file)) { __flush_iob_write_buffer(file); diff --git a/library/stdio/initializeiob.c b/library/stdio/initializeiob.c index 4d48522b..3e8b12dd 100644 --- a/library/stdio/initializeiob.c +++ b/library/stdio/initializeiob.c @@ -31,5 +31,5 @@ __initialize_iob( iob->iob_Action = action_function; iob->iob_Lock = lock; iob->iob_Flags2 = 0; - memset (&iob->iob_mbState, 0, sizeof (_mbstate_t)); + memset(&iob->iob_mbState, 0, sizeof (_mbstate_t)); } diff --git a/library/stdio/iobhookentry.c b/library/stdio/iobhookentry.c index 65977d45..a325492a 100644 --- a/library/stdio/iobhookentry.c +++ b/library/stdio/iobhookentry.c @@ -7,26 +7,28 @@ #endif /* _STDIO_HEADERS_H */ int64_t -__iob_hook_entry( - struct iob *file_iob, - struct file_action_message *fam) -{ +__iob_hook_entry(struct iob *file_iob, struct file_action_message *fam) { struct fd *fd; int64_t result; assert(fam != NULL && file_iob != NULL); - switch (fam->fam_Action) - { + switch (fam->fam_Action) { case file_action_read: case file_action_write: case file_action_seek: case file_action_close: + SHOWVALUE(file_iob->iob_Descriptor); assert(file_iob->iob_Descriptor >= 0 && file_iob->iob_Descriptor < __num_fd); assert(__fd[file_iob->iob_Descriptor] != NULL); assert(FLAG_IS_SET(__fd[file_iob->iob_Descriptor]->fd_Flags, FDF_IN_USE)); + if (__fd[file_iob->iob_Descriptor] == NULL) { + fam->fam_Error = EBADF; + result = EOF; + break; + } /* When closing, we want to affect this very file descriptor and not the original one associated with an alias of it. */ if (fam->fam_Action == file_action_close) @@ -34,12 +36,9 @@ __iob_hook_entry( else fd = __get_file_descriptor(file_iob->iob_Descriptor); - if (fd == NULL) - { + if (fd == NULL) { fam->fam_Error = EBADF; - result = EOF; - break; } @@ -54,9 +53,7 @@ __iob_hook_entry( SHOWVALUE(fam->fam_Action); fam->fam_Error = EBADF; - result = EOF; - break; } diff --git a/library/stdio/openiob.c b/library/stdio/openiob.c index 606a08d1..5852aaa5 100644 --- a/library/stdio/openiob.c +++ b/library/stdio/openiob.c @@ -94,7 +94,7 @@ __open_iob(const char *filename, const char *mode, int file_descriptor, int slot SHOWMSG("allocating file buffer"); /* Allocate a little more memory than necessary. */ - buffer = calloc(1, BUFSIZ + (__cache_line_size - 1)); + buffer = AllocVecTags(BUFSIZ + (__cache_line_size - 1), AVT_Type, MEMF_SHARED, AVT_ClearWithValue); if (buffer == NULL) { SHOWMSG("that didn't work"); @@ -153,7 +153,7 @@ __open_iob(const char *filename, const char *mode, int file_descriptor, int slot out: if (buffer != NULL) - free(buffer); + FreeVec(buffer); __stdio_unlock(); diff --git a/library/stdio/printf.c b/library/stdio/printf.c index 0a2376b1..a7f0bc4d 100644 --- a/library/stdio/printf.c +++ b/library/stdio/printf.c @@ -10,9 +10,7 @@ int printf(const char *format, ...) { int result = EOF; va_list arg; - ENTER(); - SHOWSTRING(format); assert(format != NULL); @@ -22,10 +20,13 @@ printf(const char *format, ...) { goto out; } + __stdio_lock(); va_start(arg, format); result = vfprintf(stdout, format, arg); va_end(arg); + __stdio_unlock(); + out: RETURN(result); diff --git a/library/stdio/setvbuf.c b/library/stdio/setvbuf.c index 0e703252..dd36272c 100644 --- a/library/stdio/setvbuf.c +++ b/library/stdio/setvbuf.c @@ -97,7 +97,8 @@ setvbuf(FILE *stream, char *buf, int bufmode, size_t size) { /* Get rid of any buffer specially allocated for this stream. */ if (file->iob_CustomBuffer != NULL) { - free(file->iob_CustomBuffer); + SHOWMSG("Delete allocated buffer"); + FreeVec(file->iob_CustomBuffer); file->iob_CustomBuffer = NULL; } diff --git a/library/stdio/vfprintf.c b/library/stdio/vfprintf.c index 5a983405..9bfd4578 100644 --- a/library/stdio/vfprintf.c +++ b/library/stdio/vfprintf.c @@ -27,12 +27,11 @@ static void out_init_file(Out *out, FILE *f) { } static void out(Out *_out, const char *text, size_t l) { - size_t length = ((l > 0) ? (size_t) l : 0U); - if (!length) { return; } + if (_out->file != NULL) { const char *w = text; _out->buffer_pos += length; @@ -685,9 +684,6 @@ vfprintf(FILE *f, const char *format, va_list ap) { va_list ap2; int ret, nl_type[NL_ARGMAX] = {0}; union arg nl_arg[NL_ARGMAX]; - Out _out[1]; - out_init_file(_out, f); - va_copy(ap2, ap); ENTER(); SHOWPOINTER(f); @@ -695,6 +691,10 @@ vfprintf(FILE *f, const char *format, va_list ap) { __check_abort(); + Out _out[1]; + out_init_file(_out, f); + va_copy(ap2, ap); + // Check for error in format string before writing anything to file. if (printf_core(0, format, &ap2, nl_arg, nl_type) < 0) { va_end(ap2); diff --git a/library/stdlib/exit.c b/library/stdlib/exit.c index 65de3407..e1a07aff 100644 --- a/library/stdlib/exit.c +++ b/library/stdlib/exit.c @@ -10,6 +10,10 @@ #include "stdio_headers.h" #endif /* _STDIO_HEADERS_H */ +#include "aio/aio_misc.h" +#include "pthread/common.h" +#include "misc/clist.h" + int NOCOMMON __exit_value = RETURN_FAIL; jmp_buf NOCOMMON __exit_jmp_buf; @@ -32,36 +36,66 @@ _exit(int return_code) { ENTER(); SHOWVALUE(return_code); - /* If we have a previous timer running task stop it before raise SIGINT */ - if (__global_clib2->tmr_real_task) { - struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; - int32 pid, process; - - /* Block SIGALRM signal from raise */ - sigblock(SIGALRM); - /* Get itimer process ID */ - pid = __global_clib2->tmr_real_task->pr_ProcessID; - - Forbid(); - /* Scan for process */ - process = ProcessScan(&h, (CONST_APTR) pid, 0); - while (process > 0) { - /* Send a SIGBREAKF_CTRL_F signal until the timer task return in Wait and can get the signal */ - Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); + struct Task *task = FindTask(NULL); + if (&__global_clib2->self->pr_Task != task) { + SHOWMSG("NOT IN MAIN TASK"); + /* We are NOT in main task. Don't call exit here because + * we'll have pending processes. Try to send a CTRL_C + */ + struct Task *task = FindTask(NULL); + Signal(task, SIGBREAKF_CTRL_C); + LEAVE(); + } + else { + SHOWMSG("IN MAIN TASK"); + /* If we have a previous timer running task stop it before raise SIGINT */ + if (__global_clib2->tmr_real_task) { + struct Hook h = {{NULL, NULL}, (HOOKFUNC) hook_function, NULL, NULL}; + int32 pid, process; + + /* Block SIGALRM signal from raise */ + sigblock(SIGALRM); + /* Get itimer process ID */ + pid = __global_clib2->tmr_real_task->pr_ProcessID; + + Forbid(); + /* Scan for process */ process = ProcessScan(&h, (CONST_APTR) pid, 0); - usleep(100); + while (process > 0) { + /* Send a SIGBREAKF_CTRL_F signal until the timer task return in Wait and can get the signal */ + Signal((struct Task *) __global_clib2->tmr_real_task, SIGBREAKF_CTRL_F); + process = ProcessScan(&h, (CONST_APTR) pid, 0); + usleep(100); + } + Permit(); + WaitForChildExit(pid); + __global_clib2->tmr_real_task = NULL; } - Permit(); - WaitForChildExit(pid); - __global_clib2->tmr_real_task = NULL; - } - /* Dump all currently unwritten data, especially to the console. */ - __flush_all_files(-1); + /* Check if we have some aio threads */ + SHOWMSG("Check if we have some aio pthreads created"); + AioThread *aioThread; + SHOWMSG("Obtain aio semaphore"); + ObtainSemaphore(__global_clib2->__aio_lock); + int streams = __global_clib2->aio_threads->count(__global_clib2->aio_threads); + D(("AIO list has %ld items", streams)); + if (streams > 0) { + for (int i = 0; i < streams; i++) { + aioThread = __global_clib2->aio_threads->at(__global_clib2->aio_threads, i); + D(("Cancel AIO stream with filedes %ld", aioThread->fileDes)); + aio_cancel(aioThread->fileDes, aioThread->aiocbp); + Signal(aioThread->thread, SIGBREAKF_CTRL_C); + } + } + ReleaseSemaphore(__global_clib2->__aio_lock); - LEAVE(); + /* Dump all currently unwritten data, especially to the console. */ + __flush_all_files(-1); - longjmp(__exit_jmp_buf, 1); + LEAVE(); + + longjmp(__exit_jmp_buf, 1); + } } /* The C99 version of _exit(). */ @@ -73,6 +107,5 @@ _Exit(int return_code) { void exit(int return_code) { __exit_trap_trigger(); - _exit(return_code); } diff --git a/library/stdlib/main.c b/library/stdlib/main.c index b042e508..733b34c3 100644 --- a/library/stdlib/main.c +++ b/library/stdlib/main.c @@ -28,55 +28,22 @@ #include "shm_headers.h" #endif /* _SHM_HEADERS_H */ +#ifndef _TIME_HEADERS_H +#include "time_headers.h" +#endif /* _TIME_HEADERS_H */ + #include +#include "aio/aio_misc.h" extern int main(int arg_c, char **arg_v); -BOOL open_libraries(void); -void close_libraries(void); +extern BOOL open_libraries(void); +extern void close_libraries(void); /* This will be set to TRUE in case a stack overflow was detected. */ BOOL NOCOMMON __stack_overflow; extern struct _clib2 NOCOMMON *__global_clib2; -extern struct Library *__ElfBase; -extern struct ElfIFace *__IElf; - -#define MIN_OS_VERSION 52 - -void -close_libraries(void) { - if (__IElf != NULL) { - DropInterface((struct Interface *) __IElf); - __IElf = NULL; - } - - if (__IUtility != NULL) { - DropInterface((struct Interface *) __IUtility); - __IUtility = NULL; - } - - if (IDOS != NULL) { - DropInterface((struct Interface *) IDOS); - IDOS = NULL; - } - - if (__ElfBase != NULL) { - CloseLibrary(__ElfBase); - __ElfBase = NULL; - } - - if (__UtilityBase != NULL) { - CloseLibrary(__UtilityBase); - __UtilityBase = NULL; - } - - if (DOSBase != NULL) { - CloseLibrary(DOSBase); - DOSBase = NULL; - } -} - static int call_main(void) { volatile LONG saved_io_err; @@ -93,7 +60,30 @@ call_main(void) { SHOWMSG("now invoking the constructors"); /* Go through the constructor list */ _init(); + SHOWMSG("Constructors executed correctly. Calling main()"); + + /* Set system time for rusage. + * This can be executed only here. + * Not in reent_init not in TIMER constructor because + * __ITimer or __global_clib2 cannot be yet available + */ + struct TimerIFace *ITimer = __ITimer; + if (__ITimer != NULL) { + SHOWMSG("Calling GetSysTime"); + GetSysTime(&__global_clib2->clock); + /* Generate random seed */ + __global_clib2->__random_seed = time(NULL); + } + + /* Initialize aio list */ + __global_clib2->aio_threads = CList_init(sizeof(struct AioThread)); + /* Set __current_path_name to a valid value */ + UBYTE current_dir_name[256] = {0}; + struct Process *this_process = (struct Process *) FindTask(NULL); + if (NameFromLock(this_process->pr_CurrentDir, (STRPTR) current_dir_name, sizeof(current_dir_name))) { + __set_current_path((const char *) current_dir_name); + } /* This can be helpful for debugging purposes: print the name of the current directory, followed by the name of the command and all the parameters passed to it. */ @@ -102,32 +92,29 @@ call_main(void) { UBYTE value_str[10]; LONG value; - /* Careful: only echo this information if a global environment - variable is set to enable this feature! */ + /* Careful: only echo this information if a global environment variable is set to enable this feature! */ if (GetVar("_echo", (STRPTR) value_str, sizeof(value_str), GVF_GLOBAL_ONLY) > 0 && StrToLong((CONST_STRPTR) value_str, &value) > 0 && value != 0) { - struct Process *this_process = (struct Process *) FindTask(NULL); STRPTR arg_str = GetArgStr(); size_t arg_str_len = strlen((const char *) arg_str); UBYTE *arg_str_copy; - UBYTE current_dir_name[256] = {0}; arg_str_copy = AllocVecTags(arg_str_len + 1, AVT_Type, MEMF_PRIVATE, TAG_DONE); - if (arg_str_copy != NULL && - NameFromLock(this_process->pr_CurrentDir, (STRPTR) current_dir_name, sizeof(current_dir_name))) { + if (arg_str_copy != NULL) { strcpy((char *) arg_str_copy, (char *) arg_str); while (arg_str_len > 0 && arg_str_copy[arg_str_len - 1] <= ' ') arg_str_copy[--arg_str_len] = '\0'; - kprintf("[%s] %s %s\n", current_dir_name, __program_name, arg_str_copy); + D(("[%s] %s %s\n", current_dir_name, __program_name, arg_str_copy)); + FreeVec(arg_str_copy); } - - FreeVec(arg_str_copy); } } #endif /* NDEBUG */ + /* After all these preparations, get this show on the road... */ - exit(main((int) __argc, (char **) __argv)); + exit(main(__argc, __argv)); + SHOWMSG("Done. Exit from main()"); out: @@ -161,21 +148,32 @@ call_main(void) { } #endif /* NDEBUG */ + SHOWMSG("Flush all files"); /* Dump all currently unwritten data, especially to the console. */ __flush_all_files(-1); - SHOWMSG("invoking the destructors"); - /* If one of the destructors drops into exit(), either directly or through a failed assert() call, processing will resume with the next following destructor. */ (void) setjmp(__exit_jmp_buf); + SHOWMSG("Called setjmp(__exit_jmp_buf)"); + + SHOWMSG("Set unix paths to off"); + disableUnixPaths(); + + /* Free aio list */ + if (__global_clib2->aio_threads != NULL) { + SHOWMSG("Free aio list"); + ObtainSemaphore(__global_clib2->__aio_lock); + __global_clib2->aio_threads->free(__global_clib2->aio_threads); + ReleaseSemaphore(__global_clib2->__aio_lock); + } /* Go through the destructor list */ + SHOWMSG("invoking the destructors"); _fini(); - disableUnixPaths(); - + SHOWMSG("Calling reent_exit"); reent_exit(); SHOWMSG("done."); @@ -187,45 +185,6 @@ call_main(void) { return (__exit_value); } -BOOL -open_libraries(void) { - BOOL success = FALSE; - - /* Open the minimum required libraries. */ - DOSBase = (struct Library *) OpenLibrary("dos.library", MIN_OS_VERSION); - if (DOSBase == NULL) - goto out; - - __UtilityBase = OpenLibrary("utility.library", MIN_OS_VERSION); - if (__UtilityBase == NULL) - goto out; - - /* Obtain the interfaces for these libraries. */ - IDOS = (struct DOSIFace *) GetInterface(DOSBase, "main", 1, 0); - if (IDOS == NULL) - goto out; - - __IUtility = (struct UtilityIFace *) GetInterface(__UtilityBase, "main", 1, 0); - if (__IUtility == NULL) - goto out; - - /* We need elf.library V52.2 or higher. */ - __ElfBase = OpenLibrary("elf.library", 0); - if (__ElfBase == NULL || (__ElfBase->lib_Version < MIN_OS_VERSION) || - (__ElfBase->lib_Version == MIN_OS_VERSION && __ElfBase->lib_Revision < 2)) - goto out; - - __IElf = (struct ElfIFace *) GetInterface(__ElfBase, "main", 1, NULL); - if (__IElf == NULL) - goto out; - - success = TRUE; - - out: - - return (success); -} - static void detach_cleanup(int32_t return_code, int32_t exit_data, struct ExecBase *sysBase) { (void) (return_code); @@ -280,7 +239,7 @@ _main() { __WBenchMsg = (struct WBStartup *) startup_message; /* Try to open the libraries we need to proceed. */ - if (CANNOT open_libraries()) { + if (IDOS == NULL && CANNOT open_libraries()) { const char *error_message; /* If available, use the error message provided by the client. */ @@ -345,8 +304,7 @@ _main() { SetTaskPri((struct Task *) this_process, __priority); /* Was a minimum stack size requested and do we need more stack space than was provided for? */ - if (__stack_size > 0 && current_stack_size < (ULONG)__stack_size) - { + if (__stack_size > 0 && current_stack_size < (ULONG)__stack_size) { struct StackSwapStruct *stk; unsigned int stack_size; APTR new_stack; @@ -382,8 +340,7 @@ _main() { FreeVec(new_stack); FreeVec(stk); } - else - { + else { /* We have enough room to make the call or just don't care. */ return_code = call_main(); } @@ -409,47 +366,39 @@ _main() { if (stack_size < cli->cli_DefaultStack * sizeof(LONG)) stack_size = cli->cli_DefaultStack * sizeof(LONG); - GetCliProgramName(program_name, (LONG) - sizeof(program_name)); + GetCliProgramName(program_name, (LONG) sizeof(program_name)); i = 0; tags[i].ti_Tag = NP_Entry; - tags[i++].ti_Data = (ULONG) - call_main; + tags[i++].ti_Data = (ULONG) call_main; tags[i].ti_Tag = NP_StackSize; tags[i++].ti_Data = stack_size; tags[i].ti_Tag = NP_Name; - tags[i++].ti_Data = (ULONG)(__process_name != NULL ? __process_name : (char *) FilePart(program_name)); + tags[i++].ti_Data = (ULONG) (__process_name != NULL ? __process_name : (char *) FilePart(program_name)); tags[i].ti_Tag = NP_CommandName; - tags[i++].ti_Data = (ULONG) - FilePart(program_name); + tags[i++].ti_Data = (ULONG) FilePart(program_name); tags[i].ti_Tag = NP_Cli; tags[i++].ti_Data = TRUE; tags[i].ti_Tag = NP_Child; tags[i++].ti_Data = TRUE; tags[i].ti_Tag = NP_Arguments; - tags[i++].ti_Data = (ULONG) - GetArgStr(); + tags[i++].ti_Data = (ULONG) GetArgStr(); tags[i].ti_Tag = NP_FinalCode; - tags[i++].ti_Data = (ULONG) - detach_cleanup; + tags[i++].ti_Data = (ULONG) detach_cleanup; tags[i].ti_Tag = NP_FinalData; - tags[i++].ti_Data = (ULONG) - cli->cli_Module; + tags[i++].ti_Data = (ULONG) cli->cli_Module; /* Use a predefined task priority, if requested. */ if (-128 <= __priority && __priority <= 127) { tags[i].ti_Tag = NP_Priority; - tags[i++].ti_Data = (ULONG) - __priority; + tags[i++].ti_Data = (ULONG) __priority; } /* dos.library V50 will free the segment list upon exit. */ if (((struct Library *) DOSBase)->lib_Version >= 50) { tags[i].ti_Tag = NP_Seglist; - tags[i++].ti_Data = (ULONG) - cli->cli_Module;; + tags[i++].ti_Data = (ULONG) cli->cli_Module;; tags[i].ti_Tag = NP_FreeSeglist; tags[i++].ti_Data = TRUE; } @@ -483,9 +432,6 @@ _main() { if (old_window_pointer_valid) __set_process_window(old_window_pointer); - if (child_process == NULL) - close_libraries(); - if (startup_message != NULL) { Forbid(); diff --git a/library/stdlib/program_name.c b/library/stdlib/program_name.c index 56302851..eeb2ea3a 100644 --- a/library/stdlib/program_name.c +++ b/library/stdlib/program_name.c @@ -17,8 +17,7 @@ static BOOL free_program_name; char *NOCOMMON __program_name; -STDLIB_DESTRUCTOR(stdlib_program_name_exit) -{ +STDLIB_DESTRUCTOR(stdlib_program_name_exit) { ENTER(); if (free_program_name && __program_name != NULL) @@ -30,14 +29,12 @@ STDLIB_DESTRUCTOR(stdlib_program_name_exit) LEAVE(); } /* First constructor called by _init */ -STDLIB_CONSTRUCTOR(stdlib_program_name_init) -{ +STDLIB_CONSTRUCTOR(stdlib_program_name_init) { BOOL success = FALSE; ENTER(); - if (__WBenchMsg == NULL) - { + if (__WBenchMsg == NULL) { const size_t program_name_size = 256; /* Make a copy of the current command name string. */ @@ -50,8 +47,7 @@ STDLIB_CONSTRUCTOR(stdlib_program_name_init) if (CANNOT GetCliProgramName(__program_name, program_name_size)) goto out; } - else - { + else { __program_name = (char *)__WBenchMsg->sm_ArgList[0].wa_Name; } diff --git a/library/stdlib/semaphore.c b/library/stdlib/semaphore.c index 98cd437e..7c3297a0 100644 --- a/library/stdlib/semaphore.c +++ b/library/stdlib/semaphore.c @@ -10,9 +10,15 @@ __create_semaphore(void) { ENTER(); +#if 1 semaphore = AllocVecTags(sizeof(*semaphore), AVT_Type, MEMF_SHARED, TAG_DONE); if (semaphore != NULL) InitSemaphore(semaphore); +#else + semaphore = AllocSysObjectTags(ASOT_SEMAPHORE, + ASOSEM_Size, sizeof(*semaphore), + TAG_END); +#endif SHOWPOINTER(semaphore); LEAVE(); @@ -28,8 +34,12 @@ __delete_semaphore(struct SignalSemaphore *semaphore) { SHOWPOINTER(semaphore); if (semaphore != NULL) { +#if 1 FreeVec(semaphore); - //FreeSysObject(ASOT_SEMAPHORE,semaphore); +#else + FreeSysObject(ASOT_SEMAPHORE, semaphore); +#endif + semaphore = NULL; } LEAVE(); diff --git a/library/stdlib/shared_objs.c b/library/stdlib/shared_objs.c index d1537ad4..463a3834 100644 --- a/library/stdlib/shared_objs.c +++ b/library/stdlib/shared_objs.c @@ -1,77 +1,3 @@ /* * $Id: stdlib_shared_objs.c,v 1.1 2010-08-21 11:37:03 clib2devs Exp $ */ - -#ifndef _STDLIB_HEADERS_H -#include "stdlib_headers.h" -#endif /* _STDLIB_HEADERS_H */ - -static BOOL open_elf_library(void); -static VOID close_elf_library(void); - -/* These are used to initialize the shared objects linked to this binary, - and for the dlopen(), dlclose() and dlsym() functions. */ -struct Library *__ElfBase; -struct ElfIFace *__IElf; -static Elf32_Handle elf_handle; - -static VOID close_elf_library(void) { - if (__IElf != NULL) { - DropInterface((struct Interface *) __IElf); - __IElf = NULL; - } - - if (__ElfBase != NULL) { - CloseLibrary(__ElfBase); - __ElfBase = NULL; - } -} - -static BOOL open_elf_library(void) { - BOOL success = FALSE; - - /* We need elf.library V52.2 or higher. */ - __ElfBase = OpenLibrary("elf.library", 0); - if (__ElfBase == NULL || (__ElfBase->lib_Version < 52) || - (__ElfBase->lib_Version == 52 && __ElfBase->lib_Revision < 2)) - goto out; - - __IElf = (struct ElfIFace *) GetInterface(__ElfBase, "main", 1, NULL); - if (__IElf == NULL) - goto out; - - success = TRUE; - -out: - - return (success); -} - -void shared_obj_exit(void) { - struct ElfIFace *IElf = __IElf; - - /* If we got what we wanted, trigger the destructors, etc. in the shared objects linked to this binary. */ - if (elf_handle != NULL) { - InitSHLibs(elf_handle, FALSE); - elf_handle = NULL; - }; - - close_elf_library(); -} - -void shared_obj_init(void) { - if (open_elf_library()) { - struct ElfIFace *IElf = __IElf; - - BPTR segment_list = GetProcSegList(NULL, GPSLF_RUN | GPSLF_SEG); - if (segment_list != ZERO) { - int ret = GetSegListInfoTags(segment_list, GSLI_ElfHandle, &elf_handle, TAG_DONE); - if (ret == 1) { - if (elf_handle != NULL) { - /* Trigger the constructors, etc. in the shared objects linked to this binary. */ - InitSHLibs(elf_handle, TRUE); - } - } - } - } -} \ No newline at end of file diff --git a/library/stdlib/stdlib_constructor.h b/library/stdlib/stdlib_constructor.h index 89826d5c..c5212822 100755 --- a/library/stdlib/stdlib_constructor.h +++ b/library/stdlib/stdlib_constructor.h @@ -41,32 +41,32 @@ constructors and the user-supplied destructors before the library destructors. */ -#define STDLIB_CONSTRUCTOR(name) CONSTRUCTOR(name, 11) -#define STDLIB_DESTRUCTOR(name) DESTRUCTOR(name, 11) +#define STDLIB_CONSTRUCTOR(name) CONSTRUCTOR(name, 101) +#define STDLIB_DESTRUCTOR(name) DESTRUCTOR(name, 101) -#define STK_CONSTRUCTOR(name) CONSTRUCTOR(name, 12) -#define STK_DESTRUCTOR(name) DESTRUCTOR(name, 12) +#define STK_CONSTRUCTOR(name) CONSTRUCTOR(name, 102) +#define STK_DESTRUCTOR(name) DESTRUCTOR(name, 102) -#define STDIO_CONSTRUCTOR(name) CONSTRUCTOR(name, 13) -#define STDIO_DESTRUCTOR(name) DESTRUCTOR(name, 13) +#define STDIO_CONSTRUCTOR(name) CONSTRUCTOR(name, 103) +#define STDIO_DESTRUCTOR(name) DESTRUCTOR(name, 103) -#define FILE_CONSTRUCTOR(name) CONSTRUCTOR(name, 14) -#define FILE_DESTRUCTOR(name) DESTRUCTOR(name, 14) +#define FILE_CONSTRUCTOR(name) CONSTRUCTOR(name, 104) +#define FILE_DESTRUCTOR(name) DESTRUCTOR(name, 104) -#define MATH_CONSTRUCTOR(name) CONSTRUCTOR(name, 15) -#define MATH_DESTRUCTOR(name) DESTRUCTOR(name, 15) +#define MATH_CONSTRUCTOR(name) CONSTRUCTOR(name, 105) +#define MATH_DESTRUCTOR(name) DESTRUCTOR(name, 105) -#define SOCKET_CONSTRUCTOR(name) CONSTRUCTOR(name, 16) -#define SOCKET_DESTRUCTOR(name) DESTRUCTOR(name, 16) +#define SOCKET_CONSTRUCTOR(name) CONSTRUCTOR(name, 106) +#define SOCKET_DESTRUCTOR(name) DESTRUCTOR(name, 106) -#define ARG_CONSTRUCTOR(name) CONSTRUCTOR(name, 17) -#define ARG_DESTRUCTOR(name) DESTRUCTOR(name, 17) +#define ARG_CONSTRUCTOR(name) CONSTRUCTOR(name, 107) +#define ARG_DESTRUCTOR(name) DESTRUCTOR(name, 107) -#define CLIB_CONSTRUCTOR(name) CONSTRUCTOR(name, 18) -#define CLIB_DESTRUCTOR(name) DESTRUCTOR(name, 18) +#define CLIB_CONSTRUCTOR(name) CONSTRUCTOR(name, 108) +#define CLIB_DESTRUCTOR(name) DESTRUCTOR(name, 108) -#define PROFILE_CONSTRUCTOR(name) CONSTRUCTOR(name, 19) -#define PROFILE_DESTRUCTOR(name) DESTRUCTOR(name, 19) +#define PROFILE_CONSTRUCTOR(name) CONSTRUCTOR(name, 109) +#define PROFILE_DESTRUCTOR(name) DESTRUCTOR(name, 109) /****************************************************************************/ diff --git a/library/stdlib/stdlib_headers.h b/library/stdlib/stdlib_headers.h index f24e4a3d..74f75c77 100755 --- a/library/stdlib/stdlib_headers.h +++ b/library/stdlib/stdlib_headers.h @@ -81,6 +81,8 @@ #include "debug.h" #endif /* _DEBUG_H */ +#define MIN_OS_VERSION 52 + extern jmp_buf NOCOMMON __exit_jmp_buf; extern int NOCOMMON __exit_value; @@ -95,6 +97,9 @@ extern int NOCOMMON __argc; extern BOOL NOCOMMON __lib_startup; +extern void _init(void); +extern void _fini(void); + #ifndef _STDLIB_PROTOS_H #include "stdlib_protos.h" #endif /* _STDLIB_PROTOS_H */ diff --git a/library/stdlib/stdlib_protos.h b/library/stdlib/stdlib_protos.h index 7496dc44..6d989d40 100644 --- a/library/stdlib/stdlib_protos.h +++ b/library/stdlib/stdlib_protos.h @@ -88,8 +88,6 @@ void reent_init(void); void reent_exit(void); /* stdlib_constructor_begin.c */ -void _init(void); -void _fini(void); void shared_obj_init(void); void shared_obj_exit(void); @@ -112,9 +110,8 @@ extern void __check_memory_allocations(); extern void __check_abort(void); /* stdlib_main.c */ -extern int _main(void); -extern int _start(char *args, int arglen, struct ExecBase *sysBase); -extern void _fini(void); +extern int _main(); +extern int _start(STRPTR argstring, int32 arglen, struct ExecBase *sysbase); /****************************************************************************/ diff --git a/library/stdlib/wof_allocator.c b/library/stdlib/wof_allocator.c index b4b83574..f137d1b5 100644 --- a/library/stdlib/wof_allocator.c +++ b/library/stdlib/wof_allocator.c @@ -895,10 +895,13 @@ wof_allocator_destroy(wof_allocator_t *allocator) { wof_allocator_t * wof_allocator_new(void) { wof_allocator_t *allocator; + ENTER(); //allocator = (wof_allocator_t *) malloc(sizeof(wof_allocator_t)); - allocator = (wof_allocator_t *) AllocVecTags(sizeof(wof_allocator_t), MEMF_SHARED, TAG_DONE); + allocator = (wof_allocator_t *) AllocVecTags(sizeof(wof_allocator_t), MEMF_SHARED, AVT_ClearWithValue, 0, TAG_DONE); if (allocator == NULL) { + SHOWMSG("Unable to create wof_allocator"); + RETURN(NULL); return NULL; } @@ -906,6 +909,8 @@ wof_allocator_new(void) { allocator->master_head = NULL; allocator->recycler_head = NULL; + SHOWPOINTER(allocator); + LEAVE(); return allocator; } diff --git a/library/string/atomic.h b/library/string/atomic.h index 54fbc170..1fd257da 100644 --- a/library/string/atomic.h +++ b/library/string/atomic.h @@ -3,15 +3,274 @@ #include -static inline int a_ctz_32(uint32_t x) { +#include "atomic_arch.h" + +#ifdef a_ll + +#ifndef a_pre_llsc +#define a_pre_llsc() +#endif + +#ifndef a_post_llsc +#define a_post_llsc() +#endif + +#ifndef a_cas +#define a_cas a_cas +static inline int a_cas(volatile int *p, int t, int s) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (old==t && !a_sc(p, s)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, (unsigned)old + v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old & v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old | v)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifdef a_ll_p + +#ifndef a_cas_p +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + void *old; + a_pre_llsc(); + do old = a_ll_p(p); + while (old==t && !a_sc_p(p, s)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifndef a_cas +#error missing definition of a_cas +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, v) != old); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, (unsigned)old+v) != old); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old&v) != old); + return old; +} +#endif +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old|v) != old); + return old; +} +#endif + +#ifndef a_and +#define a_and a_and +static inline void a_and(volatile int *p, int v) +{ + a_fetch_and(p, v); +} +#endif + +#ifndef a_or +#define a_or a_or +static inline void a_or(volatile int *p, int v) +{ + a_fetch_or(p, v); +} +#endif + +#ifndef a_inc +#define a_inc a_inc +static inline void a_inc(volatile int *p) +{ + a_fetch_add(p, 1); +} +#endif + +#ifndef a_dec +#define a_dec a_dec +static inline void a_dec(volatile int *p) +{ + a_fetch_add(p, -1); +} +#endif + +#ifndef a_store +#define a_store a_store +static inline void a_store(volatile int *p, int v) +{ +#ifdef a_barrier + a_barrier(); + *p = v; + a_barrier(); +#else + a_swap(p, v); +#endif +} +#endif + +#ifndef a_barrier +#define a_barrier a_barrier +static void a_barrier() +{ + volatile int tmp = 0; + a_cas(&tmp, 0, 0); +} +#endif + +#ifndef a_spin +#define a_spin a_barrier +#endif + +#ifndef a_and_64 +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]+1) a_and((int *)p, u.r[0]); + if (u.r[1]+1) a_and((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_or_64 +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]) a_or((int *)p, u.r[0]); + if (u.r[1]) a_or((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_cas_p +typedef char a_cas_p_undefined_but_pointer_not_32bit[-sizeof(char) == 0xffffffff ? 1 : -1]; +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + return (void *)a_cas((volatile int *)p, (int)t, (int)s); +} +#endif + +#ifndef a_or_l +#define a_or_l a_or_l +static inline void a_or_l(volatile void *p, long v) +{ + if (sizeof(long) == sizeof(int)) a_or(p, v); + else a_or_64(p, v); +} +#endif + +#ifndef a_crash +#define a_crash a_crash +static inline void a_crash() +{ + *(volatile char *)0=0; +} +#endif + +#ifndef a_ctz_32 +#define a_ctz_32 a_ctz_32 +static inline int a_ctz_32(uint32_t x) +{ +#ifdef a_clz_32 + return 31-a_clz_32(x&-x); +#else static const char debruijn32[32] = { 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 }; - return debruijn32[(x & -x) * 0x076be629 >> 27]; + return debruijn32[(x&-x)*0x076be629 >> 27]; +#endif } +#endif -static inline int a_ctz_64(uint64_t x) { +#ifndef a_ctz_64 +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) +{ static const char debruijn64[64] = { 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, @@ -21,16 +280,54 @@ static inline int a_ctz_64(uint64_t x) { if (sizeof(long) < 8) { uint32_t y = x; if (!y) { - y = x >> 32; + y = x>>32; return 32 + a_ctz_32(y); } return a_ctz_32(y); } - return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; + return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; } +#endif -static inline int a_ctz_l(unsigned long x) { +static inline int a_ctz_l(unsigned long x) +{ return (sizeof(long) < 8) ? a_ctz_32(x) : a_ctz_64(x); } -#endif \ No newline at end of file +#ifndef a_clz_64 +#define a_clz_64 a_clz_64 +static inline int a_clz_64(uint64_t x) +{ +#ifdef a_clz_32 + if (x>>32) + return a_clz_32(x>>32); + return a_clz_32(x) + 32; +#else + uint32_t y; + int r; + if (x>>32) y=x>>32, r=0; else y=x, r=32; + if (y>>16) y>>=16; else r |= 16; + if (y>>8) y>>=8; else r |= 8; + if (y>>4) y>>=4; else r |= 4; + if (y>>2) y>>=2; else r |= 2; + return r | !(y>>1); +#endif +} +#endif + +#ifndef a_clz_32 +#define a_clz_32 a_clz_32 +static inline int a_clz_32(uint32_t x) +{ + x >>= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return 31-a_ctz_32(x); +} +#endif + +#endif diff --git a/library/string/atomic_arch.h b/library/string/atomic_arch.h new file mode 100644 index 00000000..1d95242f --- /dev/null +++ b/library/string/atomic_arch.h @@ -0,0 +1,38 @@ +#define a_ll a_ll +static inline int a_ll(volatile int *p) +{ + int v; + __asm__ __volatile__ ("lwarx %0, 0, %2" : "=r"(v) : "m"(*p), "r"(p)); + return v; +} + +#define a_sc a_sc +static inline int a_sc(volatile int *p, int v) +{ + int r; + __asm__ __volatile__ ( + "stwcx. %2, 0, %3 ; mfcr %0" + : "=r"(r), "=m"(*p) : "r"(v), "r"(p) : "memory", "cc"); + return r & 0x20000000; /* "bit 2" of "cr0" (backwards bit order) */ +} + +#define a_barrier a_barrier +static inline void a_barrier() +{ + __asm__ __volatile__ ("sync" : : : "memory"); +} + +#define a_pre_llsc a_barrier + +#define a_post_llsc a_post_llsc +static inline void a_post_llsc() +{ + __asm__ __volatile__ ("isync" : : : "memory"); +} + +#define a_clz_32 a_clz_32 +static inline int a_clz_32(uint32_t x) +{ + __asm__ ("cntlzw %0, %1" : "=r"(x) : "r"(x)); + return x; +} diff --git a/library/string/memchr.c b/library/string/memchr.c index 935ed229..6a743e0a 100644 --- a/library/string/memchr.c +++ b/library/string/memchr.c @@ -1,5 +1,5 @@ /* - * $Id: string_memchr.c,v 1.7 2021-03-22 12:04:26 clib2devs Exp $ + * $Id: string_memchr.c,v 1.8 2023-02-22 12:04:26 clib2devs Exp $ */ #ifndef _STDLIB_HEADERS_H @@ -10,164 +10,144 @@ #include "string_headers.h" #endif /* _STRING_HEADERS_H */ -/* Check if one of the four bytes which make up a long word is zero. */ -#define LONG_CONTAINS_ZERO_OCTET(x) (((x) + 0xfefefeff) & ~((x) | 0x7f7f7f7f)) - -INLINE STATIC void * -__memchr(const unsigned char *m, unsigned char val, size_t len) -{ - void *result = NULL; - - assert(m != NULL && len > 0); - - /* The setup below is intended to speed up searching in larger - * memory blocks. This can be very elaborate and should not be - * done unless a payoff can be expected. - */ - if (len > 4 * sizeof(long)) - { - /* Try to align the memory block to an even address. */ - if (IS_UNALIGNED(m)) - { - len--; - - if ((*m) == val) - { - result = (void *)m; - goto out; - } - - m++; - } - - /* Try to align the memory block to an address which is - * a multiple of a long word. - */ - if (len >= sizeof(short) && IS_SHORT_ALIGNED(m)) - { - len--; - - if ((*m) == val) - { - result = (void *)m; - goto out; - } - - m++; - - len--; - - if ((*m) == val) - { - result = (void *)m; - goto out; - } - - m++; - } - - /* If the memory block is aligned to an address from which - * data can be read one long word at a time, perform the - * search in this manner. - */ - if (len >= sizeof(long) && IS_LONG_ALIGNED(m)) - { - const unsigned long *_m = (const unsigned long *)m; - unsigned long _val = val; - unsigned long x; - - /* Build a long word which contains the byte value to - * find, repeated four times. - */ - _val |= (_val << 8); - _val |= (_val << 16); - - do - { - /* Technically, what we want to achieve is to look - * at a single long word and be able to tell whether - * it contains the value we are looking for in one - * of the octets which it consists of. This is - * achieved by an XOR operation which sets those - * octets to zero which match the search value. The - * result of this operation is then tested to see - * whether it contains any zero octets. - */ - x = (*_m) ^ _val; - if (LONG_CONTAINS_ZERO_OCTET(x)) - { - /* We got what we wanted. Now figure out which byte - * would match the value we were looking for. - */ - m = (const unsigned char *)_m; - goto out; - } - - _m++; - len -= sizeof(long); - } while (len >= sizeof(long)); - - m = (const unsigned char *)_m; - } - } - -out: - - /* If there are bytes left in need of comparison, take - * care of them here. This also includes 'aborted' - * comparison attempts from above. - */ - while (len-- > 0) - { - if ((*m) == val) - { - result = (void *)m; - break; - } - - m++; - } - - return (result); +inline static void * +__memchr(void const *s, int c_in, size_t n) { + /* On 32-bit hardware, choosing longword to be a 32-bit unsigned + long instead of a 64-bit uintmax_t tends to give better + performance. On 64-bit hardware, unsigned long is generally 64 + bits already. Change this typedef to experiment with + performance. */ + typedef unsigned long int longword; + + const unsigned char *char_ptr; + const longword *longword_ptr; + longword repeated_one; + longword repeated_c; + unsigned char c; + + c = (unsigned char) c_in; + + /* Handle the first few bytes by reading one byte at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + n > 0 && (size_t) char_ptr % sizeof(longword) != 0; + --n, ++char_ptr) + if (*char_ptr == c) + return (void *) char_ptr; + + longword_ptr = (const longword *) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to any size longwords. */ + + /* Compute auxiliary longword values: + repeated_one is a value which has a 1 in every byte. + repeated_c has c in every byte. */ + repeated_one = 0x01010101; + repeated_c = c | (c << 8); + repeated_c |= repeated_c << 16; + if (0xffffffffU < (longword) -1) { + repeated_one |= repeated_one << 31 << 1; + repeated_c |= repeated_c << 31 << 1; + if (8 < sizeof(longword)) { + size_t i; + + for (i = 64; i < sizeof(longword) * 8; i *= 2) { + repeated_one |= repeated_one << i; + repeated_c |= repeated_c << i; + } + } + } + + /* Instead of the traditional loop which tests each byte, we will test a + longword at a time. The tricky part is testing if *any of the four* + bytes in the longword in question are equal to c. We first use an xor + with repeated_c. This reduces the task to testing whether *any of the + four* bytes in longword1 is zero. + + We compute tmp = + ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7). + That is, we perform the following operations: + 1. Subtract repeated_one. + 2. & ~longword1. + 3. & a mask consisting of 0x80 in every byte. + Consider what happens in each byte: + - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff, + and step 3 transforms it into 0x80. A carry can also be propagated + to more significant bytes. + - If a byte of longword1 is nonzero, let its lowest 1 bit be at + position k (0 <= k <= 7); so the lowest k bits are 0. After step 1, + the byte ends in a single bit of value 0 and k bits of value 1. + After step 2, the result is just k bits of value 1: 2^k - 1. After + step 3, the result is 0. And no carry is produced. + So, if longword1 has only non-zero bytes, tmp is zero. + Whereas if longword1 has a zero byte, call j the position of the least + significant zero byte. Then the result has a zero at positions 0, ..., + j-1 and a 0x80 at position j. We cannot predict the result at the more + significant bytes (positions j+1..3), but it does not matter since we + already have a non-zero bit at position 8*j+7. + + So, the test whether any byte in longword1 is zero is equivalent to + testing whether tmp is nonzero. */ + + while (n >= sizeof(longword)) { + longword longword1 = *longword_ptr ^ repeated_c; + + if ((((longword1 - repeated_one) & ~longword1) + & (repeated_one << 7)) != 0) + break; + longword_ptr++; + n -= sizeof(longword); + } + + char_ptr = (const unsigned char *) longword_ptr; + + /* At this point, we know that either n < sizeof (longword), or one of the + sizeof (longword) bytes starting at char_ptr is == c. On little-endian + machines, we could determine the first such byte without any further + memory accesses, just by looking at the tmp result from the last loop + iteration. But this does not work on big-endian machines. Choose code + that works in both cases. */ + + for (; n > 0; --n, ++char_ptr) { + if (*char_ptr == c) + return (void *) char_ptr; + } + + return NULL; } void * -memchr(const void *ptr, int val, size_t len) -{ - const unsigned char *m = ptr; - void *result = NULL; - - assert(ptr != NULL); - assert((int)len >= 0); - - if (ptr == NULL) - { - __set_errno(EFAULT); - goto out; - } - - if (len > 0) - { - /* Make sure __global_clib2 has been created */ - if (__global_clib2 != NULL && __global_clib2->optimizedCPUFunctions) { - switch (__global_clib2->cpufamily) - { +memchr(const void *ptr, int val, size_t len) { + const unsigned char *m = ptr; + void *result = NULL; + + assert(ptr != NULL); + assert((int) len >= 0); + + if (ptr == NULL) { + __set_errno(EFAULT); + goto out; + } + + if (len > 0) { + /* Make sure __global_clib2 has been created */ + if (__global_clib2 != NULL && __global_clib2->optimizedCPUFunctions) { + switch (__global_clib2->cpufamily) { case CPUFAMILY_4XX: - result = __memchr440(m, (unsigned char)(val & 255), len); + result = __memchr440(m, (unsigned char) (val & 255), len); break; default: - result = __memchr(m, (unsigned char)(val & 255), len); - } - } - else { - /* Fallback to standard function */ - result = __memchr(m, (unsigned char)(val & 255), len); - } - } - else - __set_errno(EFAULT); - -out: - - return (result); + result = __memchr(m, (unsigned char) (val & 255), len); + } + } else { + /* Fallback to standard function */ + result = __memchr(m, (unsigned char) (val & 255), len); + } + } else + __set_errno(EFAULT); + + out: + + return (result); } diff --git a/library/string/memset.c b/library/string/memset.c index 2bee6668..f7c7a90e 100644 --- a/library/string/memset.c +++ b/library/string/memset.c @@ -1,5 +1,5 @@ /* - * $Id: string_memset.c,v 1.9 2021-03-22 09:02:51 clib2devs Exp $ + * $Id: string_memset.c,v 1.10 2023-02-22 09:02:51 clib2devs Exp $ */ #ifndef _STDLIB_HEADERS_H @@ -25,20 +25,7 @@ memset(void *ptr, int val, size_t len) { goto out; } - if (__global_clib2 != NULL && __global_clib2->optimizedCPUFunctions == TRUE) { - /* Check if we have altivec enabled */ - if (__global_clib2->hasAltivec) { - result = _vec_memset(m, (unsigned char)(val & 255), len); - } - else { - /* Fallback to standard function */ - result = SetMem(ptr, val, len); - } - } - else { - /* Fallback to standard function */ - result = SetMem(ptr, val, len); - } + result = SetMem(ptr, val, len); out: diff --git a/library/termios/console_fdhookentry.c b/library/termios/console_fdhookentry.c index ab18ff40..c635ba6d 100644 --- a/library/termios/console_fdhookentry.c +++ b/library/termios/console_fdhookentry.c @@ -245,9 +245,14 @@ __termios_console_hook(struct fd *fd, struct file_action_message *fam) { * in RAW Mode but I suppose that we are ok since we are using * a termios hook */ - if (FLAG_IS_CLEAR(tios->c_cflag, ICANON) && FLAG_IS_SET(tios->c_cflag, NCURSES)) { + SHOWVALUE(FLAG_IS_CLEAR(tios->c_lflag, ICANON)); + SHOWVALUE(FLAG_IS_SET(tios->c_lflag, NCURSES)); + if (FLAG_IS_CLEAR(tios->c_lflag, ICANON) && FLAG_IS_SET(tios->c_lflag, NCURSES)) { /* Set raw mode. */ - SetMode(file, DOSTRUE); + if (fam->fam_DOSMode == DOSFALSE) { + SetMode(file, DOSTRUE); + fam->fam_DOSMode = DOSTRUE; + } if (tios->c_cc[VMIN] > 0 && tios->c_cc[VTIME] > 0) { if (WaitForChar(file, 100000 * tios->c_cc[VTIME])) { result = Read(file, fam->fam_Data, fam->fam_Size); @@ -411,8 +416,13 @@ __termios_console_hook(struct fd *fd, struct file_action_message *fam) { __remove_fd_alias(fd); } else if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_STDIO)) { /* Should we reset this file into line buffered mode? */ - if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) - SetMode(fd->fd_File, DOSFALSE); + if (FLAG_IS_SET(fd->fd_Flags, FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE)) { + /* Set canonical mode. */ + if (fam->fam_DOSMode == DOSTRUE) { + SetMode(fd->fd_File, DOSFALSE); + fam->fam_DOSMode = DOSFALSE; + } + } /* Are we allowed to close this file? */ if (FLAG_IS_CLEAR(fd->fd_Flags, FDF_NO_CLOSE)) { diff --git a/library/termios/tcgetattr.c b/library/termios/tcgetattr.c index 7f197114..76877bde 100644 --- a/library/termios/tcgetattr.c +++ b/library/termios/tcgetattr.c @@ -44,8 +44,10 @@ get_console_termios(struct fd *fd, BOOL use_ncurses) { SET_FLAG(tios->c_cflag, CREAD); tios->c_lflag = ISIG|ICANON|ECHO; - if (use_ncurses) - SET_FLAG(tios->c_cflag, NCURSES); + if (use_ncurses) { + CLEAR_FLAG(tios->c_lflag, ICANON); + SET_FLAG(tios->c_lflag, NCURSES); + } memcpy(tios->c_cc, def_console_cc, NCCS); @@ -99,6 +101,7 @@ tcgetattr(int file_descriptor, struct termios *user_tios) { BOOL use_ncurses = FALSE; struct fd *fd = NULL; struct termios *tios; + BPTR file; __stdio_lock(); @@ -113,10 +116,17 @@ tcgetattr(int file_descriptor, struct termios *user_tios) { goto out; } + file = __resolve_fd_file(fd); + if (file == ZERO) + goto out; + __fd_lock(fd); - if (FLAG_IS_SET(user_tios->c_cflag, NCURSES)) + if (FLAG_IS_SET(user_tios->c_lflag, NCURSES)) { + SetMode(file, DOSTRUE); + CLEAR_FLAG(user_tios->c_lflag, ICANON); use_ncurses = TRUE; + } if (FLAG_IS_SET(fd->fd_Flags, FDF_TERMIOS)) { assert(fd->fd_Aux != NULL); diff --git a/library/termios/tcsetattr.c b/library/termios/tcsetattr.c index 12f616fd..eb47cbf8 100644 --- a/library/termios/tcsetattr.c +++ b/library/termios/tcsetattr.c @@ -13,8 +13,10 @@ set_console_termios(struct fd *fd, struct termios *new_tios) { BPTR file; BOOL use_ncurses = FALSE; - if (FLAG_IS_SET(new_tios->c_cflag, NCURSES)) + if (FLAG_IS_SET(new_tios->c_lflag, NCURSES)) { + CLEAR_FLAG(new_tios->c_lflag, ICANON); use_ncurses = TRUE; + } /* TODO: Check for some "impossible" combinations here? */ diff --git a/library/time/clock_gettime.c b/library/time/clock_gettime.c index 0892c604..52c22a89 100644 --- a/library/time/clock_gettime.c +++ b/library/time/clock_gettime.c @@ -13,20 +13,18 @@ extern struct TimerIFace *NOCOMMON __ITimer; extern BOOL NOCOMMON __timer_busy; -int clock_gettime(clockid_t clk_id, struct timespec *t) -{ +int +clock_gettime(clockid_t clk_id, struct timespec *t) { ENTER(); - + /* Check the supported flags. */ - if ((clk_id & ~(CLOCK_MONOTONIC | CLOCK_REALTIME)) != 0) - { + if ((clk_id & ~(CLOCK_MONOTONIC | CLOCK_REALTIME)) != 0) { __set_errno(EINVAL); RETURN(-1); return -1; } - if (__timer_busy) - { + if (__timer_busy) { __set_errno(EAGAIN); RETURN(-1); return -1; @@ -44,11 +42,9 @@ int clock_gettime(clockid_t clk_id, struct timespec *t) tv.tv_sec = tv.tv_usec = 0; GetTimezoneAttrs(NULL, TZA_UTCOffset, &gmtoffset, TZA_TimeFlag, &dstime, TAG_DONE); - if (result == 0) - { + if (result == 0) { __timer_busy = TRUE; - if (clk_id == CLOCK_MONOTONIC) - { + if (clk_id == CLOCK_MONOTONIC) { /* CLOCK_MONOTONIC A nonsettable system-wide clock that represents monotonic @@ -57,10 +53,8 @@ int clock_gettime(clockid_t clk_id, struct timespec *t) number of seconds that the system has been running since it was booted. */ - GetUpTime((struct TimeVal *)&tv); - } - else - { + GetUpTime((struct TimeVal *) &tv); + } else { /* A settable system-wide clock that measures real (i.e., wall-clock) time. Setting this clock requires appropriate @@ -69,18 +63,14 @@ int clock_gettime(clockid_t clk_id, struct timespec *t) manually changes the clock), and by the incremental adjustments performed by adjtime(3) and NTP. */ - GetSysTime((struct TimeVal *)&tv); + GetSysTime((struct TimeVal *) &tv); } - if (result == 0) - { - if (clk_id == CLOCK_MONOTONIC) - { + if (result == 0) { + if (clk_id == CLOCK_MONOTONIC) { t->tv_sec = tv.tv_sec; t->tv_nsec = tv.tv_usec * 1000; - } - else - { + } else { /* 2922 is the number of days between 1.1.1970 and 1.1.1978 */ tv.tv_sec += (2922 * 24 * 60 + gmtoffset) * 60; t->tv_sec = tv.tv_sec; diff --git a/library/time/clock_gettime64.c b/library/time/clock_gettime64.c new file mode 100644 index 00000000..96cb56f4 --- /dev/null +++ b/library/time/clock_gettime64.c @@ -0,0 +1,89 @@ +/* + * $Id: time_clock_gettime64.c,v 1.0 2023-03-03 16:55:42 clib2devs Exp $ +*/ + +#ifndef _STDIO_HEADERS_H +#include "stdio_headers.h" +#endif /* _STDIO_HEADERS_H */ + +#ifndef _TIMEZONE_HEADERS_H +#include "timezone_headers.h" +#endif /* _TIMEZONE_HEADERS_H */ + +extern struct TimerIFace *NOCOMMON __ITimer; +extern BOOL NOCOMMON __timer_busy; + +int +clock_gettime64(clockid_t clk_id, struct timespec64 *t) { + ENTER(); + + /* Check the supported flags. */ + if ((clk_id & ~(CLOCK_MONOTONIC | CLOCK_REALTIME)) != 0) { + __set_errno(EINVAL); + RETURN(-1); + return -1; + } + + if (__timer_busy) { + __set_errno(EAGAIN); + RETURN(-1); + return -1; + } + + DECLARE_TIMEZONEBASE(); + struct TimerIFace *ITimer = __ITimer; + + struct timeval tv; + int result = 0; + uint32 gmtoffset = 0; + int8 dstime = -1; + + //Set default value for tv + tv.tv_sec = tv.tv_usec = 0; + + GetTimezoneAttrs(NULL, TZA_UTCOffset, &gmtoffset, TZA_TimeFlag, &dstime, TAG_DONE); + if (result == 0) { + __timer_busy = TRUE; + if (clk_id == CLOCK_MONOTONIC) { + /* + CLOCK_MONOTONIC + A nonsettable system-wide clock that represents monotonic + time since—as described by POSIX—"some unspecified point + in the past". On clib2, that point corresponds to the + number of seconds that the system has been running since + it was booted. + */ + GetUpTime((struct TimeVal *) &tv); + } else { + /* + A settable system-wide clock that measures real (i.e., + wall-clock) time. Setting this clock requires appropriate + privileges. This clock is affected by discontinuous jumps + in the system time (e.g., if the system administrator + manually changes the clock), and by the incremental + adjustments performed by adjtime(3) and NTP. + */ + GetSysTime((struct TimeVal *) &tv); + } + + if (result == 0) { + /* Use a 32 bit timespec to calculate the result */ + struct timespec tr; + if (clk_id == CLOCK_MONOTONIC) { + tr.tv_sec = tv.tv_sec; + tr.tv_nsec = tv.tv_usec * 1000; + } else { + /* 2922 is the number of days between 1.1.1970 and 1.1.1978 */ + tv.tv_sec += (2922 * 24 * 60 + gmtoffset) * 60; + tr.tv_sec = tv.tv_sec; + tr.tv_nsec = tv.tv_usec * 1000; + } + /* And then convert it to a 64bit timespec */ + *t = valid_timespec_to_timespec64(tr); + } + } + + __timer_busy = FALSE; + RETURN(result); + return result; +} diff --git a/library/time/rdtsc.c b/library/time/rdtsc.c index 7d73ead5..de26c67c 100644 --- a/library/time/rdtsc.c +++ b/library/time/rdtsc.c @@ -1,27 +1,12 @@ /* - * $Id: time_srdtsc.c,v 1.0 2022-04-09 18:06:24 clib2devs Exp $ - * + * $Id: time_srdtsc.c,v 1.1 2023-02-22 18:06:24 clib2devs Exp $ */ #include -#include +#include -// This is a generic GCC version for 32 bit PowerPC machines. -// We need to loop because we are reading two registers and the high one might change. -uint64_t rdtsc(void) -{ - uint32_t high1 = 0, high2 = 0, low = 0; - - __asm__ __volatile__ - ( - "1: mftbu %0\n" - "mftb %1\n" - "mftbu %2\n" - "cmpw %3,%4\n" - "bne- 1b\n" - : "=r" (high1), "=r" (low), "=r" (high2) - : "0" (high1), "2" (high2) - ); - - return ((uint64_t)(high1) << 32) | low; +unsigned long long rdtsc(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; } \ No newline at end of file diff --git a/library/unistd/init_exit.c b/library/unistd/init_exit.c index 5aab48ff..4396eb72 100644 --- a/library/unistd/init_exit.c +++ b/library/unistd/init_exit.c @@ -11,13 +11,10 @@ #endif /* _STDLIB_CONSTRUCTOR_H */ /* Names of files and directories to delete when shutting down. */ -struct MinList NOCOMMON -__unlink_list; -struct SignalSemaphore NOCOMMON -__unlink_semaphore; +struct MinList NOCOMMON __unlink_list; +struct SignalSemaphore NOCOMMON __unlink_semaphore; -CLIB_CONSTRUCTOR(unistd_init) -{ +CLIB_CONSTRUCTOR(unistd_init) { ENTER(); NewList((struct List *)&__unlink_list); @@ -28,8 +25,7 @@ CLIB_CONSTRUCTOR(unistd_init) CONSTRUCTOR_SUCCEED(); } -CLIB_DESTRUCTOR(unistd_exit) -{ +CLIB_DESTRUCTOR(unistd_exit) { ENTER(); if (__unlink_list.mlh_Head != NULL && NOT IsMinListEmpty(&__unlink_list)) { diff --git a/library/unistd/lseek.c b/library/unistd/lseek.c index 0d2088c5..7d56a768 100644 --- a/library/unistd/lseek.c +++ b/library/unistd/lseek.c @@ -66,7 +66,7 @@ lseek(int file_descriptor, off_t offset, int mode) { result = position; - out: +out: __fd_unlock(fd); diff --git a/library/unistd/pread.c b/library/unistd/pread.c index 21affb5c..0312a18f 100644 --- a/library/unistd/pread.c +++ b/library/unistd/pread.c @@ -2,28 +2,25 @@ * $Id: unistd_pread.c,v 1.0 2021-02-21 23:05:27 clib2devs Exp $ */ -/****************************************************************************/ - #ifndef _UNISTD_HEADERS_H #include "unistd_headers.h" #endif /* _UNISTD_HEADERS_H */ ssize_t -pread(int fd, void *buf, size_t n, off_t off) -{ +pread(int fd, void *buf, size_t n, off_t off) { off_t cur_pos; ssize_t num_read; - if ((cur_pos = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) + if ((cur_pos = lseek(fd, 0, SEEK_CUR)) == (off_t) - 1) return -1; - if (lseek(fd, off, SEEK_SET) == (off_t)-1) + if (lseek(fd, off, SEEK_SET) == (off_t) - 1) return -1; num_read = read(fd, buf, n); - if (lseek(fd, cur_pos, SEEK_SET) == (off_t)-1) + if (lseek(fd, cur_pos, SEEK_SET) == (off_t) - 1) return -1; - return (ssize_t)num_read; + return (ssize_t) num_read; } diff --git a/library/unistd/pread64.c b/library/unistd/pread64.c new file mode 100644 index 00000000..2857e45b --- /dev/null +++ b/library/unistd/pread64.c @@ -0,0 +1,26 @@ +/* + * $Id: unistd_pread64.c,v 1.0 2023-03-03 23:05:27 clib2devs Exp $ +*/ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +ssize_t +pread64(int fd, void *buf, size_t n, off64_t off) { + off64_t cur_pos; + ssize_t num_read; + + if ((cur_pos = lseek64(fd, 0, SEEK_CUR)) == (off64_t) - 1) + return -1; + + if (lseek64(fd, off, SEEK_SET) == (off64_t) - 1) + return -1; + + num_read = read(fd, buf, n); + + if (lseek64(fd, cur_pos, SEEK_SET) == (off64_t) - 1) + return -1; + + return (ssize_t) num_read; +} diff --git a/library/unistd/pwrite.c b/library/unistd/pwrite.c index 84ff98ba..5d113759 100644 --- a/library/unistd/pwrite.c +++ b/library/unistd/pwrite.c @@ -1,5 +1,5 @@ /* - * $Id: unistd_pwrite.c,v 1.0 2021-02-21 23:09:27 clib2devs Exp $ + * $Id: unistd_pwrite.c,v 1.1 2022-03-04 23:09:27 clib2devs Exp $ */ #ifndef _UNISTD_HEADERS_H @@ -7,21 +7,29 @@ #endif /* _UNISTD_HEADERS_H */ ssize_t -pwrite(int fd, const void *buf, size_t n, off_t off) -{ +pwrite(int fd, const void *buf, size_t n, off_t off) { + ENTER(); + SHOWVALUE(fd); + SHOWVALUE(n); + SHOWVALUE(off); + ssize_t result = ERROR; off_t cur_pos; - ssize_t num_written; + + __set_errno(0); if ((cur_pos = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) - return -1; + goto out; if (lseek(fd, off, SEEK_SET) == (off_t)-1) - return -1; + goto out; - num_written = write(fd, buf, n); + result = write(fd, buf, n); if (lseek(fd, cur_pos, SEEK_SET) == (off_t)-1) - return -1; + result = ERROR; + +out: - return (ssize_t)num_written; + RETURN(result); + return result; } diff --git a/library/unistd/pwrite64.c b/library/unistd/pwrite64.c new file mode 100644 index 00000000..a8123369 --- /dev/null +++ b/library/unistd/pwrite64.c @@ -0,0 +1,26 @@ +/* + * $Id: unistd_pwrite64.c,v 1.0 2023-03-03 23:09:27 clib2devs Exp $ +*/ + +#ifndef _UNISTD_HEADERS_H +#include "unistd_headers.h" +#endif /* _UNISTD_HEADERS_H */ + +ssize_t +pwrite64(int fd, const void *buf, size_t n, off64_t off) { + off64_t cur_pos; + ssize_t num_written; + + if ((cur_pos = lseek64(fd, 0, SEEK_CUR)) == (off64_t) - 1) + return -1; + + if (lseek64(fd, off, SEEK_SET) == (off64_t) - 1) + return -1; + + num_written = write(fd, buf, n); + + if (lseek64(fd, cur_pos, SEEK_SET) == (off64_t) - 1) + return -1; + + return (ssize_t) num_written; +} diff --git a/library/unistd/realpath.c b/library/unistd/realpath.c index 332b78fb..6c55662c 100644 --- a/library/unistd/realpath.c +++ b/library/unistd/realpath.c @@ -19,8 +19,6 @@ realpath(const char *path_name, char *buffer) { SHOWSTRING(path_name); SHOWPOINTER(buffer); - assert(path_name != NULL && buffer != NULL); - __check_abort(); if (path_name == NULL || buffer == NULL) { diff --git a/library/unistd/setcurrentpath.c b/library/unistd/setcurrentpath.c index 98b9bea4..28ee93b9 100644 --- a/library/unistd/setcurrentpath.c +++ b/library/unistd/setcurrentpath.c @@ -1,5 +1,5 @@ /* - * $Id: unistd_setcurrentpath.c,v 1.5 2006-01-08 12:04:27 clib2devs Exp $ + * $Id: unistd_setcurrentpath.c,v 1.6 2023-03-05 12:04:27 clib2devs Exp $ */ #ifndef _UNISTD_HEADERS_H @@ -24,10 +24,18 @@ __set_current_path(const char *path_name) { } /* Only store the path if it's absolute. */ - if (path_name[0] == '/') - strcpy(__current_path_name, path_name); - else - strcpy(__current_path_name, ""); + if (__unix_path_semantics) { + if (path_name[0] == '/') + strcpy(__current_path_name, path_name); + else + strcpy(__current_path_name, ""); + } else { + if (strchr(path_name, ':')) + strcpy(__current_path_name, path_name); + else + strcpy(__current_path_name, ""); + + } result = OK; diff --git a/library/unistd/time_delay.c b/library/unistd/time_delay.c index 629d96b0..5ae245ca 100644 --- a/library/unistd/time_delay.c +++ b/library/unistd/time_delay.c @@ -29,12 +29,18 @@ __time_delay(ULONG timercmd, struct timeval *tv) { if (__timer_request == NULL) return EINVAL; + SHOWMSG("Clearing Signals"); SetSignal(0, SIGB_SINGLE | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E); + SHOWMSG("Allocating System Objects"); mp = AllocSysObjectTags(ASOT_PORT, ASOPORT_AllocSig, FALSE, ASOPORT_Signal, SIGB_SINGLE, TAG_DONE); + if (!mp) { + SHOWMSG("Cannot allocate Message Port"); + return ENOMEM; + } tr = AllocSysObjectTags(ASOT_IOREQUEST, ASOIOR_Duplicate, __timer_request, @@ -42,6 +48,7 @@ __time_delay(ULONG timercmd, struct timeval *tv) { ASOIOR_Size, sizeof(struct TimeRequest), TAG_END); if (!tr) { + SHOWMSG("Cannot allocate Timer Request"); FreeSysObject(ASOT_IOREQUEST, mp); return ENOMEM; } @@ -50,19 +57,23 @@ __time_delay(ULONG timercmd, struct timeval *tv) { tr->Time.Seconds = tv->tv_sec; tr->Time.Microseconds = tv->tv_usec; + SHOWMSG("Send IO Request"); SendIO((struct IORequest *) tr); wait_mask = SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_C | 1L << mp->mp_SigBit; /* Wait for signals */ + SHOWMSG("Waiting for signal"); uint32 signals = Wait(wait_mask); if (signals & SIGBREAKF_CTRL_C || signals & SIGBREAKF_CTRL_E) { if (CheckIO((struct IORequest *) tr)) /* If request is complete... */ WaitIO((struct IORequest *) tr); /* clean up and remove reply */ AbortIO((struct IORequest *) tr); if (signals & SIGBREAKF_CTRL_E) { + SHOWMSG("Received SIGBREAKF_CTRL_E"); /* Return EINTR since the request has been interrupted by alarm */ result = EINTR; } else { + SHOWMSG("Received SIGBREAKF_CTRL_C. Reset it to set state"); /* Reset SIGBREAKF_CTRL_C to set state since __check_abort can * break the execution */ @@ -71,10 +82,14 @@ __time_delay(ULONG timercmd, struct timeval *tv) { } WaitIO((struct IORequest *) tr); + SHOWVALUE("tr->Time.Seconds"); + SHOWVALUE("tr->Time.Microseconds"); tv->tv_sec = tr->Time.Seconds; tv->tv_usec = tr->Time.Microseconds; - FreeSysObject(ASOT_MESSAGE, tr); + SHOWMSG("Freeing Request Object"); + FreeSysObject(ASOT_IOREQUEST, tr); + SHOWMSG("Freeing Message Port"); FreeSysObject(ASOT_PORT, mp); __check_abort(); diff --git a/library/unistd/timer.c b/library/unistd/timer.c index 07044747..d0f5bc5d 100644 --- a/library/unistd/timer.c +++ b/library/unistd/timer.c @@ -34,50 +34,42 @@ BOOL NOCOMMON __timer_busy; struct Library *NOCOMMON __TimerBase; struct TimerIFace *NOCOMMON __ITimer; -/****************************************************************************/ - -CLIB_CONSTRUCTOR(timer_init) -{ +CLIB_CONSTRUCTOR(timer_init) { BOOL success = FALSE; ENTER(); __timer_port = AllocSysObjectTags(ASOT_PORT, ASOPORT_AllocSig, FALSE, ASOPORT_Signal, SIGB_SINGLE, TAG_DONE); - if (__timer_port == NULL) - { + if (__timer_port == NULL) { __show_error("The timer message port could not be created."); goto out; } - + SHOWMSG("__timer_port allocated"); + __timer_request = AllocSysObjectTags(ASOT_MESSAGE, ASOMSG_Size, sizeof(struct TimeRequest), ASOMSG_ReplyPort, __timer_port, TAG_DONE); - if (__timer_request == NULL) - { + if (__timer_request == NULL) { __show_error("The timer I/O request could not be created."); goto out; } + SHOWMSG("__timer_request allocated"); - if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)__timer_request, 0) != OK) - { + if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)__timer_request, 0) != OK) { __show_error("The timer could not be opened."); goto out; } + SHOWMSG("OpenDevice opened"); __TimerBase = (struct Library *)__timer_request->tr_node.io_Device; + SHOWPOINTER(__TimerBase); __ITimer = (struct TimerIFace *)GetInterface(__TimerBase, "main", 1, 0); - if (__ITimer == NULL) - { + SHOWPOINTER(__ITimer); + if (__ITimer == NULL) { + SHOWMSG("__ITimer is NULL"); __show_error("The timer interface could not be obtained."); goto out; } - /* Set system time for rusage */ - struct TimerIFace *ITimer = __ITimer; - GetSysTime(&__global_clib2->clock); - /* Generate random seed */ - __global_clib2->__random_seed = time(NULL); - - -success = TRUE; + success = TRUE; out: diff --git a/library/wchar/vwscanf.c b/library/wchar/vwscanf.c index 73694e84..a2e39fad 100644 --- a/library/wchar/vwscanf.c +++ b/library/wchar/vwscanf.c @@ -12,8 +12,6 @@ vwscanf(const wchar_t *fmt, va_list ap) { ENTER(); - SHOWSTRING(fmt); - assert(fmt != NULL); if (fmt == NULL) { diff --git a/library/wchar/wcwidth.c b/library/wchar/wcwidth.c index ad28be12..68fd5ddc 100644 --- a/library/wchar/wcwidth.c +++ b/library/wchar/wcwidth.c @@ -11,13 +11,11 @@ int wcwidth(const wchar_t wc) { int result = -1; - ENTER(); if (iswprint(wc)) result = 1; else if (iswcntrl(wc) || wc == L'\0') result = 0; - RETURN(result); return result; } diff --git a/test_programs/aio/aio1.c b/test_programs/aio/aio1.c new file mode 100644 index 00000000..736a7ec4 --- /dev/null +++ b/test_programs/aio/aio1.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#define __USE_GNU +#include +#include + +#define BUF_SIZE 20 /* Size of buffers for read operations */ + +#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) + +struct ioRequest { /* Application-defined structure for tracking + I/O requests */ + int reqNum; + int status; + struct aiocb *aiocbp; +}; + +static volatile sig_atomic_t gotSIGQUIT = 0; + +/* On delivery of SIGQUIT, we attempt to + cancel all outstanding I/O requests */ + +static void /* Handler for SIGQUIT */ +quitHandler(int sig) { + gotSIGQUIT = 1; +} + +#define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ + +static void /* Handler for I/O completion signal */ +aioSigHandler(int sig, siginfo_t *si, void *ucontext) { + if (si->si_code == SI_ASYNCIO) { + write(STDOUT_FILENO, "I/O completion signal received\n", 31); + + /* The corresponding ioRequest structure would be available as + struct ioRequest *ioReq = si->si_value.sival_ptr; + and the file descriptor would then be available via + ioReq->aiocbp->aio_fildes */ + } +} + +int +main(int argc, char *argv[]) { + struct sigaction sa; + int s; + int numReqs; /* Total number of queued I/O requests */ + int openReqs; /* Number of I/O requests still in progress */ + + if (argc < 2) { + fprintf(stderr, "Usage: %s ...\n", argv[0]); + exit(EXIT_FAILURE); + } + + numReqs = argc - 1; + + /* Allocate our arrays. */ + + struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList)); + if (ioList == NULL) + errExit("calloc"); + + struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList)); + if (aiocbList == NULL) + errExit("calloc"); + + /* Establish handlers for SIGQUIT and the I/O completion signal. */ + + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + + sa.sa_handler = quitHandler; + if (sigaction(SIGQUIT, &sa, NULL) == -1) + errExit("sigaction"); + + sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_sigaction = aioSigHandler; + if (sigaction(IO_SIGNAL, &sa, NULL) == -1) + errExit("sigaction"); + + /* Open each file specified on the command line, and queue + a read request on the resulting file descriptor. */ + + for (int j = 0; j < numReqs; j++) { + ioList[j].reqNum = j; + ioList[j].status = EINPROGRESS; + ioList[j].aiocbp = &aiocbList[j]; + + ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY); + if (ioList[j].aiocbp->aio_fildes == -1) + errExit("open"); + printf("opened %s on descriptor %d\n", argv[j + 1], ioList[j].aiocbp->aio_fildes); + + ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE); + if (ioList[j].aiocbp->aio_buf == NULL) + errExit("malloc"); + + ioList[j].aiocbp->aio_nbytes = BUF_SIZE; + ioList[j].aiocbp->aio_reqprio = 0; + ioList[j].aiocbp->aio_offset = 0; + ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL; + ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL; + ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr = &ioList[j]; + + s = aio_read(ioList[j].aiocbp); + if (s == -1) + errExit("aio_read"); + } + + openReqs = numReqs; + + /* Loop, monitoring status of I/O requests. */ + while (openReqs > 0) { + sleep(3); /* Delay between each monitoring step */ + + if (gotSIGQUIT) { + /* On receipt of SIGQUIT, attempt to cancel each of the + outstanding I/O requests, and display status returned + from the cancellation requests. */ + + printf("got SIGQUIT; canceling I/O requests: \n"); + + for (int j = 0; j < numReqs; j++) { + if (ioList[j].status == EINPROGRESS) { + printf(" Request %d on descriptor %d:", j, ioList[j].aiocbp->aio_fildes); + s = aio_cancel(ioList[j].aiocbp->aio_fildes, ioList[j].aiocbp); + if (s == AIO_CANCELED) + printf("I/O canceled\n"); + else if (s == AIO_NOTCANCELED) + printf("I/O not canceled\n"); + else if (s == AIO_ALLDONE) + printf("I/O all done\n"); + else + perror("aio_cancel"); + } + } + + gotSIGQUIT = 0; + } + + /* Check the status of each I/O request that is still + in progress. */ + + printf("aio_error():\n"); + for (int j = 0; j < numReqs; j++) { + if (ioList[j].status == EINPROGRESS) { + printf(" for request %d (descriptor %d): ", j, ioList[j].aiocbp->aio_fildes); + ioList[j].status = aio_error(ioList[j].aiocbp); + + switch (ioList[j].status) { + case 0: + printf("I/O succeeded\n"); + break; + case EINPROGRESS: + printf("In progress\n"); + break; + case ECANCELED: + printf("Canceled\n"); + break; + default: + perror("aio_error"); + break; + } + + if (ioList[j].status != EINPROGRESS) + openReqs--; + } + } + } + + printf("All I/O requests completed\n"); + + /* Check status return of all I/O requests. */ + + printf("aio_return():\n"); + for (int j = 0; j < numReqs; j++) { + ssize_t s; + + s = aio_return(ioList[j].aiocbp); + printf(" for request %d (descriptor %d): %zd\n", j, ioList[j].aiocbp->aio_fildes, s); + } + + exit(EXIT_SUCCESS); +} \ No newline at end of file diff --git a/test_programs/aio/aio2.c b/test_programs/aio/aio2.c new file mode 100644 index 00000000..ba6e9e11 --- /dev/null +++ b/test_programs/aio/aio2.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +#define BUFSIZE 1024 + +int main(void) { + int fd, ret; + struct aiocb my_aiocb; + + fd = open("file.txt", O_RDONLY); + if (fd < 0) + perror("open"); + + bzero((char *) &my_aiocb, sizeof(struct aiocb)); + + my_aiocb.aio_buf = calloc(1, BUFSIZE + 1); + if (!my_aiocb.aio_buf) + perror("malloc"); + + my_aiocb.aio_fildes = fd; + my_aiocb.aio_nbytes = BUFSIZE; + my_aiocb.aio_offset = 0; + + ret = aio_read(&my_aiocb); + if (ret < 0) + perror("aio_read"); + + while (aio_error(&my_aiocb) == EINPROGRESS) + continue; + + if ((ret = aio_return(&my_aiocb))) { + printf("ret:%d,read:%s\n", ret, my_aiocb.aio_buf); + } else { + printf("read 0\n"); + } + + + close(fd); + return 0; +} \ No newline at end of file diff --git a/test_programs/aio/aio_client.c b/test_programs/aio/aio_client.c new file mode 100644 index 00000000..3794a2f5 --- /dev/null +++ b/test_programs/aio/aio_client.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE (100) + +#ifndef __amigaos4__ +#define sigval_t __sigval_t +#endif + +void aio_read_completion_handler(sigval_t sigval); +void aio_write_completion_handler(sigval_t sigval); +struct aiocb my_aiocb1, my_aiocb2; + +// Global variables +struct aiocb *cblist[2]; +int theSocket; + +void InitializeAiocbData(struct aiocb *pAiocb, char *pBuffer) { + bzero((char *) pAiocb, sizeof(struct aiocb)); + + pAiocb->aio_fildes = theSocket; + pAiocb->aio_nbytes = BUFSIZE; + pAiocb->aio_offset = 0; + pAiocb->aio_buf = pBuffer; +} + +void IssueReadOperation(struct aiocb *pAiocb, char *pBuffer) { + InitializeAiocbData(pAiocb, pBuffer); + + /* Link the AIO request with a thread callback */ + pAiocb->aio_sigevent.sigev_notify = SIGEV_THREAD; + pAiocb->aio_sigevent.sigev_notify_function = aio_read_completion_handler; + pAiocb->aio_sigevent.sigev_notify_attributes = NULL; + pAiocb->aio_sigevent.sigev_value.sival_ptr = &my_aiocb1; + + int ret = aio_read(pAiocb); + assert(ret >= 0); +} + +void IssueWriteOperation(struct aiocb *pAiocb, char *pBuffer) { + InitializeAiocbData(pAiocb, pBuffer); + + /* Link the AIO request with a thread callback */ + pAiocb->aio_sigevent.sigev_notify = SIGEV_THREAD; + pAiocb->aio_sigevent.sigev_notify_function = aio_write_completion_handler; + pAiocb->aio_sigevent.sigev_notify_attributes = NULL; + pAiocb->aio_sigevent.sigev_value.sival_ptr = &my_aiocb2; + + int ret = aio_write(pAiocb); + assert(ret >= 0); +} + +void aio_write_completion_handler(sigval_t sigval) { + struct aiocb *req; + req = (struct aiocb *) sigval.sival_ptr; +} + +void aio_read_completion_handler(sigval_t sigval) { + struct aiocb *req; + req = (struct aiocb *) sigval.sival_ptr; +} + +int main() { + int ret; + int nPort = 11111; + char *szServer = "102.168.0.204"; + + // Connect to the remote server + theSocket = socket(AF_INET, SOCK_STREAM, 0); + assert(theSocket >= 0); + + struct hostent *pServer; + struct sockaddr_in serv_addr; + pServer = gethostbyname(szServer); + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(nPort); + bcopy((char *) pServer->h_addr, (char *) &serv_addr.sin_addr.s_addr, pServer->h_length); + + assert(connect(theSocket, (const struct sockaddr *) (&serv_addr), sizeof(serv_addr)) >= 0); + + // Construct the AIO callbacks array + char *pBuffer = malloc(BUFSIZE + 1); + + bzero((char *) cblist, sizeof(cblist)); + cblist[0] = &my_aiocb1; + cblist[1] = &my_aiocb2; + + // Start the read and write operations on the same socket + IssueReadOperation(&my_aiocb1, pBuffer); + IssueWriteOperation(&my_aiocb2, pBuffer); + + // Wait for I/O completion on both operations + int nRound = 1; + printf("\naio_suspend round #%d:\n", nRound++); + ret = aio_suspend(cblist, 2, NULL); + assert(ret == 0); + + // Check the error status for the read and write operations + ret = aio_error(&my_aiocb1); + assert(ret == EWOULDBLOCK); + + // Get the return code for the read + { + ssize_t retcode = aio_return(&my_aiocb1); + printf("First read operation results: aio_error=%d, aio_return=%d - That's the first EWOULDBLOCK\n", ret, retcode); + } + + ret = aio_error(&my_aiocb2); + assert(ret == EINPROGRESS); + printf("Write operation is still \"in progress\"\n"); + + // Re-issue the read operation + IssueReadOperation(&my_aiocb1, pBuffer); + + // Wait for I/O completion on both operations + printf("\naio_suspend round #%d:\n", nRound++); + ret = aio_suspend(cblist, 2, NULL); + assert(ret == 0); + + // Check the error status for the read and write operations for the second time + ret = aio_error(&my_aiocb1); + assert(ret == EINPROGRESS); + printf("Second read operation request is suddenly marked as \"in progress\"\n"); + + ret = aio_error(&my_aiocb2); + assert(ret == 0); + + // Get the return code for the write + { + ssize_t retcode = aio_return(&my_aiocb2); + printf("Write operation has completed with results: aio_error=%d, aio_return=%d\n", ret, retcode); + } + + // Now try waiting for the read operation to complete - it'll just busy-wait, receiving "EWOULDBLOCK" indefinitely + do { + printf("\naio_suspend round #%d:\n", nRound++); + ret = aio_suspend(cblist, 1, NULL); + assert(ret == 0); + + // Check the error of the read operation and re-issue if needed + ret = aio_error(&my_aiocb1); + if (ret == EWOULDBLOCK) { + IssueReadOperation(&my_aiocb1, pBuffer); + printf("EWOULDBLOCK again on the read operation!\n"); + } + } while (ret == EWOULDBLOCK); + + free(pBuffer); + + return 0; +} \ No newline at end of file diff --git a/test_programs/aio/aio_suspend1.c b/test_programs/aio/aio_suspend1.c new file mode 100644 index 00000000..6a6752e1 --- /dev/null +++ b/test_programs/aio/aio_suspend1.c @@ -0,0 +1,50 @@ +#include +#include + +char CONTENT[] = "asdf;"; +const int LENGTH = 5; + +struct aiocb createIoRequest(int fd, off_t offset, volatile void *content, size_t length) { + // create and initialize the aiocb structure. + // If we don't init to 0, we have undefined behavior. + // E.g. through sigevent op.aio_sigevent there could be + // a callback function being set, that the program + // tries to call - which will then fail. + struct aiocb ret = {0}; + { + ret.aio_fildes = fd; + ret.aio_offset = offset; + ret.aio_buf = content; + ret.aio_nbytes = length; + } + return ret; +} + + +int main() { + FILE *file = fopen("RAM:outfile.txt", "w"); + int fd = fileno(file); + + struct aiocb op = createIoRequest(fd, 0, CONTENT, LENGTH); + + // schedule write + // for valgrind mem leak output see comments from answer in + // https://stackoverflow.com/questions/4248720/aio-h-aio-read-and-write-memory-leak + int ret = aio_write(&op); + printf("aio_write 1: %d\n", ret); + + // wait until everything is done + const struct aiocb *aiolist[1]; + aiolist[0] = &op; + + ret = aio_suspend(aiolist, 1, NULL); + printf("aio_suspend: %d\n", ret); + + // report possible errors + ret = aio_error(&op); + printf("errno 1: %d\n", ret); + + fclose(file); + + return 0; +} \ No newline at end of file diff --git a/test_programs/aio/aio_suspend2.c b/test_programs/aio/aio_suspend2.c new file mode 100644 index 00000000..d7b9c6fb --- /dev/null +++ b/test_programs/aio/aio_suspend2.c @@ -0,0 +1,59 @@ +#include +#include + +char CONTENT[] = "asdf;"; +const int LENGTH = 5; + +struct aiocb createIoRequest(int fd, off_t offset, volatile void *content, size_t length) { + // create and initialize the aiocb structure. + // If we don't init to 0, we have undefined behavior. + // E.g. through sigevent op.aio_sigevent there could be + // a callback function being set, that the program + // tries to call - which will then fail. + struct aiocb ret = {0}; + { + ret.aio_fildes = fd; + ret.aio_offset = offset; + ret.aio_buf = content; + ret.aio_nbytes = length; + } + return ret; +} + + +int main() { + FILE *file = fopen("RAM:outfile.txt", "w"); + int fd = fileno(file); + + struct aiocb op = createIoRequest(fd, 0, CONTENT, LENGTH); + struct aiocb op2 = createIoRequest(fd, LENGTH, CONTENT, LENGTH); + + // schedule write + // for valgrind mem leak output see comments from answer in + // https://stackoverflow.com/questions/4248720/aio-h-aio-read-and-write-memory-leak + int ret = aio_write(&op); + printf("aio_write 1: %d\n", ret); + ret = aio_write(&op2); + printf("aio_write 2: %d\n", ret); + + // wait until everything is done + + const int OPs = 2; + const struct aiocb *aiolist[OPs]; + aiolist[0] = &op; + aiolist[1] = &op2; + + ret = aio_suspend(aiolist, OPs, NULL); + printf("aio_suspend: %d\n", ret); + + // report possible errors + ret = aio_error(&op); + printf("errno 1: %d\n", ret); + ret = aio_error(&op2); + printf("errno 2: %d\n", ret); + // error codes can be checked in + + fclose(file); + + return 0; +} \ No newline at end of file diff --git a/test_programs/aio/testcancel.c b/test_programs/aio/testcancel.c new file mode 100644 index 00000000..03461155 --- /dev/null +++ b/test_programs/aio/testcancel.c @@ -0,0 +1,309 @@ +/* Copyright (C) 2003-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#define __USE_GNU +#include + +static pthread_barrier_t b; + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl(void *arg) { + ++cl_called; +} + + +static void * +tf(void *arg) { + int r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("tf: barrier_wait failed"); + exit(1); + } + + pthread_cleanup_push(cl, NULL); + + const struct aiocb *l[1] = {arg}; + + TEMP_FAILURE_RETRY(aio_suspend(l, 1, NULL)); + + pthread_cleanup_pop(0); + + puts("tf: aio_suspend returned"); + + exit(1); +} + + +static void * +tf2(void *arg) { + int r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("tf2: barrier_wait failed"); + exit(1); + } + + pthread_cleanup_push(cl, NULL); + + const struct aiocb *l[1] = {arg}; + struct timespec ts = {.tv_sec = 1000, .tv_nsec = 0}; + + TEMP_FAILURE_RETRY(aio_suspend(l, 1, &ts)); + + pthread_cleanup_pop(0); + + puts("tf2: aio_suspend returned"); + + exit(1); +} + + +int main(int argc, char *argv[]) { + int fds[2]; + if (pipe(fds) != 0) { + puts("pipe failed"); + return 1; + } + + struct aiocb a, a2, *ap; + char mem[1]; + memset(&a, '\0', sizeof(a)); + a.aio_fildes = fds[0]; + a.aio_buf = mem; + a.aio_nbytes = sizeof(mem); + if (aio_read(&a) != 0) { + puts("aio_read failed"); + return 1; + } + + if (pthread_barrier_init(&b, NULL, 2) != 0) { + puts("barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create(&th, NULL, tf, &a) != 0) { + puts("1st create failed"); + return 1; + } + + int r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("barrier_wait failed"); + exit(1); + } + + struct timespec ts = {.tv_sec = 0, .tv_nsec = 100000000}; + while (nanosleep(&ts, &ts) != 0) + continue; + + puts("going to cancel tf in-time"); + if (pthread_cancel(th) != 0) { + puts("1st cancel failed"); + return 1; + } + + void *status; + if (pthread_join(th, &status) != 0) { + puts("1st join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) { + puts("1st thread not canceled"); + return 1; + } + + if (cl_called == 0) { + puts("tf cleanup handler not called"); + return 1; + } + if (cl_called > 1) { + puts("tf cleanup handler called more than once"); + return 1; + } + + cl_called = 0; + + if (pthread_create(&th, NULL, tf2, &a) != 0) { + puts("2nd create failed"); + return 1; + } + + r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("2nd barrier_wait failed"); + exit(1); + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + while (nanosleep(&ts, &ts) != 0) + continue; + + puts("going to cancel tf2 in-time"); + if (pthread_cancel(th) != 0) { + puts("2nd cancel failed"); + return 1; + } + + if (pthread_join(th, &status) != 0) { + puts("2nd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) { + puts("2nd thread not canceled"); + return 1; + } + + if (cl_called == 0) { + puts("tf2 cleanup handler not called"); + return 1; + } + if (cl_called > 1) { + puts("tf2 cleanup handler called more than once"); + return 1; + } + + puts("in-time cancellation succeeded"); + + ap = &a; + if (aio_cancel(fds[0], &a) != AIO_CANCELED) { + puts("aio_cancel failed"); + /* If aio_cancel failed, we cannot reuse aiocb a. */ + ap = &a2; + } + + + cl_called = 0; + + size_t len2 = fpathconf(fds[1], _PC_PIPE_BUF); + size_t page_size = sysconf(_SC_PAGESIZE); + len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof(mem) + 1; + char *mem2 = malloc(len2); + if (mem2 == NULL) { + puts("could not allocate memory for pipe write"); + return 1; + } + + memset(ap, '\0', sizeof(*ap)); + ap->aio_fildes = fds[1]; + ap->aio_buf = mem2; + ap->aio_nbytes = len2; + if (aio_write(ap) != 0) { + puts("aio_write failed"); + return 1; + } + + if (pthread_create(&th, NULL, tf, ap) != 0) { + puts("3rd create failed"); + return 1; + } + + puts("going to cancel tf early"); + if (pthread_cancel(th) != 0) { + puts("3rd cancel failed"); + return 1; + } + + r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("3rd barrier_wait failed"); + exit(1); + } + + if (pthread_join(th, &status) != 0) { + puts("3rd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) { + puts("3rd thread not canceled"); + return 1; + } + + if (cl_called == 0) { + puts("tf cleanup handler not called"); + return 1; + } + if (cl_called > 1) { + puts("tf cleanup handler called more than once"); + return 1; + } + + cl_called = 0; + + if (pthread_create(&th, NULL, tf2, ap) != 0) { + puts("4th create failed"); + return 1; + } + + puts("going to cancel tf2 early"); + if (pthread_cancel(th) != 0) { + puts("4th cancel failed"); + return 1; + } + + r = pthread_barrier_wait(&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) { + puts("4th barrier_wait failed"); + exit(1); + } + + if (pthread_join(th, &status) != 0) { + puts("4th join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) { + puts("4th thread not canceled"); + return 1; + } + + if (cl_called == 0) { + puts("tf2 cleanup handler not called"); + return 1; + } + if (cl_called > 1) { + puts("tf2 cleanup handler called more than once"); + return 1; + } + + puts("early cancellation succeeded"); + + if (ap == &a2) { + /* The aio_read(&a) was not canceled because the read request was + already in progress. In the meanwhile aio_write(ap) wrote something + to the pipe and the read request either has already been finished or + is able to read the requested byte. + Wait for the read request before returning from this function because + the return value and error code from the read syscall will be written + to the struct aiocb a, which lies on the stack of this function. + Otherwise the stack from subsequent function calls - e.g. _dl_fini - + will be corrupted, which can lead to undefined behaviour like a + segmentation fault. */ + const struct aiocb *l[1] = {&a}; + TEMP_FAILURE_RETRY(aio_suspend(l, 1, NULL)); + } + + return 0; +} diff --git a/test_programs/bsd/ifconfig.c b/test_programs/bsd/ifconfig.c index 67a418b2..0f2f7e43 100644 --- a/test_programs/bsd/ifconfig.c +++ b/test_programs/bsd/ifconfig.c @@ -354,10 +354,7 @@ struct afswtch { struct afswtch *afp; /*the address family being set or asked about*/ -int main(argc, argv) - int argc; - char *argv[]; -{ +int main(int argc, char *argv[]) { int af = AF_INET; register struct afswtch *rafp; diff --git a/test_programs/exceptions/try1.cpp b/test_programs/exceptions/try1.cpp new file mode 100644 index 00000000..3539a66b --- /dev/null +++ b/test_programs/exceptions/try1.cpp @@ -0,0 +1,19 @@ +#include + +using namespace std; + +int main() { + try { + int age = 15; + if (age >= 18) { + cout << "Access granted - you are old enough."; + } else { + throw (age); + } + } + catch (int myNum) { + cout << "Access denied - You must be at least 18 years old.\n"; + cout << "Age is: " << myNum << endl; + } + return 0; +} diff --git a/test_programs/exceptions/try2.cpp b/test_programs/exceptions/try2.cpp new file mode 100644 index 00000000..28c5fce0 --- /dev/null +++ b/test_programs/exceptions/try2.cpp @@ -0,0 +1,18 @@ +#include + +using namespace std; + +int main() { + try { + int age = 15; + if (age >= 18) { + cout << "Access granted - you are old enough."; + } else { + throw 505; + } + } + catch (...) { + cout << "Access denied - You must be at least 18 years old.\n"; + } + return 0; +} diff --git a/test_programs/exceptions/try3.cpp b/test_programs/exceptions/try3.cpp new file mode 100644 index 00000000..dbbdb144 --- /dev/null +++ b/test_programs/exceptions/try3.cpp @@ -0,0 +1,23 @@ +#include + +using namespace std; + +float division(int x, int y) { + if (y == 0) { + throw "Attempted to divide by zero!"; + } + return (x / y); +} + +int main() { + int i = 25; + int j = 0; + float k = 0; + try { + k = division(i, j); + cout << k << endl; + } catch (const char *e) { + cerr << e << endl; + } + return 0; +} \ No newline at end of file diff --git a/test_programs/io/fopen.c b/test_programs/io/fopen.c index e92720c8..2e4bd14c 100755 --- a/test_programs/io/fopen.c +++ b/test_programs/io/fopen.c @@ -6,8 +6,7 @@ #define BUFFER_SIZE 1024 -off_t filesize(FILE *fp) -{ +off_t filesize(FILE *fp) { long int save_pos; long size_of_file; @@ -25,8 +24,7 @@ off_t filesize(FILE *fp) return (size_of_file); } -_off64_t filesize64(FILE *fp) -{ +_off64_t filesize64(FILE *fp) { _off64_t save_pos; _off64_t size_of_file; @@ -44,27 +42,23 @@ _off64_t filesize64(FILE *fp) return (size_of_file); } -int main(int argc, char **argv) -{ - if (argc != 2) - { +int main(int argc, char **argv) { + if (argc != 2) { printf("Usage: fopen LARGEFILE\n"); return -1; } FILE *fd = fopen(argv[1], "wb"); - if (fd != NULL) - { - char buffer[] = {'x', 'y', 'z'}; + if (fd != NULL) { + char buffer[] = {'x', 'y', 'z', '\0'}; fwrite(buffer, sizeof(char), sizeof(buffer), fd); size_t result = fread(buffer, sizeof(char), sizeof(buffer), fd); printf("buffer = %s\n", buffer); fclose(fd); } - fd = fopen("test.txt", "r"); - if (fd != NULL) - { + fd = fopen(argv[1], "r"); + if (fd != NULL) { off_t size1 = filesize(fd); _off64_t size2 = filesize64(fd); printf("Size1 = %ld\n", size1); diff --git a/test_programs/memory/ramspeed.c b/test_programs/memory/ramspeed.c new file mode 100644 index 00000000..30948256 --- /dev/null +++ b/test_programs/memory/ramspeed.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +static unsigned int unalign; + +struct test_fct { + const char *name; + + unsigned int (*f)(unsigned int, unsigned int); +}; + +#ifndef CLIB2 +static inline unsigned long long rdtsc() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} +#endif + +unsigned int bench_memcpy(unsigned int loop, unsigned int size) { + unsigned long long before, after; + unsigned int i; + void *src, *dst; + + posix_memalign(&src, 64, size); + posix_memalign(&dst, 64, size + unalign); + + /* ensure the pages are allocated */ + memset(src, 0, size); + memset(dst, 0, size); + + before = rdtsc(); + for (i = 0; i < loop; i++) { + memcpy(dst + unalign, src, size); + asm("":: : "memory"); + } + after = rdtsc(); + + free(src); + free(dst); + return after - before; +} + +unsigned int bench_memchr(unsigned int loop, unsigned int size) { + unsigned long long before, after; + unsigned int i; + char *dst; + + dst = malloc(size); + + /* ensure the pages are allocated */ + memset(dst, 0, size); + + before = rdtsc(); + for (i = 0; i < loop; i++) { + if (memchr(dst, i | 1, size)) + return 0; + asm("":: : "memory"); + } + + after = rdtsc(); + + free(dst); + return after - before; +} + +unsigned int bench_memset(unsigned int loop, unsigned int size) { + unsigned long long before, after; + unsigned int i; + char *dst; + + dst = malloc(size); + + /* ensure the pages are allocated */ + memset(dst, 0, size); + + before = rdtsc(); + for (i = 0; i < loop; i++) { + memset(dst, i, size); + asm("":: : "memory"); + } + after = rdtsc(); + + free(dst); + return after - before; +} + +static struct test_fct test_fcts[] = { + {"bench_memchr", bench_memchr}, + {"bench_memset", bench_memset}, + {"bench_memcpy", bench_memcpy}, + {NULL, NULL} +}; + +void run_bench(unsigned int loop, unsigned int size) { + unsigned int usecs; + struct test_fct *t = test_fcts; + + printf("Running tests with %d loops of %d bytes\n", loop, size); + + while (t->name && t->f) { + usecs = t->f(loop, size); + printf("%s: %ld us for %d loops of %d bytes = %lld kB/s\n", + t->name, + usecs, loop, size, (unsigned long long) 1024ULL * loop * size / usecs); + t++; + } +} + +int main(int argc, char **argv) { + unsigned int size; + unsigned int loop; + + loop = 10; + size = 16777216; + + if (argc > 1) + loop = atoi(argv[1]); + + if (argc > 2) + size = atoi(argv[2]); + + if (argc > 3) + unalign = atoi(argv[3]); + + run_bench(loop, size); + exit(0); +} \ No newline at end of file diff --git a/test_programs/misc/errno.c b/test_programs/misc/errno.c new file mode 100644 index 00000000..e719794b --- /dev/null +++ b/test_programs/misc/errno.c @@ -0,0 +1,23 @@ +#include +#include +#include + +extern int errno; + +int main() { + + FILE *pf; + int errnum; + pf = fopen("unexist.txt", "rb"); + + if (pf == NULL) { + errnum = errno; + fprintf(stderr, "Value of errno: %d\n", errno); + perror("Error printed by perror"); + fprintf(stderr, "Error opening file: %s\n", strerror(errnum)); + } else { + fclose(pf); + } + + return 0; +} \ No newline at end of file diff --git a/test_programs/profile/test_grpof.c b/test_programs/profile/test_gprof.c similarity index 74% rename from test_programs/profile/test_grpof.c rename to test_programs/profile/test_gprof.c index 8360c51f..f3d48121 100644 --- a/test_programs/profile/test_grpof.c +++ b/test_programs/profile/test_gprof.c @@ -1,3 +1,7 @@ +/* https://www.thegeekstuff.com/2012/08/gprof-tutorial/ + * compile with: + * ppc-amigaos -mcrt=clib2 -pg test_gprof.c -o test_gprof -lprofile +*/ #include void new_func1(void) { diff --git a/test_programs/misc/setjmp.c b/test_programs/setjmp/setjmp.c similarity index 100% rename from test_programs/misc/setjmp.c rename to test_programs/setjmp/setjmp.c diff --git a/test_programs/setjmp/setjmp1.c b/test_programs/setjmp/setjmp1.c new file mode 100644 index 00000000..87ea05f7 --- /dev/null +++ b/test_programs/setjmp/setjmp1.c @@ -0,0 +1,240 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* The setjmp()/longjmp(), sigsetjmp()/siglongjmp(). */ + +#include +#include +#include +#include +#include +#include + +#ifndef UNUSED +#define UNUSED __attribute__((unused)) +#endif + +int nerrors; +int verbose; + +static jmp_buf jbuf; +static sigjmp_buf sigjbuf; +static sigset_t sigset4; + +void +raise_longjmp(jmp_buf jbuf, int i, int n) { + while (i < n) + raise_longjmp(jbuf, i + 1, n); + + longjmp(jbuf, n); +} + +void +test_setjmp(void) { + volatile int i; + jmp_buf jbuf; + int ret; + + for (i = 0; i < 10; ++i) { + if ((ret = setjmp(jbuf))) { + if (verbose) + printf("%s: secondary setjmp () return, ret=%d\n", __FUNCTION__, ret); + if (ret != i + 1) { + fprintf(stderr, "%s: setjmp() returned %d, expected %d\n", __FUNCTION__, ret, i + 1); + ++nerrors; + } + continue; + } + if (verbose) + printf("%s.%d: done with setjmp(); calling children\n", __FUNCTION__, i + 1); + + raise_longjmp(jbuf, 0, i + 1); + + fprintf(stderr, "%s: raise_longjmp() returned unexpectedly\n", __FUNCTION__); + ++nerrors; + } +} + + +void +raise_siglongjmp(sigjmp_buf jbuf, int i, int n) { + while (i < n) + raise_siglongjmp(jbuf, i + 1, n); + + siglongjmp(jbuf, n); +} + +void +test_sigsetjmp(void) { + sigjmp_buf jbuf; + volatile int i; + int ret; + + for (i = 0; i < 10; ++i) { + if ((ret = sigsetjmp(jbuf, 1))) { + if (verbose) + printf("%s: secondary sigsetjmp () return, ret=%d\n", __FUNCTION__, ret); + if (ret != i + 1) { + fprintf(stderr, "%s: sigsetjmp() returned %d, expected %d\n", __FUNCTION__, ret, i + 1); + ++nerrors; + } + continue; + } + if (verbose) + printf("%s.%d: done with sigsetjmp(); calling children\n", __FUNCTION__, i + 1); + + raise_siglongjmp(jbuf, 0, i + 1); + + fprintf(stderr, "%s: raise_siglongjmp() returned unexpectedly\n", __FUNCTION__); + ++nerrors; + } +} + +void +sighandler(int signal) { + if (verbose) + printf("%s: got signal %d\n", __FUNCTION__, signal); + + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset4); + if (verbose) + printf("%s: back from sigprocmask\n", __FUNCTION__); + + siglongjmp(sigjbuf, 1); + printf("%s: siglongjmp() returned unexpectedly!\n", __FUNCTION__); +} + +int +main(int argc, char **argv UNUSED) { + sigset_t sigset1, sigset2, sigset3; + volatile struct sigaction act; + + if (argc > 1) + verbose = 1; + + memset(&sigset1, 0, sizeof(sigset1)); + memset(&sigset2, 0, sizeof(sigset2)); + memset(&sigset3, 0, sizeof(sigset3)); + memset(&sigset4, 0, sizeof(sigset4)); + + sigemptyset((sigset_t * ) & sigset1); + sigaddset((sigset_t * ) & sigset1, SIGUSR1); + sigemptyset((sigset_t * ) & sigset2); + sigaddset((sigset_t * ) & sigset2, SIGUSR2); + + memset((void *) &act, 0, sizeof(act)); + act.sa_handler = sighandler; + sigaction(SIGTERM, (struct sigaction *) &act, NULL); + + test_setjmp(); + test_sigsetjmp(); + + /* _setjmp() MUST NOT change signal mask: */ + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset1, NULL); + int ret = _setjmp(jbuf); + if (ret) { + sigemptyset((sigset_t * ) & sigset3); + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset3); + if (memcmp((sigset_t * ) & sigset3, (sigset_t * ) & sigset2, sizeof(sigset_t)) != 0) { + fprintf(stderr, "1) FAILURE: _longjmp() manipulated signal mask!\n"); + ++nerrors; + } else if (verbose) + printf("1) OK: _longjmp() seems not to change signal mask\n"); + } else { + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset2, NULL); + _longjmp(jbuf, 1); + } + + /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */ + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset1, NULL); + ret = sigsetjmp(sigjbuf, 1); + if (ret) { + sigemptyset((sigset_t * ) & sigset3); + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset3); + if (memcmp((sigset_t * ) & sigset3, (sigset_t * ) & sigset1, sizeof(sigset_t)) != 0) { + fprintf(stderr, + "2) FAILURE: siglongjmp() didn't restore signal mask!\n"); + ++nerrors; + } else if (verbose) + printf("2) OK: siglongjmp() restores signal mask when asked to\n"); + } else { + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset2, NULL); + siglongjmp(sigjbuf, 1); + } + + /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */ + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset1, NULL); + ret = sigsetjmp(sigjbuf, 0); + if (ret) { + sigemptyset((sigset_t * ) & sigset3); + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset3); + if (memcmp((sigset_t * ) & sigset3, (sigset_t * ) & sigset2, sizeof(sigset_t)) != 0) { + fprintf(stderr, "3) FAILURE: siglongjmp() changed signal mask!\n"); + ++nerrors; + } else if (verbose) + printf("3) OK: siglongjmp() leaves signal mask alone when asked to\n"); + } else { + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset2, NULL); + siglongjmp(sigjbuf, 1); + } + + /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */ + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset1, NULL); + ret = sigsetjmp(sigjbuf, 1); + if (ret) { + sigemptyset((sigset_t * ) & sigset3); + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset3); + if (memcmp((sigset_t * ) & sigset3, (sigset_t * ) & sigset1, sizeof(sigset_t)) != 0) { + fprintf(stderr, "4) FAILURE: siglongjmp() didn't restore signal mask!\n"); + ++nerrors; + } else if (verbose) + printf("4) OK: siglongjmp() restores signal mask when asked to\n"); + } else { + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset2, NULL); + kill(getpid(), SIGTERM); + fprintf(stderr, "4) FAILURE: unexpected return from kill()\n"); + ++nerrors; + } + + /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */ + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset1, NULL); + ret = sigsetjmp(sigjbuf, 0); + if (ret) { + sigemptyset((sigset_t * ) & sigset3); + sigprocmask(SIG_BLOCK, NULL, (sigset_t * ) & sigset3); + if (memcmp((sigset_t * ) & sigset3, (sigset_t * ) & sigset4, sizeof(sigset_t)) != 0) { + fprintf(stderr, "5) FAILURE: siglongjmp() changed signal mask!\n"); + ++nerrors; + } else if (verbose) + printf("5) OK: siglongjmp() leaves signal mask alone when asked to\n"); + } else { + sigprocmask(SIG_SETMASK, (sigset_t * ) & sigset2, NULL); + kill(getpid(), SIGTERM); + fprintf(stderr, "5) FAILURE: unexpected return from kill()\n"); + ++nerrors; + } + + if (nerrors > 0) { + fprintf(stderr, "FAILURE: detected %d failures\n", nerrors); + exit(-1); + } + if (verbose) + printf("SUCCESS\n"); + return 0; +} diff --git a/test_programs/setjmp/setjmp2.c b/test_programs/setjmp/setjmp2.c new file mode 100644 index 00000000..ae2f3c17 --- /dev/null +++ b/test_programs/setjmp/setjmp2.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main() { + sigjmp_buf sj; + sigset_t m; + + sigemptyset(&m); + sigprocmask(SIG_SETMASK, &m, NULL); + if (sigsetjmp(sj, 0) == 0) { + sigaddset(&m, SIGUSR1); + sigprocmask(SIG_SETMASK, &m, NULL); + siglongjmp(sj, 1); + return -1; + } + sigprocmask(SIG_SETMASK, NULL, &m); + if (sigismember(&m, SIGUSR1)) + printf("SUCCESS\n"); + else + printf("EXIT_FAILURE\n"); + return 0; +} \ No newline at end of file diff --git a/test_programs/setjmp/signal.c b/test_programs/setjmp/signal.c new file mode 100644 index 00000000..26d6b82b --- /dev/null +++ b/test_programs/setjmp/signal.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include + +sigjmp_buf jmpbuf; +volatile sig_atomic_t canjump; + +void pr_mask(const char *str) { + sigset_t sigset; + int errno_save; + + // Backup the errno value since this function may change it + errno_save = errno; + + // Get the current signal mask + if (sigprocmask(0, NULL, &sigset) < 0) { + printf("sigprocmask error!\n"); + exit(1); + } + + printf("%s", str); + + // Output the signal mask + if (sigismember(&sigset, SIGINT)) printf("SIGINT "); + if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT "); + if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 "); + if (sigismember(&sigset, SIGALRM)) printf("SIGALRM "); + + printf("\n"); + + //Restore the errno value + errno = errno_save; +} + +void sig_usr1(int signo) { + time_t starttime; + + // Precheck the canjump variable + if (canjump == 0) + return; + + pr_mask("starting sig_usr1: "); + + // Setup alarm for 3 seconds and let program wait for 5 seconds + // During this period, sig_alrm will start running, and then return back + alarm(3); + starttime = time(NULL); + for (;;) + if (time(NULL) > starttime + 5) break; + pr_mask("finishing sig_usr1: "); + + // Turn off the canjump, to skip future SIGUSR1 signal + canjump = 0; + siglongjmp(jmpbuf, 1); +} + +void sig_alrm(int signo) { + pr_mask("in sig_alrm: "); +} + +int main(int argc, char *argv[]) { + // Setup the signal handler for SIGUSR1, SIGALRM + if (signal(SIGUSR1, sig_usr1) == SIG_ERR) { + printf("signal error!\n"); + exit(1); + } + + if (signal(SIGALRM, sig_alrm) == SIG_ERR) { + printf("signal error!\n"); + exit(2); + } + + pr_mask("starting main: "); + + // Setup the signal jump entry + if (sigsetjmp(jmpbuf, 1)) { + pr_mask("ending main: "); + exit(0); + } + + // Note: the reason to setump canjump after "sigsetjmp" here is to prevent + // the SIGUSR1 signal come before sigssetjmp. Please keep in mind that, + // signal can come at any time to interrupt the normal codeflow. And the + // program need to prepare for that. + canjump = 1; + + // Pause function to wait for signal coming + for (;;) + pause(); + + exit(0); +} \ No newline at end of file diff --git a/test_programs/setjmp/sigsetjmp.c b/test_programs/setjmp/sigsetjmp.c new file mode 100644 index 00000000..ccea2cb1 --- /dev/null +++ b/test_programs/setjmp/sigsetjmp.c @@ -0,0 +1,29 @@ +#include +#include +#include + +sigjmp_buf mark; + +void p(void); +void recover(void); + +int main(void) { + if (sigsetjmp(mark, 1) != 0) { + printf("siglongjmp() has been called\n"); + recover(); + exit(1); + } + printf("sigsetjmp() has been called\n"); + p(); +} + +void p(void) { + int error = 0; + error = 9; + if (error != 0) + siglongjmp(mark, -1); +} + +void recover(void) { + +} \ No newline at end of file diff --git a/test_programs/setjmp/sigsetjmp1.c b/test_programs/setjmp/sigsetjmp1.c new file mode 100644 index 00000000..e3522c58 --- /dev/null +++ b/test_programs/setjmp/sigsetjmp1.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +jmp_buf env; + +static void signal_handler(int sig); +int processing = 1; + +int main() { + int returned_from_longjump; + unsigned int time_interval = 4; + if ((returned_from_longjump = setjmp(env)) != 0) { + switch (returned_from_longjump) { + case SIGINT: + printf("longjumped from interrupt %d\n", SIGINT); + break; + case SIGALRM: + printf("longjumped from alarm %d\n", SIGALRM); + break; + } + } + signal(SIGINT, signal_handler); + signal(SIGALRM, signal_handler); + alarm(time_interval); + while (processing) { + printf(" waiting for you to INTERRUPT (cntrl-C) ...\n"); + sleep(1); + } + /* end while forever loop */ + return 0; +} + +static void signal_handler(int sig) { + switch (sig) { + case SIGINT: /* process for interrupt */ + longjmp(env, sig); + /* break never reached */ + case SIGALRM: /* process for alarm */ + longjmp(env, sig); + /* break never reached */ + default: + processing = 0; + //exit(sig); + } +} \ No newline at end of file diff --git a/test_programs/threads/pthread_barrier.c b/test_programs/threads/pthread_barrier.c new file mode 100644 index 00000000..3346fb70 --- /dev/null +++ b/test_programs/threads/pthread_barrier.c @@ -0,0 +1,69 @@ +/* + * barrier1.c +*/ + +#include +#include +#include +#include + +pthread_barrier_t barrier; // the barrier synchronization object + +void * +thread1(void *not_used) { + time_t now; + char buf[27]; + + time(&now); + printf("thread1 starting at %s", ctime_r(&now, buf)); + + // do the computation + // let's just do a sleep here... + sleep(20); + pthread_barrier_wait(&barrier); + // after this point, all three threads have completed. + time(&now); + printf("barrier in thread1() done at %s", ctime_r(&now, buf)); +} + +void * +thread2(void *not_used) { + time_t now; + char buf[27]; + + time(&now); + printf("thread2 starting at %s", ctime_r(&now, buf)); + + // do the computation + // let's just do a sleep here... + sleep(40); + pthread_barrier_wait(&barrier); + // after this point, all three threads have completed. + time(&now); + printf("barrier in thread2() done at %s", ctime_r(&now, buf)); +} + +int main() { // ignore arguments + time_t now; + char buf[27]; + pthread_t t1; + pthread_t t2; + + // create a barrier object with a count of 3 + pthread_barrier_init(&barrier, NULL, 3); + + // start up two threads, thread1 and thread2 + pthread_create(&t1, NULL, thread1, NULL); + pthread_create(&t2, NULL, thread2, NULL); + + // at this point, thread1 and thread2 are running + + // now wait for completion + time(&now); + printf("main () waiting for barrier at %s", ctime_r(&now, buf)); + pthread_barrier_wait(&barrier); + + // after this point, all three threads have completed. + time(&now); + printf("barrier in main () done at %s", ctime_r(&now, buf)); +} \ No newline at end of file