diff options
Diffstat (limited to 'librt')
| -rw-r--r-- | librt/Makefile.in | 63 | ||||
| -rw-r--r-- | librt/clock_getcpuclockid.c | 103 | ||||
| -rw-r--r-- | librt/clock_gettime.c | 299 | ||||
| -rw-r--r-- | librt/clock_nanosleep.c | 95 | ||||
| -rw-r--r-- | librt/dso_handle.c | 5 | ||||
| -rw-r--r-- | librt/kernel-posix-cpu-timers.h | 18 | ||||
| -rw-r--r-- | librt/kernel-posix-timers.h | 22 | ||||
| -rw-r--r-- | librt/mq_receive.c | 40 | ||||
| -rw-r--r-- | librt/mq_send.c | 40 | ||||
| -rw-r--r-- | librt/mq_timedreceive.S | 8 | ||||
| -rw-r--r-- | librt/mq_timedsend.S | 8 | ||||
| -rw-r--r-- | librt/rt_stubs.c | 40 | ||||
| -rw-r--r-- | librt/shm.c | 102 | ||||
| -rw-r--r-- | librt/spawn.c | 266 | ||||
| -rw-r--r-- | librt/spawn_faction_addclose.c | 51 | ||||
| -rw-r--r-- | librt/spawn_faction_adddup2.c | 52 | ||||
| -rw-r--r-- | librt/spawn_faction_addopen.c | 55 | ||||
| -rw-r--r-- | librt/spawn_faction_init.c | 42 | ||||
| -rw-r--r-- | librt/spawn_int.h | 35 | ||||
| -rw-r--r-- | librt/timer_create.c | 5 |
20 files changed, 1300 insertions, 49 deletions
diff --git a/librt/Makefile.in b/librt/Makefile.in index 19b779551..1536a5cb9 100644 --- a/librt/Makefile.in +++ b/librt/Makefile.in @@ -1,53 +1,88 @@ # Makefile for uClibc # -# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org> # # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # +subdirs += librt + CFLAGS-librt := -DNOT_IN_libc -DIS_IN_librt $(SSP_ALL_CFLAGS) +LDFLAGS-$(UCLIBC_FORMAT_DSBT_ELF)-librt.so := -Wl,--dsbt-index=9 LDFLAGS-librt.so := $(LDFLAGS) - LIBS-librt.so := $(LIBS) +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +LIBS-librt.so += $(top_builddir)lib/libpthread.so \ + $(CC_FLAG_ASNEEDED) $(top_builddir)lib/libdl.so $(CC_FLAG_NO_ASNEEDED) +endif librt_FULL_NAME := librt-$(VERSION).so librt_DIR := $(top_srcdir)librt librt_OUT := $(top_builddir)librt -ifeq ($(UCLIBC_HAS_REALTIME),y) -librt_SRC := $(wildcard $(librt_DIR)/*.c) -librt_OBJ := $(patsubst $(librt_DIR)/%.c,$(librt_OUT)/%.o,$(librt_SRC)) +librt_SRC := $(notdir $(wildcard $(librt_DIR)/*.c)) +librt_filter_SRC := +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +librt_filter_SRC += mq_notify.c timer_create.c timer_delete.c \ + timer_getoverr.c timer_gettime.c timer_settime.c +# these should really be guarded by ADVANCED_REALTIME, we use them in mq_send.c/mq_receive.c +librt_SSRC := $(wildcard $(librt_DIR)/*.S) +else +librt_filter_SRC += clock_nanosleep.c clock_getcpuclockid.c clock_gettime.c +librt_SSRC := +endif + +librt_filter_SRC += $(if $(UCLIBC_HAS_ADVANCED_REALTIME),, \ + spawn.c \ + spawn_faction_addclose.c \ + spawn_faction_adddup2.c \ + spawn_faction_addopen.c \ + spawn_faction_init.c) + +librt_filter_SRC += $(if $(UCLIBC_HAS_STUBS),,rt_stubs.c) +librt_filter_SRC += $(if $(HAS_NO_THREADS),dso_handle.c) + +librt_SRC := $(filter-out $(librt_filter_SRC),$(librt_SRC)) +librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_SRC)) +librt_OBJ += $(patsubst $(librt_DIR)/%.S,$(librt_OUT)/%.o,$(librt_SSRC)) + +ASFLAGS-mq_timedreceive.S = -D_LIBC_REENTRANT +ASFLAGS-mq_timedsend.S = -D_LIBC_REENTRANT ifeq ($(DOPIC),y) librt-a-y += $(librt_OBJ:.o=.os) else librt-a-y += $(librt_OBJ) endif -librt-so-y += $(librt_OBJ:.o=.os) +librt-so-y += $(librt_OBJ:.o=.oS) +ifeq ($(UCLIBC_HAS_REALTIME),y) lib-a-y += $(top_builddir)lib/librt.a lib-so-y += $(top_builddir)lib/librt.so endif -ifeq ($(DOPIC),y) -$(top_builddir)lib/librt.so: $(top_builddir)lib/librt.a $(libc.depend) +librt-dep-y := $(libc.depend) +librt-dep-$(UCLIBC_HAS_THREADS_NATIVE) += $(libpthread.depend) $(libdl.depend) + +# for NPTL we need SHARED regardless of DOPIC +ifeq ($(if $(UCLIBC_HAS_THREADS_NATIVE),,$(DOPIC)),y) +$(top_builddir)lib/librt.so: $(top_builddir)lib/librt.a $(librt-dep-y) else -$(top_builddir)lib/librt.so: $(librt_OUT)/librt_so.a $(libc.depend) +$(top_builddir)lib/librt.so: $(librt_OUT)/librt_so.a $(librt-dep-y) endif - $(call link.so,$(librt_FULL_NAME),$(MAJOR_VERSION)) + $(call link.so,$(librt_FULL_NAME),$(ABI_VERSION)) $(librt_OUT)/librt_so.a: $(librt-so-y) $(Q)$(RM) $@ $(do_ar) $(top_builddir)lib/librt.a: $(librt-a-y) - $(Q)$(INSTALL) -d $(dir $@) $(Q)$(RM) $@ $(do_ar) -objclean-y += librt_clean +objclean-y += CLEAN_librt -librt_clean: - $(RM) $(librt_OUT)/*.{o,os,a} +CLEAN_librt: + $(do_rm) $(addprefix $(librt_OUT)/*., o os oS a) diff --git a/librt/clock_getcpuclockid.c b/librt/clock_getcpuclockid.c new file mode 100644 index 000000000..b6142a78a --- /dev/null +++ b/librt/clock_getcpuclockid.c @@ -0,0 +1,103 @@ +/* clock_getcpuclockid -- Get a clockid_t for process CPU time. Linux version. + Copyright (C) 2004, 2005 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include <unistd.h> +#include <bits/kernel-features.h> +#include "kernel-posix-cpu-timers.h" + +#ifndef HAS_CPUCLOCK +# define HAS_CPUCLOCK 1 +#endif + +int +clock_getcpuclockid (pid_t pid, clockid_t *clock_id) +{ +#ifdef __NR_clock_getres + /* The clockid_t value is a simple computation from the PID. + But we do a clock_getres call to validate it. */ + + const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, CPUCLOCK_SCHED); + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) + extern int __libc_missing_posix_cpu_timers attribute_hidden; +# if !(__ASSUME_POSIX_TIMERS > 0) + extern int __libc_missing_posix_timers attribute_hidden; + if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) + __libc_missing_posix_cpu_timers = 1; +# endif + if (!__libc_missing_posix_cpu_timers) +# endif + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, pidclock, NULL); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + { + *clock_id = pidclock; + return 0; + } + +# if !(__ASSUME_POSIX_TIMERS > 0) + if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) + { + /* The kernel doesn't support these calls at all. */ + __libc_missing_posix_timers = 1; + __libc_missing_posix_cpu_timers = 1; + } + else +# endif + if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL) + { +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) + if (pidclock == MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED) + || INTERNAL_SYSCALL_ERROR_P (INTERNAL_SYSCALL + (clock_getres, err, 2, + MAKE_PROCESS_CPUCLOCK + (0, CPUCLOCK_SCHED), NULL), + err)) + /* The kernel doesn't support these clocks at all. */ + __libc_missing_posix_cpu_timers = 1; + else +# endif + /* The clock_getres system call checked the PID for us. */ + return ESRCH; + } + else + return INTERNAL_SYSCALL_ERRNO (r, err); + } +#endif + + /* We don't allow any process ID but our own. */ + if (pid != 0 && pid != getpid ()) + return EPERM; + +#ifdef CLOCK_PROCESS_CPUTIME_ID + if (HAS_CPUCLOCK) + { + /* Store the number. */ + *clock_id = CLOCK_PROCESS_CPUTIME_ID; + + return 0; + } +#endif + + /* We don't have a timer for that. */ + return ENOENT; +} diff --git a/librt/clock_gettime.c b/librt/clock_gettime.c new file mode 100644 index 000000000..e61616314 --- /dev/null +++ b/librt/clock_gettime.c @@ -0,0 +1,299 @@ +/* clock_gettime -- Get current time from a POSIX clockid_t. Linux version. + Copyright (C) 2003, 2004 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 + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include <errno.h> +#include <time.h> +#include "kernel-posix-cpu-timers.h" +#include <bits/kernel-features.h> + + +#define SYSCALL_GETTIME \ + retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \ + break + +#ifdef __ASSUME_POSIX_TIMERS + +/* This means the REALTIME and MONOTONIC clock are definitely + supported in the kernel. */ +# define SYSDEP_GETTIME \ + SYSDEP_GETTIME_CPUTIME \ + case CLOCK_REALTIME: \ + case CLOCK_MONOTONIC: \ + SYSCALL_GETTIME + +# define __libc_missing_posix_timers 0 +#elif defined __NR_clock_gettime +/* Is the syscall known to exist? */ +int __libc_missing_posix_timers attribute_hidden; + +static inline int +maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp) +{ + int e = EINVAL; + + if (!__libc_missing_posix_timers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + + e = INTERNAL_SYSCALL_ERRNO (r, err); + if (e == ENOSYS) + { + __libc_missing_posix_timers = 1; + e = EINVAL; + } + } + + return e; +} + +/* The REALTIME and MONOTONIC clock might be available. Try the + syscall first. */ +# define SYSDEP_GETTIME \ + SYSDEP_GETTIME_CPUTIME \ + case CLOCK_REALTIME: \ + case CLOCK_MONOTONIC: \ + retval = maybe_syscall_gettime (clock_id, tp); \ + if (retval == 0) \ + break; \ + /* Fallback code. */ \ + if (retval == EINVAL && clock_id == CLOCK_REALTIME) \ + retval = realtime_gettime (tp); \ + else \ + { \ + __set_errno (retval); \ + retval = -1; \ + } \ + break; +#endif + +#ifdef __NR_clock_gettime +/* We handled the REALTIME clock here. */ +# define HANDLED_REALTIME 1 +# define HANDLED_CPUTIME 1 + +# if __ASSUME_POSIX_CPU_TIMERS > 0 + +# define SYSDEP_GETTIME_CPU SYSCALL_GETTIME +# define SYSDEP_GETTIME_CPUTIME /* Default catches them too. */ + +# else + +int __libc_missing_posix_cpu_timers attribute_hidden; + +static int +maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp) +{ + int e = EINVAL; + + if (!__libc_missing_posix_cpu_timers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + + e = INTERNAL_SYSCALL_ERRNO (r, err); +# ifndef __ASSUME_POSIX_TIMERS + if (e == ENOSYS) + { + __libc_missing_posix_timers = 1; + __libc_missing_posix_cpu_timers = 1; + e = EINVAL; + } + else +# endif + { + if (e == EINVAL) + { + /* Check whether the kernel supports CPU clocks at all. + If not, record it for the future. */ + r = INTERNAL_SYSCALL (clock_getres, err, 2, + MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), + NULL); + if (INTERNAL_SYSCALL_ERROR_P (r, err)) + __libc_missing_posix_cpu_timers = 1; + } + } + } + + return e; +} + +# define SYSDEP_GETTIME_CPU \ + retval = maybe_syscall_gettime_cpu (clock_id, tp); \ + if (retval == 0) \ + break; \ + if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \ + { \ + __set_errno (retval); \ + retval = -1; \ + break; \ + } \ + retval = -1 /* Otherwise continue on to the HP_TIMING version. */; + +static inline int +maybe_syscall_gettime_cputime (clockid_t clock_id, struct timespec *tp) +{ + return maybe_syscall_gettime_cpu + (clock_id == CLOCK_THREAD_CPUTIME_ID + ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) + : MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), + tp); +} + +# define SYSDEP_GETTIME_CPUTIME \ + case CLOCK_PROCESS_CPUTIME_ID: \ + case CLOCK_THREAD_CPUTIME_ID: \ + retval = maybe_syscall_gettime_cputime (clock_id, tp); \ + if (retval == 0) \ + break; \ + if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \ + { \ + __set_errno (retval); \ + retval = -1; \ + break; \ + } \ + retval = hp_timing_gettime (clock_id, tp); \ + break; +# if !HP_TIMING_AVAIL +# define hp_timing_gettime(clock_id, tp) (__set_errno (EINVAL), -1) +# endif + +# endif +#endif + +#include <errno.h> +#include <stdint.h> +#include <time.h> +#include <sys/time.h> +#include <ldsodefs.h> + + +#if HP_TIMING_AVAIL +/* Clock frequency of the processor. We make it a 64-bit variable + because some jokers are already playing with processors with more + than 4GHz. */ +static hp_timing_t freq; + + +/* This function is defined in the thread library. */ +extern int __pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, + struct timespec *tp) + __attribute__ ((__weak__)); + +static int +hp_timing_gettime (clockid_t clock_id, struct timespec *tp) +{ + hp_timing_t tsc; + + if (__builtin_expect (freq == 0, 0)) + { + /* This can only happen if we haven't initialized the `freq' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should + lead to the same result. */ + freq = __get_clockfreq (); + if (__builtin_expect (freq == 0, 0)) + /* Something went wrong. */ + return -1; + } + + if (clock_id != CLOCK_PROCESS_CPUTIME_ID + && __pthread_clock_gettime != NULL) + return __pthread_clock_gettime (clock_id, freq, tp); + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* Compute the offset since the start time of the process. */ + tsc -= GL(dl_cpuclock_offset); + + /* Compute the seconds. */ + tp->tv_sec = tsc / freq; + + /* And the nanoseconds. This computation should be stable until + we get machines with about 16GHz frequency. */ + tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq; + + return 0; +} +#endif + + +static inline int +realtime_gettime (struct timespec *tp) +{ + struct timeval tv; + int retval = gettimeofday (&tv, NULL); + if (retval == 0) + /* Convert into `timespec'. */ + TIMEVAL_TO_TIMESPEC (&tv, tp); + return retval; +} + +librt_hidden_proto (clock_gettime) +/* Get current value of CLOCK and store it in TP. */ +int +clock_gettime (clockid_t clock_id, struct timespec *tp) +{ + int retval = -1; +#ifndef HANDLED_REALTIME + struct timeval tv; +#endif + + switch (clock_id) + { +#ifdef SYSDEP_GETTIME + SYSDEP_GETTIME; +#endif + +#ifndef HANDLED_REALTIME + case CLOCK_REALTIME: + retval = gettimeofday (&tv, NULL); + if (retval == 0) + TIMEVAL_TO_TIMESPEC (&tv, tp); + break; +#endif + + default: +#ifdef SYSDEP_GETTIME_CPU + SYSDEP_GETTIME_CPU; +#endif +#if HP_TIMING_AVAIL + if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) + == CLOCK_THREAD_CPUTIME_ID) + retval = hp_timing_gettime (clock_id, tp); + else +#endif + __set_errno (EINVAL); + break; + +#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME + case CLOCK_PROCESS_CPUTIME_ID: + retval = hp_timing_gettime (clock_id, tp); + break; +#endif + } + + return retval; +} +librt_hidden_def (clock_gettime) diff --git a/librt/clock_nanosleep.c b/librt/clock_nanosleep.c new file mode 100644 index 000000000..235e8b563 --- /dev/null +++ b/librt/clock_nanosleep.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2004, 2005 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 + <http://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <errno.h> + +#include <sysdep-cancel.h> +#include <bits/kernel-features.h> +#include "kernel-posix-cpu-timers.h" + + +#ifdef __ASSUME_POSIX_TIMERS +/* We can simply use the syscall. The CPU clocks are not supported + with this function. */ +int +clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req, + struct timespec *rem) +{ + INTERNAL_SYSCALL_DECL (err); + int r; + + if (clock_id == CLOCK_THREAD_CPUTIME_ID) + return EINVAL; + if (clock_id == CLOCK_PROCESS_CPUTIME_ID) + clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED); + + if (SINGLE_THREAD_P) + r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req, rem); + else + { + int oldstate = LIBC_CANCEL_ASYNC (); + + r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, clock_id, flags, req, + rem); + + LIBC_CANCEL_RESET (oldstate); + } + + return (INTERNAL_SYSCALL_ERROR_P (r, err) + ? INTERNAL_SYSCALL_ERRNO (r, err) : 0); +} + +#else +# ifdef __NR_clock_nanosleep +/* Is the syscall known to exist? */ +extern int __libc_missing_posix_timers attribute_hidden; + +/* The REALTIME and MONOTONIC clock might be available. Try the + syscall first. */ +# define SYSDEP_NANOSLEEP \ + if (!__libc_missing_posix_timers) \ + { \ + clockid_t syscall_clockid; \ + INTERNAL_SYSCALL_DECL (err); \ + \ + if (clock_id == CLOCK_THREAD_CPUTIME_ID) \ + return EINVAL; \ + if (clock_id == CLOCK_PROCESS_CPUTIME_ID) \ + syscall_clockid = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED); \ + else \ + syscall_clockid = clock_id; \ + \ + int oldstate = LIBC_CANCEL_ASYNC (); \ + \ + int r = INTERNAL_SYSCALL (clock_nanosleep, err, 4, \ + syscall_clockid, flags, req, rem); \ + \ + LIBC_CANCEL_RESET (oldstate); \ + \ + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) \ + return 0; \ + \ + if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS) \ + return INTERNAL_SYSCALL_ERRNO (r, err); \ + \ + __libc_missing_posix_timers = 1; \ + } +# endif + +# include <sysdeps/unix/clock_nanosleep.c> +#endif diff --git a/librt/dso_handle.c b/librt/dso_handle.c new file mode 100644 index 000000000..633907103 --- /dev/null +++ b/librt/dso_handle.c @@ -0,0 +1,5 @@ +/* Copyright (C) 2015 Bernhard Reutner-Fischer + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +const void *const __dso_handle attribute_hidden = &__dso_handle; diff --git a/librt/kernel-posix-cpu-timers.h b/librt/kernel-posix-cpu-timers.h new file mode 100644 index 000000000..164a90dde --- /dev/null +++ b/librt/kernel-posix-cpu-timers.h @@ -0,0 +1,18 @@ +/* Parameters for the Linux kernel ABI for CPU clocks. */ + +#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) +#define CPUCLOCK_PERTHREAD(clock) \ + (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) +#define CPUCLOCK_PID_MASK 7 +#define CPUCLOCK_PERTHREAD_MASK 4 +#define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) +#define CPUCLOCK_CLOCK_MASK 3 +#define CPUCLOCK_PROF 0 +#define CPUCLOCK_VIRT 1 +#define CPUCLOCK_SCHED 2 +#define CPUCLOCK_MAX 3 + +#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ + ((~(clockid_t) (pid) << 3) | (clockid_t) (clock)) +#define MAKE_THREAD_CPUCLOCK(tid, clock) \ + MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) diff --git a/librt/kernel-posix-timers.h b/librt/kernel-posix-timers.h index bf246c925..f8bfdc2ae 100644 --- a/librt/kernel-posix-timers.h +++ b/librt/kernel-posix-timers.h @@ -10,6 +10,25 @@ #include <pthread.h> #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +/* Nonzero if the system calls are not available. */ +extern int __no_posix_timers attribute_hidden; + +/* Callback to start helper thread. */ +extern void __start_helper_thread (void) attribute_hidden; + +/* Control variable for helper thread creation. */ +extern pthread_once_t __helper_once attribute_hidden; + +/* TID of the helper thread. */ +extern pid_t __helper_tid attribute_hidden; + +/* List of active SIGEV_THREAD timers. */ +extern struct timer *__active_timer_sigev_thread attribute_hidden; +/* Lock for the __active_timer_sigev_thread. */ +extern pthread_mutex_t __active_timer_sigev_thread_lock attribute_hidden; +#endif + /* Type of timers in the kernel */ typedef int kernel_timer_t; @@ -33,4 +52,7 @@ struct timer { #ifdef __UCLIBC_HAS_THREADS__ pthread_attr_t attr; #endif + + /* Next element in list of active SIGEV_THREAD timers. */ + struct timer *next; }; diff --git a/librt/mq_receive.c b/librt/mq_receive.c index 3da88f391..2be1c1a98 100644 --- a/librt/mq_receive.c +++ b/librt/mq_receive.c @@ -2,20 +2,28 @@ * mq_receive.c - functions for receiving from message queue. */ -#include <errno.h> -#include <stddef.h> #include <sys/syscall.h> + +#ifdef __NR_mq_timedreceive + +#include <stddef.h> #include <mqueue.h> -#warning FIXME: hard dependency on ADVANCED REALTIME feature +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# ifndef __UCLIBC_HAS_ADVANCED_REALTIME__ +extern ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, + unsigned int *msg_prio, + const struct timespec *abs_timeout); +# endif librt_hidden_proto(mq_timedreceive) -#ifdef __NR_mq_timedreceive -#define __NR___syscall_mq_timedreceive __NR_mq_timedreceive -static __inline__ _syscall5(int, __syscall_mq_timedreceive, int, mqdes, - char *, msg_ptr, size_t, msg_len, unsigned int *, - msg_prio, const void *, abs_timeout); -#endif +#else + +# define __NR___syscall_mq_timedreceive __NR_mq_timedreceive +static _syscall5(int, __syscall_mq_timedreceive, int, mqdes, + char *, msg_ptr, size_t, msg_len, unsigned int *, + msg_prio, const void *, abs_timeout) +# ifdef __UCLIBC_HAS_ADVANCED_REALTIME__ /* * Receive the oldest from highest priority messages. * Stop waiting if abs_timeout expires. @@ -24,20 +32,22 @@ ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout) { -#ifdef __NR_mq_timedreceive return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout); -#else - errno = ENOSYS; - return -1; -#endif } +# endif -librt_hidden_def(mq_timedreceive) +#endif /* Receive the oldest from highest priority messages */ ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio) { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL); +#else + return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL); +#endif } + +#endif diff --git a/librt/mq_send.c b/librt/mq_send.c index 446ecc89a..5e50d1a19 100644 --- a/librt/mq_send.c +++ b/librt/mq_send.c @@ -2,20 +2,27 @@ * mq_send.c - functions for sending to message queue. */ -#include <errno.h> -#include <stddef.h> #include <sys/syscall.h> + +#ifdef __NR_mq_timedsend + +#include <stddef.h> #include <mqueue.h> -#warning FIXME: hard dependency on ADVANCED REALTIME feature +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# ifndef __UCLIBC_HAS_ADVANCED_REALTIME__ +extern int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, + unsigned int msg_prio, const struct timespec *abs_timeout); +# endif librt_hidden_proto(mq_timedsend) -#ifdef __NR_mq_timedsend -#define __NR___syscall_mq_timedsend __NR_mq_timedsend -static __inline__ _syscall5(int, __syscall_mq_timedsend, int, mqdes, - const char *, msg_ptr, size_t, msg_len, unsigned int, - msg_prio, const void *, abs_timeout); -#endif +#else + +# define __NR___syscall_mq_timedsend __NR_mq_timedsend +static _syscall5(int, __syscall_mq_timedsend, int, mqdes, + const char *, msg_ptr, size_t, msg_len, unsigned int, + msg_prio, const void *, abs_timeout) +# ifdef __UCLIBC_HAS_ADVANCED_REALTIME__ /* * Add a message to queue. If O_NONBLOCK is set and queue is full, wait * for sufficient room in the queue until abs_timeout expires. @@ -23,20 +30,21 @@ static __inline__ _syscall5(int, __syscall_mq_timedsend, int, mqdes, int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) { -#ifdef __NR_mq_timedsend return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout); -#else - errno = ENOSYS; - return -1; -#endif } - -librt_hidden_def(mq_timedsend) +# endif +#endif /* Add a message to queue */ int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio) { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL); +#else + return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL); +#endif } + +#endif diff --git a/librt/mq_timedreceive.S b/librt/mq_timedreceive.S new file mode 100644 index 000000000..00fecac03 --- /dev/null +++ b/librt/mq_timedreceive.S @@ -0,0 +1,8 @@ +#include <sysdep-cancel.h> +#ifndef __NR_mq_timedreceive +#error Missing definition of NR_timedreceive needed for cancellation. +#endif +PSEUDO(mq_timedreceive, mq_timedreceive, 5) +ret_ERRVAL +PSEUDO_END(mq_timedreceive) +librt_hidden_def(mq_timedreceive) diff --git a/librt/mq_timedsend.S b/librt/mq_timedsend.S new file mode 100644 index 000000000..ee8d48334 --- /dev/null +++ b/librt/mq_timedsend.S @@ -0,0 +1,8 @@ +#include <sysdep-cancel.h> +#ifndef __NR_mq_timedsend +#error Missing definition of NR_timedsend needed for cancellation. +#endif +PSEUDO(mq_timedsend, mq_timedsend, 5) +ret_ERRVAL +PSEUDO_END(mq_timedsend) +librt_hidden_def(mq_timedsend) diff --git a/librt/rt_stubs.c b/librt/rt_stubs.c new file mode 100644 index 000000000..a2b84e62a --- /dev/null +++ b/librt/rt_stubs.c @@ -0,0 +1,40 @@ +/* + * system call not available stub + * based on libc's stubs.c + * + * Copyright (C) 2009 Analog Devices Inc. + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <sys/syscall.h> + +#ifdef __UCLIBC_HAS_STUBS__ + +static int rt_enosys_stub(void) __attribute_used__; +static int rt_enosys_stub(void) +{ + __set_errno(ENOSYS); + return -1; +} + +#define make_stub(stub) \ + link_warning(stub, #stub ": this function is not implemented") \ + strong_alias(rt_enosys_stub, stub) + +#ifndef __NR_mq_timedreceive +make_stub(mq_receive) +# ifdef __UCLIBC_HAS_ADVANCED_REALTIME__ +make_stub(mq_timedreceive) +# endif +#endif + +#ifndef __NR_mq_timedsend +make_stub(mq_send) +# ifdef __UCLIBC_HAS_ADVANCED_REALTIME__ +make_stub(mq_timedsend) +# endif +#endif + +#endif diff --git a/librt/shm.c b/librt/shm.c new file mode 100644 index 000000000..40e69fa2e --- /dev/null +++ b/librt/shm.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2009 Bernhard Reutner-Fischer <uclibc@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <features.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#ifndef _PATH_SHM +#define _PATH_SHM "/dev/shm/" +#endif + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +/* Get name of dummy shm operation handle. + * Returns a malloc'ed buffer containing the OS specific path + * to the shm filename or NULL upon failure. + */ +static __attribute_noinline__ char* get_shm_name(const char *name) __nonnull((1)); +static char* get_shm_name(const char *name) +{ + char *path; + int i; + + /* Skip leading slashes */ + while (*name == '/') + ++name; +#ifdef __USE_GNU + i = asprintf(&path, _PATH_SHM "%s", name); + if (i < 0) + return NULL; +#else + path = malloc(NAME_MAX); + if (path == NULL) + return NULL; + i = snprintf(path, NAME_MAX, _PATH_SHM "%s", name); + if (i < 0) { + free(path); + return NULL; + } else if (i >= NAME_MAX) { + free(path); + __set_errno(ENAMETOOLONG); + return NULL; + } +#endif + return path; +} + +int shm_open(const char *name, int oflag, mode_t mode) +{ + int fd; + char *shm_name = get_shm_name(name); + + /* Stripped multiple '/' from start; may have set errno properly */ + if (shm_name == NULL) + return -1; + /* The FD_CLOEXEC file descriptor flag associated with the new + * file descriptor is set. */ +#ifdef O_CLOEXEC + /* Just open it with CLOEXEC set, for brevity */ + fd = open(shm_name, oflag | O_CLOEXEC, mode); +#else + fd = open(shm_name, oflag, mode); + if (fd >= 0) { + fcntl(fd, F_SETFD, FD_CLOEXEC); + /* thus far, {G,S}ETFD only has this single flag, + * and setting it never fails. + *int fdflags = fcntl(fd, F_GETFD); + *if (fdflags >= 0) + * fdflags = fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); + *if (fdflags < 0) { + * close(fd); + * fd = -1; + *} + */ + } +#endif + free(shm_name); /* doesn't affect errno */ + return fd; +} + +int shm_unlink(const char *name) +{ + char *shm_name = get_shm_name(name); + int ret; + + /* Stripped multiple '/' from start; may have set errno properly */ + if (shm_name == NULL) + return -1; + ret = unlink(shm_name); + free(shm_name); /* doesn't affect errno */ + return ret; +} diff --git a/librt/spawn.c b/librt/spawn.c new file mode 100644 index 000000000..07d40193c --- /dev/null +++ b/librt/spawn.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2000, 2011 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <alloca.h> +#include <unistd.h> +#include <signal.h> +#include <stdbool.h> +#include <fcntl.h> + +#include <sys/resource.h> +#include <not-cancel.h> + +#include <spawn.h> +#include "spawn_int.h" + +/* The Unix standard contains a long explanation of the way to signal + an error after the fork() was successful. Since no new wait status + was wanted there is no way to signal an error using one of the + available methods. The committee chose to signal an error by a + normal program exit with the exit code 127. */ +#define SPAWN_ERROR 127 + +/* Execute file actions. + * Returns true on error. + */ +inline static bool execute_file_actions(const posix_spawn_file_actions_t *fa) +{ + struct rlimit64 fdlimit; + bool have_fdlimit = false; + int cnt; + + for (cnt = 0; cnt < fa->__used; ++cnt) { + struct __spawn_action *action = &fa->__actions[cnt]; + + switch (action->tag) { + case spawn_do_close: + if (close_not_cancel(action->action.close_action.fd) != 0) { + if (!have_fdlimit) { + getrlimit64(RLIMIT_NOFILE, &fdlimit); + have_fdlimit = true; + } + + /* Only signal errors for file descriptors out of range. */ + if (0 > action->action.close_action.fd + || action->action.close_action.fd >= fdlimit.rlim_cur) + /* Signal the error. */ + return true; + } + break; + + case spawn_do_open:; + int new_fd = open_not_cancel(action->action.open_action.path, + action->action.open_action.oflag + | O_LARGEFILE, + action->action.open_action.mode); + + if (new_fd == -1) + return true; + + /* Make sure the desired file descriptor is used. */ + if (new_fd != action->action.open_action.fd) { + if (dup2(new_fd, action->action.open_action.fd) + != action->action.open_action.fd) + return true; + + if (close_not_cancel(new_fd) != 0) + return true; + } + break; + + case spawn_do_dup2: + if (dup2(action->action.dup2_action.fd, + action->action.dup2_action.newfd) + != action->action.dup2_action.newfd) + return true; + break; + } + } + + return false; +} + +#define DANGEROUS (POSIX_SPAWN_SETSIGMASK \ + | POSIX_SPAWN_SETSIGDEF \ + | POSIX_SPAWN_SETSCHEDPARAM \ + | POSIX_SPAWN_SETSCHEDULER \ + | POSIX_SPAWN_SETPGROUP \ + | POSIX_SPAWN_RESETIDS) +inline static bool is_vfork_safe(short int flags) +{ + return ((flags & POSIX_SPAWN_USEVFORK) || !(flags & DANGEROUS)); +} + + +/* Spawn a new process executing PATH with the attributes describes in *ATTRP. + Before running the process perform the actions described in FILE-ACTIONS. */ +static int +__spawni(pid_t *pid, const char *file, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *attrp, char *const argv[], + char *const envp[], const char *path) +{ + short int flags = attrp ? attrp->__flags : 0; + + pid_t new_pid; + if (is_vfork_safe(flags) && !fa) + new_pid = vfork(); + else { +#ifdef __ARCH_USE_MMU__ + new_pid = fork(); +#else + return ENOSYS; +#endif + } + + if (new_pid) { + if (new_pid < 0) + return errno; + + if (pid) + *pid = new_pid; + + return 0; + } + + if (flags & POSIX_SPAWN_SETSIGMASK) { + if (sigprocmask(SIG_SETMASK, &attrp->__ss, NULL) != 0) + goto error; + } + + if (flags & POSIX_SPAWN_SETSIGDEF) { + /* We have to iterate over all signals. This could possibly be + done better but it requires system specific solutions since + the sigset_t data type can be very different on different + architectures. */ + struct sigaction sa; + int sig; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + for (sig = 1; sig <= _NSIG; ++sig) { + if (sigismember(&attrp->__sd, sig)) { + if (sigaction(sig, &sa, NULL) != 0) + goto error; + } + } + } + + if (flags & POSIX_SPAWN_SETSCHEDULER) { + if (sched_setscheduler(0, attrp->__policy, &attrp->__sp) == -1) + goto error; + } else if (flags & POSIX_SPAWN_SETSCHEDPARAM) { + if (sched_setparam(0, &attrp->__sp) == -1) + goto error; + } + + if (flags & POSIX_SPAWN_SETPGROUP) { + if (setpgid(0, attrp->__pgrp) != 0) + goto error; + } + + if (flags & POSIX_SPAWN_RESETIDS) { + if (seteuid(getuid()) || setegid(getgid())) + goto error; + } + + if (fa && execute_file_actions(fa)) + goto error; + + if (!path || strchr(file, '/')) { + execve(file, argv, envp); + goto error; + } + + + char *name; + { + size_t filelen = strlen(file) + 1; + size_t pathlen = strlen(path) + 1; + name = alloca(pathlen + filelen); + + /* Copy the file name at the top. */ + name = (char *) memcpy(name + pathlen, file, filelen); + + /* And add the slash. */ + *--name = '/'; + } + + char *p; + do { + char *startp; + p = strchrnul(path, ':'); + + /* Two adjacent colons, or a colon at the beginning or the end + of `PATH' means to search the current directory. */ + if (p == path) + startp = name + 1; + else + startp = (char *) memcpy(name - (p - path), path, p - path); + + execve(startp, argv, envp); + + switch (errno) { + case EACCES: + case ENOENT: + case ESTALE: + case ENOTDIR: + /* Those errors indicate the file is missing or not + executable by us, in which case we want to just try + the next path directory. */ + break; + default: + /* Some other error means we found an executable file, + but something went wrong executing it; return the + error to our caller. */ + goto error; + } + + path = p; + } while (*p++ != '\0'); + +error: + _exit(SPAWN_ERROR); +} + +/* Spawn a new process executing PATH with the attributes describes in *ATTRP. + Before running the process perform the actions described in FILE-ACTIONS. */ +int posix_spawn (pid_t *pid, const char *path, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *attrp, char *const argv[], + char *const envp[]) +{ + return __spawni(pid, path, fa, attrp, argv, envp, NULL); +} + +/* Spawn a new process executing FILE with the attributes describes in *ATTRP. + Before running the process perform the actions described in FILE-ACTIONS. */ +int +posix_spawnp(pid_t *pid, const char *file, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *attrp, char *const argv[], + char *const envp[]) +{ + const char *path = getenv("PATH"); + + if (!path) + path = ":/bin:/usr/bin"; + + return __spawni(pid, file, fa, attrp, argv, envp, path); +} diff --git a/librt/spawn_faction_addclose.c b/librt/spawn_faction_addclose.c new file mode 100644 index 000000000..b418f962f --- /dev/null +++ b/librt/spawn_faction_addclose.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2000 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <spawn.h> +#include <unistd.h> + +#include "spawn_int.h" + +/* Add an action to FILE-ACTIONS which tells the implementation to call + `close' for the given file descriptor during the `spawn' call. */ +int +posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, + int fd) +{ + int maxfd = sysconf(_SC_OPEN_MAX); + struct __spawn_action *rec; + + /* Test for the validity of the file descriptor. */ + if (fd < 0 || fd >= maxfd) + return EBADF; + + /* Allocate more memory if needed. */ + if (file_actions->__used == file_actions->__allocated + && __posix_spawn_file_actions_realloc(file_actions) != 0) + /* This can only mean we ran out of memory. */ + return ENOMEM; + + /* Add the new value. */ + rec = &file_actions->__actions[file_actions->__used]; + rec->tag = spawn_do_close; + rec->action.open_action.fd = fd; + + /* Account for the new entry. */ + ++file_actions->__used; + return 0; +} diff --git a/librt/spawn_faction_adddup2.c b/librt/spawn_faction_adddup2.c new file mode 100644 index 000000000..6d7331326 --- /dev/null +++ b/librt/spawn_faction_adddup2.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2000 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <spawn.h> +#include <unistd.h> + +#include "spawn_int.h" + +/* Add an action to FILE-ACTIONS which tells the implementation to call + `dup2' for the given file descriptors during the `spawn' call. */ +int +posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, + int fd, int newfd) +{ + int maxfd = sysconf(_SC_OPEN_MAX); + struct __spawn_action *rec; + + /* Test for the validity of the file descriptor. */ + if (fd < 0 || newfd < 0 || fd >= maxfd || newfd >= maxfd) + return EBADF; + + /* Allocate more memory if needed. */ + if (file_actions->__used == file_actions->__allocated + && __posix_spawn_file_actions_realloc (file_actions) != 0) + /* This can only mean we ran out of memory. */ + return ENOMEM; + + /* Add the new value. */ + rec = &file_actions->__actions[file_actions->__used]; + rec->tag = spawn_do_dup2; + rec->action.dup2_action.fd = fd; + rec->action.dup2_action.newfd = newfd; + + /* Account for the new entry. */ + ++file_actions->__used; + return 0; +} diff --git a/librt/spawn_faction_addopen.c b/librt/spawn_faction_addopen.c new file mode 100644 index 000000000..285ca715e --- /dev/null +++ b/librt/spawn_faction_addopen.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2000 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <spawn.h> +#include <unistd.h> + +#include "spawn_int.h" + +/* Add an action to FILE-ACTIONS which tells the implementation to call + `open' for the given file during the `spawn' call. */ +int +posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *file_actions, + int fd, const char *path, int oflag, + mode_t mode) +{ + int maxfd = sysconf(_SC_OPEN_MAX); + struct __spawn_action *rec; + + /* Test for the validity of the file descriptor. */ + if (fd < 0 || fd >= maxfd) + return EBADF; + + /* Allocate more memory if needed. */ + if (file_actions->__used == file_actions->__allocated + && __posix_spawn_file_actions_realloc (file_actions) != 0) + /* This can only mean we ran out of memory. */ + return ENOMEM; + + /* Add the new value. */ + rec = &file_actions->__actions[file_actions->__used]; + rec->tag = spawn_do_open; + rec->action.open_action.fd = fd; + rec->action.open_action.path = path; + rec->action.open_action.oflag = oflag; + rec->action.open_action.mode = mode; + + /* Account for the new entry. */ + ++file_actions->__used; + return 0; +} diff --git a/librt/spawn_faction_init.c b/librt/spawn_faction_init.c new file mode 100644 index 000000000..fb398a566 --- /dev/null +++ b/librt/spawn_faction_init.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2000 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <spawn.h> +#include <stdlib.h> +#include <string.h> + +#include "spawn_int.h" + + +/* Function used to increase the size of the allocated array. This + function is called from the `add'-functions. */ +int +__posix_spawn_file_actions_realloc(posix_spawn_file_actions_t *file_actions) +{ + int newalloc = file_actions->__allocated + 8; + void *newmem = realloc(file_actions->__actions, + newalloc * sizeof(struct __spawn_action)); + + if (newmem == NULL) + /* Not enough memory. */ + return ENOMEM; + + file_actions->__actions = (struct __spawn_action *)newmem; + file_actions->__allocated = newalloc; + return 0; +} diff --git a/librt/spawn_int.h b/librt/spawn_int.h new file mode 100644 index 000000000..1d990fc33 --- /dev/null +++ b/librt/spawn_int.h @@ -0,0 +1,35 @@ +/* Data structure to contain the action information. */ +struct __spawn_action { + enum { + spawn_do_close, + spawn_do_dup2, + spawn_do_open + } tag; + + union { + struct { + int fd; + } close_action; + struct { + int fd; + int newfd; + } dup2_action; + struct { + int fd; + const char *path; + int oflag; + mode_t mode; + } open_action; + } action; +}; + +int __posix_spawn_file_actions_realloc(posix_spawn_file_actions_t *fa); + +/* handle !LFS */ +#ifndef __UCLIBC_HAS_LFS__ +# define rlimit64 rlimit +# define getrlimit64 getrlimit +#endif +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif diff --git a/librt/timer_create.c b/librt/timer_create.c index 9298a37c7..f52a36ff9 100644 --- a/librt/timer_create.c +++ b/librt/timer_create.c @@ -2,6 +2,7 @@ * timer_create.c - create a per-process timer. */ +#include <stddef.h> #include <errno.h> #include <signal.h> #include <stdlib.h> @@ -13,10 +14,6 @@ #ifdef __NR_timer_create -#ifndef offsetof -# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - #define __NR___syscall_timer_create __NR_timer_create static __inline__ _syscall3(int, __syscall_timer_create, clockid_t, clock_id, struct sigevent *, evp, kernel_timer_t *, ktimerid); |
