瀏覽代碼

Patch from Paul Mundt (lethal) adding an initial librt implementation.
I then reworked the syscall handling and made minor cleanups. With luck
I've not completely broken his patch...

Eric Andersen 19 年之前
父節點
當前提交
50a6ac7fb9
共有 16 個文件被更改,包括 603 次插入1 次删除
  1. 2 1
      Makefile
  2. 97 0
      include/mqueue.h
  3. 47 0
      librt/Makefile
  4. 30 0
      librt/kernel-posix-timers.h
  5. 22 0
      librt/mq_close.c
  6. 33 0
      librt/mq_getsetattr.c
  7. 28 0
      librt/mq_notify.c
  8. 52 0
      librt/mq_open.c
  9. 36 0
      librt/mq_receive.c
  10. 36 0
      librt/mq_send.c
  11. 38 0
      librt/mq_unlink.c
  12. 70 0
      librt/timer_create.c
  13. 33 0
      librt/timer_delete.c
  14. 25 0
      librt/timer_getoverr.c
  15. 26 0
      librt/timer_gettime.c
  16. 28 0
      librt/timer_settime.c

+ 2 - 1
Makefile

@@ -28,7 +28,7 @@ noconfig_targets := menuconfig config oldconfig randconfig \
 TOPDIR=./
 include Rules.mak
 
-DIRS = ldso libc libcrypt libresolv libnsl libutil libm libpthread
+DIRS = ldso libc libcrypt libresolv libnsl libutil libm libpthread librt
 ifeq ($(strip $(UCLIBC_HAS_GETTEXT_AWARENESS)),y)
 	DIRS += libintl
 endif
@@ -50,6 +50,7 @@ ifeq ($(strip $(HAVE_SHARED)),y)
 	@$(MAKE) -C libutil shared
 	@$(MAKE) -C libm shared
 	@$(MAKE) -C libpthread shared
+	@$(MAKE) -C librt shared
 ifeq ($(strip $(UCLIBC_HAS_GETTEXT_AWARENESS)),y)
 	@$(MAKE) -C libintl shared
 endif

+ 97 - 0
include/mqueue.h

@@ -0,0 +1,97 @@
+/*
+ * mqueue.h - definitions and function prototypes for POSIX mqueue support.
+ */
+
+#ifndef _MQUEUE_H
+#define _MQUEUE_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#define __need_sigevent_t
+#include <bits/siginfo.h>
+#define __need_timespec
+#include <time.h>
+
+typedef int mqd_t;
+
+struct mq_attr {
+    long int mq_flags;		/* Message queue flags */
+    long int mq_maxmsg;		/* Maximum number of messages */
+    long int mq_msgsize;	/* Maximum message size */
+    long int mq_curmsgs;	/* Number of messages currently queued */
+    long int __pad[4];
+};
+
+__BEGIN_DECLS
+
+/*
+ * Establish connection between a process and a message queue __name and
+ * return message queue descriptor or (mqd_t) -1 on error. __oflag determines
+ * the type of access used. If O_CREAT is on __oflag, the third argument is
+ * taken as a `mode_t', the mode of the created message queue, and the fourth
+ * argument is taken as `struct mq_attr *', pointer to message queue
+ * attributes. If the fourth argument is NULL, default attributes are used.
+ */
+extern mqd_t mq_open(const char *__name, int __oflag, ...) __THROW;
+
+/*
+ * Remove the association between message queue descriptor __mqdes and its
+ * message queue.
+ */
+extern int mq_close(mqd_t __mqdes) __THROW;
+
+/* Query status and attributes of message queue __mqdes */
+extern int mq_getattr(mqd_t __mqdes, struct mq_attr *__mqstat) __THROW;
+
+/*
+ * Set attributes associated with message queue __mqdes and if __omqstat is
+ * not NULL also query its old attributes.
+ */
+extern int mq_setattr(mqd_t __mqdes,
+		      const struct mq_attr *__restrict __mqstat,
+		      struct mq_attr *__restrict __omqstat) __THROW;
+
+/* Remove message queue named __name */
+extern int mq_unlink(const char *__name) __THROW;
+
+/*
+ * Register notification upon message arrival to an empty message queue
+ * __mqdes
+ */
+extern int mq_notify(mqd_t __mqdes, const struct sigevent *__notification)
+     __THROW;
+
+/*
+ * Receive the oldest from highest priority messages in message queue
+ * __mqdes
+ */
+extern ssize_t mq_receive(mqd_t __mqdes, char *__msg_ptr, size_t __msg_len,
+			  unsigned int *__msg_prio);
+
+/* Add message pointed by __msg_ptr to message queue __mqdes */
+extern int mq_send(mqd_t __mqdes, const char *__msg_ptr, size_t __msg_len,
+		   unsigned int __msg_prio);
+
+#ifdef __USE_XOPEN2K
+/*
+ * Receive the oldest from highest priority messages in message queue
+ * __mqdes, stop waiting if __abs_timeout expires.
+ */
+extern ssize_t mq_timedreceive(mqd_t __mqdes, char *__restrict __msg_ptr,
+			       size_t __msg_len,
+			       unsigned int *__restrict __msg_prio,
+			       const struct timespec *__restrict __abs_timeout);
+
+/*
+ * Add message pointed by __msg_ptr to message queue __mqdes, stop blocking
+ * on full message queue if __abs_timeout expires.
+ */
+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
+
+__END_DECLS
+
+#endif

+ 47 - 0
librt/Makefile

@@ -0,0 +1,47 @@
+#
+# Makefile for librt
+#
+
+TOPDIR=../
+include $(TOPDIR)Rules.mak
+LIBC=$(TOPDIR)libc.a
+
+LIBRT=librt.a
+LIBRT_SHARED=librt.so
+LIBRT_SHARED_FULLNAME=librt-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
+
+# uClibc's librt lacks all aio routines, all clock routines,
+# and all shm routines
+CSRC=mq_open.c mq_close.c mq_unlink.c mq_getsetattr.c \
+     mq_send.c mq_receive.c mq_notify.c \
+     timer_create.c timer_delete.c \
+     timer_settime.c timer_gettime.c timer_getoverr.c
+OBJS=$(patsubst %.c,%.o, $(CSRC))
+
+all: $(OBJS) $(LIBC)
+
+$(LIBC): ar-target
+
+ar-target: $(OBJS)
+	$(AR) $(ARFLAGS) $(LIBRT) $(OBJS)
+	$(INSTALL) -d $(TOPDIR)lib
+	$(RM) $(TOPDIR)lib/$(LIBRT)
+	$(INSTALL) -m 644 $(LIBRT) $(TOPDIR)lib/
+
+$(OBJS): %.o : %.c
+	$(CC) $(CFLAGS) -c $< -o $@
+	$(STRIPTOOL) -x -R .note -R .comment $*.o
+
+shared: all
+	$(LD) $(LDFLAGS) -soname=$(LIBRT_SHARED).$(MAJOR_VERSION) \
+		-o $(LIBRT_SHARED_FULLNAME) --whole-archive $(LIBRT) \
+		--no-whole-archive $(TOPDIR)libc/misc/internals/interp.o \
+		-L$(TOPDIR)lib -lc $(LDADD_LIBFLOAT) $(LIBGCC);
+	$(INSTALL) -d $(TOPDIR)lib
+	$(RM) $(TOPDIR)lib/$(LIBRT_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBRT_SHARED).$(MAJOR_VERSION)
+	$(INSTALL) -m 644 $(LIBRT_SHARED_FULLNAME) $(TOPDIR)lib
+	$(LN) -sf $(LIBRT_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBRT_SHARED)
+	$(LN) -sf $(LIBRT_SHARED_FULLNAME) $(TOPDIR)lib/$(LIBRT_SHARED).$(MAJOR_VERSION)
+
+clean:
+	$(RM) *.[oa] *~ core $(LIBRT_SHARED)* $(LIBRT_SHARED_FULLNAME)*

+ 30 - 0
librt/kernel-posix-timers.h

@@ -0,0 +1,30 @@
+/*
+ * kernel-posix-timers.h - kernel-dependent definitions for POSIX timers.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/types.h>
+
+/* Type of timers in the kernel */
+typedef int kernel_timer_t;
+
+/* Internal representation of timer */
+struct timer {
+    /* Notification mechanism */
+    int sigev_notify;
+
+    /* Timer ID returned by the kernel */
+    kernel_timer_t ktimerid;
+
+    /*
+     * All new elements must be added after ktimerid. And if the thrfunc
+     * element is not the third element anymore the memory allocation in
+     * timer_create needs to be changed.
+     */
+
+    /* Parameters for the thread to be started for SIGEV_THREAD */
+    void (*thrfunc) (sigval_t);
+    sigval_t sival;
+    pthread_attr_t attr;
+};

+ 22 - 0
librt/mq_close.c

@@ -0,0 +1,22 @@
+/*
+ * mq_close.c - close a message queue.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#ifdef __NR_mq_open
+
+/*
+ * Remove the association between message queue descriptor and its
+ * message queue.
+ */
+int mq_close(mqd_t mqdes)
+{
+    return close(mqdes);
+}
+
+#endif

+ 33 - 0
librt/mq_getsetattr.c

@@ -0,0 +1,33 @@
+/*
+ * mq_getattr.c - get message queue attributes.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#ifdef __NR_mq_getsetattr
+
+#define __NR___syscall_mq_getsetattr __NR_mq_getsetattr
+static inline _syscall3(int, __syscall_mq_getsetattr, int, mqdes,
+	const void *, mqstat, void *, omqstat);
+
+/*
+ * Set attributes associated with message queue (and possibly also get
+ * its old attributes)
+ */
+int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat,
+		struct mq_attr *omqstat)
+{
+    return __syscall_mq_getsetattr(mqdes, mqstat, omqstat);
+}
+
+/* Query status and attributes of message queue */
+int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat)
+{
+    return mq_setattr(mqdes, NULL, mqstat);
+}
+
+#endif

+ 28 - 0
librt/mq_notify.c

@@ -0,0 +1,28 @@
+/*
+ * mq_notify.c - notify process that a message is available.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#ifdef __NR_mq_notify
+
+#define __NR___syscall_mq_notify __NR_mq_notify
+static inline _syscall2(int, __syscall_mq_notify, int, mqdes,
+	const void *, notification);
+
+/* Register notification upon message arrival to an empty message queue */
+int mq_notify(mqd_t mqdes, const struct sigevent *notification)
+{
+    /* We don't support SIGEV_THREAD notification yet */
+    if (notification != NULL && notification->sigev_notify == SIGEV_THREAD) {
+	__set_errno(ENOSYS);
+	return -1;
+    }
+    return __syscall_mq_notify(mqdes, notification);
+}
+
+#endif

+ 52 - 0
librt/mq_open.c

@@ -0,0 +1,52 @@
+/*
+ * mq_open.c - open a message queue.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#ifdef __NR_mq_open
+
+#define __NR___syscall_mq_open __NR_mq_open
+static inline _syscall4(int, __syscall_mq_open, const char *, name,
+	int, oflag, __kernel_mode_t, mode, void *, attr);
+/*
+ * Establish connection between a process and a message queue and
+ * return message queue descriptor or (mqd_t) -1 on error.
+ * oflag determines the type of access used. If O_CREAT is on oflag, the
+ * third argument is taken as a `mode_t', the mode of the created
+ * message queue, and the fourth argument is taken as `struct mq_attr *',
+ * pointer to message queue attributes.
+ * If the fourth argument is NULL, default attributes are used.
+ */
+mqd_t mq_open(const char *name, int oflag, ...)
+{
+    mode_t mode;
+    struct mq_attr *attr;
+
+    if (name[0] != '/') {
+	__set_errno(EINVAL);
+	return -1;
+    }
+
+    mode = 0;
+    attr = NULL;
+
+    if (oflag & O_CREAT) {
+	va_list ap;
+
+	va_start(ap, oflag);
+	mode = va_arg(ap, mode_t);
+	attr = va_arg(ap, struct mq_attr *);
+
+	va_end(ap);
+    }
+
+    return __syscall_mq_open(name + 1, oflag, mode, attr);
+}
+
+#endif

+ 36 - 0
librt/mq_receive.c

@@ -0,0 +1,36 @@
+/*
+ * mq_receive.c - functions for receiving from message queue.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#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);
+
+/*
+ * Receive the oldest from highest priority messages.
+ * Stop waiting if abs_timeout expires.
+ */
+ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
+			unsigned int *msg_prio,
+			const struct timespec *abs_timeout)
+{
+    return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
+}
+
+/* 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)
+{
+    return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL);
+}
+
+#endif

+ 36 - 0
librt/mq_send.c

@@ -0,0 +1,36 @@
+/*
+ * mq_send.c - functions for sending to message queue.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#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);
+
+/*
+ * 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.
+ */
+int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
+		unsigned int msg_prio,
+		const struct timespec *abs_timeout)
+{
+    return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
+}
+
+/* Add a message to queue */
+int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
+		unsigned int msg_prio)
+{
+    return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL);
+}
+
+#endif

+ 38 - 0
librt/mq_unlink.c

@@ -0,0 +1,38 @@
+/*
+ * mq_unlink.c - remove a message queue.
+ */
+
+#include <errno.h>
+#include <sys/syscall.h>
+
+#include <mqueue.h>
+
+#ifdef __NR_mq_unlink
+
+#define __NR___syscall_mq_unlink __NR_mq_unlink
+static inline _syscall1(int, __syscall_mq_unlink, const char *, name);
+
+/* Remove message queue */
+int mq_unlink(const char *name)
+{
+    int ret;
+    if (name[0] != '/') {
+	__set_errno(EINVAL);
+	return -1;
+    }
+
+    ret = __syscall_mq_unlink(name + 1);
+
+    /* While unlink can return either EPERM or EACCES, mq_unlink should return just EACCES.  */
+    if (ret < 0) {
+	ret = errno;
+	if (ret == EPERM)
+	    ret = EACCES;
+	__set_errno(ret);
+	ret = -1;
+    }
+
+    return ret;
+}
+
+#endif

+ 70 - 0
librt/timer_create.c

@@ -0,0 +1,70 @@
+/*
+ * timer_create.c - create a per-process timer.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/syscall.h>
+
+#include "kernel-posix-timers.h"
+
+#ifdef __NR_timer_create
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#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);
+
+/* Create a per-process timer */
+int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
+{
+    int retval;
+    kernel_timer_t ktimerid;
+    struct sigevent local_evp;
+    struct timer *newp;
+
+    /* Notification via a thread is not supported yet */
+    if (__builtin_expect(evp->sigev_notify == SIGEV_THREAD, 1))
+	return -1;
+
+    /*
+     * We avoid allocating too much memory by basically using
+     * struct timer as a derived class with the first two elements
+     * being in the superclass. We only need these two elements here.
+     */
+    newp = (struct timer *) malloc(offsetof(struct timer, thrfunc));
+    if (newp == NULL)
+	return -1;	/* No memory */
+
+    if (evp == NULL) {
+	/*
+	 * The kernel has to pass up the timer ID which is a userlevel object.
+	 * Therefore we cannot leave it up to the kernel to determine it.
+	 */
+	local_evp.sigev_notify = SIGEV_SIGNAL;
+	local_evp.sigev_signo = SIGALRM;
+	local_evp.sigev_value.sival_ptr = newp;
+
+	evp = &local_evp;
+    }
+
+    retval = __syscall_timer_create(clock_id, evp, &ktimerid);
+    if (retval != -1) {
+	newp->sigev_notify = (evp != NULL ? evp->sigev_notify : SIGEV_SIGNAL);
+	newp->ktimerid = ktimerid;
+
+	*timerid = (timer_t) newp;
+    } else {
+	/* Cannot allocate the timer, fail */
+	free(newp);
+	retval = -1;
+    }
+
+    return retval;
+}
+
+#endif

+ 33 - 0
librt/timer_delete.c

@@ -0,0 +1,33 @@
+/*
+ * timer_delete.c - delete a per-process timer.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/syscall.h>
+
+#include "kernel-posix-timers.h"
+
+#ifdef __NR_timer_delete
+
+#define __NR___syscall_timer_delete __NR_timer_delete
+static inline _syscall1(int, __syscall_timer_delete, kernel_timer_t, ktimerid);
+
+/* Delete a per-process timer */
+int timer_delete(timer_t timerid)
+{
+    int res;
+    struct timer *kt = (struct timer *) timerid;
+
+    /* Delete the kernel timer object */
+    res = __syscall_timer_delete(kt->ktimerid);
+    if (res == 0) {
+	free(kt);	/* Free the memory */
+	return 0;
+    }
+
+    return -1;
+}
+
+#endif

+ 25 - 0
librt/timer_getoverr.c

@@ -0,0 +1,25 @@
+/*
+ * timer-getoverr.c - get the timer overrun count.
+ */
+
+#include <errno.h>
+#include <time.h>
+#include <sys/syscall.h>
+
+#include "kernel-posix-timers.h"
+
+#ifdef __NR_timer_getoverrun
+
+#define __NR___syscall_timer_getoverrun __NR_timer_getoverrun
+static inline _syscall1(int, __syscall_timer_getoverrun, kernel_timer_t, ktimerid);
+
+/* Get the timer overrun count */
+int timer_getoverrun(timer_t timerid)
+{
+    struct timer *kt = (struct timer *) timerid;
+
+    /* Get the information from the kernel */
+    return __syscall_timer_getoverrun(kt->ktimerid);
+}
+
+#endif

+ 26 - 0
librt/timer_gettime.c

@@ -0,0 +1,26 @@
+/*
+ * timer_gettime.c - get the timer value.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/syscall.h>
+
+#include "kernel-posix-timers.h"
+
+#ifdef __NR_timer_gettime
+
+#define __NR___syscall_timer_gettime __NR_timer_gettime
+static inline _syscall2(int, __syscall_timer_gettime, kernel_timer_t, ktimerid, void *, value);
+
+/* Get the amount of time left on a timer */
+int timer_gettime(timer_t timerid, struct itimerspec *value)
+{
+    struct timer *kt = (struct timer *) timerid;
+
+    /* Get timeout from the kernel */
+    return __syscall_timer_gettime(kt->ktimerid, value);
+}
+
+#endif

+ 28 - 0
librt/timer_settime.c

@@ -0,0 +1,28 @@
+/*
+ * timer_settime.c - set the timer.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/syscall.h>
+
+#include "kernel-posix-timers.h"
+
+#ifdef __NR_timer_settime
+
+#define __NR___syscall_timer_settime __NR_timer_settime
+static inline _syscall4(int, __syscall_timer_settime, kernel_timer_t, ktimerid,
+	int, flags, const void *, value, void *, ovalue);
+
+/* Set the expiration time for a timer */
+int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
+		    struct itimerspec *ovalue)
+{
+    struct timer *kt = (struct timer *) timerid;
+
+    /* Set timeout */
+    return __syscall_timer_settime(kt->ktimerid, flags, value, ovalue);
+}
+
+#endif