diff options
1038 files changed, 93169 insertions, 935 deletions
diff --git a/Makefile.in b/Makefile.in index 39dd18cc1..0e0091f6d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -114,7 +114,8 @@ target-headers-sysdep := \ $(ALL_HEADERS_BITS_ARCH) \ $(ALL_HEADERS_BITS_SUBARCH) \ $(ALL_HEADERS_SYS_COMMON) \ - $(ALL_HEADERS_SYS_ARCH) + $(ALL_HEADERS_SYS_ARCH) \ + $(ALL_HEADERS_BITS_PTHREAD) $(top_builddir)include/fpu_control.h: @$(disp_ln) @@ -160,6 +161,14 @@ headers-y += $(target-headers-sysdep) headers: $(top_builddir)include/bits/uClibc_config.h subdirs: $(addprefix $(top_builddir),$(subdirs)) pregen: $(top_builddir)include/bits/sysnum.h headers subdirs + $(Q)$(if $(UCLIBC_HAS_LOCALE),$(MAKE) -C extra/locale locale_headers) +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) + $(Q)$(MAKE) nptl_headers +ifeq ($(shell $(CC) --help 2>&1 > /dev/null && echo yes),yes) + $(Q)$(MAKE) nptl_arch_headers + $(Q)$(MAKE) nptl_linux_headers +endif +endif $(top_builddir)include/bits/sysnum.h: $(top_srcdir)extra/scripts/gen_bits_syscall_h.sh $(Q)$(INSTALL) -d $(@D) @@ -228,7 +228,7 @@ CPU_CFLAGS-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += -msep-data CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN) += -Wl,-EL CPU_LDFLAGS-$(ARCH_BIG_ENDIAN) += -Wl,-EB -PICFLAG-y := -fPIC +PICFLAG-y := -fPIC -DPIC PICFLAG-$(UCLIBC_FORMAT_FDPIC_ELF) := -mfdpic PICFLAG := $(PICFLAG-y) PIEFLAG_NAME:=-fPIE @@ -587,7 +587,7 @@ endif LDFLAGS:=$(LDFLAGS_NOSTRIP) -Wl,-z,defs ifeq ($(DODEBUG),y) -CFLAGS += -O0 -g3 +CFLAGS += -O0 -g3 -DDEBUG else CFLAGS += $(OPTIMIZATION) endif @@ -630,6 +630,7 @@ PTDIR := libpthread/$(PTNAME) # set up system dependencies include dirs (NOTE: order matters!) ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) PTINC:= -I$(top_srcdir)$(PTDIR) \ + -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/$(TARGET_SUBARCH) \ -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ -I$(top_srcdir)$(PTDIR)/sysdeps/$(TARGET_ARCH) \ -I$(top_srcdir)$(PTDIR)/sysdeps/unix/sysv/linux \ @@ -669,6 +670,7 @@ else PTNAME := PTINC := endif +CFLAGS += -I$(top_srcdir)libc/sysdeps/linux/common CFLAGS += -I$(KERNEL_HEADERS) #CFLAGS += -iwithprefix include-fixed -iwithprefix include diff --git a/libc/Makefile.in b/libc/Makefile.in index 7297e9284..c4cf5d7c7 100644 --- a/libc/Makefile.in +++ b/libc/Makefile.in @@ -16,7 +16,9 @@ VERSION_SCRIPT := -Wl,--version-script,$(VERSION_SCRIPT) endif LDFLAGS-libc.so := $(LDFLAGS) $(VERSION_SCRIPT) -Wl,-init,$(SYMBOL_PREFIX)__uClibc_init - +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS += -D__USE_STDIO_FUTEXES__ +endif LIBS-libc.so := $(interp) $(ldso) $(top_builddir)lib/$(NONSHARED_LIBNAME) # we have SHARED_MAJORNAME=libc.so.$(MAJOR_VERSION) defined in Rules.mak diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c index b91486f53..4a42b9eb6 100644 --- a/libc/inet/getaddrinfo.c +++ b/libc/inet/getaddrinfo.c @@ -307,7 +307,7 @@ gaih_local(const char *name, const struct gaih_service *service, char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path; if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0 - || __gen_tempname(buf, __GT_NOCREATE) != 0 + || __gen_tempname(buf, __GT_NOCREATE, 0) != 0 ) { return -EAI_SYSTEM; } diff --git a/libc/inet/hostid.c b/libc/inet/hostid.c index 99346d7f8..c6d6204ae 100644 --- a/libc/inet/hostid.c +++ b/libc/inet/hostid.c @@ -14,6 +14,7 @@ #include <netdb.h> #include <fcntl.h> #include <unistd.h> +#include <not-cancel.h> #define HOSTID "/etc/hostid" @@ -26,11 +27,11 @@ int sethostid(long int new_id) if (geteuid() || getuid()) return __set_errno(EPERM); - fd = open(HOSTID, O_CREAT|O_WRONLY, 0644); + fd = open_not_cancel(HOSTID, O_CREAT|O_WRONLY, 0644); if (fd < 0) return fd; - ret = write(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1; - close(fd); + ret = write_not_cancel(fd, &new_id, sizeof(new_id)) == sizeof(new_id) ? 0 : -1; + close_not_cancel_no_status (fd); return ret; } #endif @@ -44,13 +45,13 @@ long int gethostid(void) * It is not an error if we cannot read this file. It is not even an * error if we cannot read all the bytes, we just carry on trying... */ - fd = open(HOSTID, O_RDONLY); - if (fd >= 0 && read(fd, &id, sizeof(id))) + fd = open_not_cancel_2(HOSTID, O_RDONLY); + if (fd >= 0 && read_not_cancel(fd, &id, sizeof(id))) { - close (fd); + close_not_cancel_no_status (fd); return id; } - if (fd >= 0) close (fd); + if (fd >= 0) close_not_cancel_no_status (fd); /* Try some methods of returning a unique 32 bit id. Clearly IP * numbers, if on the internet, will have a unique address. If they diff --git a/libc/inet/if_index.c b/libc/inet/if_index.c index 750a4649e..8efcd2a76 100644 --- a/libc/inet/if_index.c +++ b/libc/inet/if_index.c @@ -32,6 +32,7 @@ #include <sys/socket.h> #include <sys/ioctl.h> #include <libc-internal.h> +#include <not-cancel.h> #include "netlinkaccess.h" @@ -55,13 +56,13 @@ if_nametoindex(const char* ifname) { /* close never fails here, fd is just a unconnected socket. *int saved_errno = errno; */ - close(fd); + close_not_cancel_no_status(fd); /*if (saved_errno == EINVAL) * __set_errno(ENOSYS); */ return 0; } - close(fd); + close_not_cancel_no_status(fd); return ifr.ifr_ifindex; #endif } @@ -112,7 +113,7 @@ if_nameindex (void) if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) { - close (fd); + close_not_cancel_no_status (fd); return NULL; } } @@ -123,7 +124,7 @@ if_nameindex (void) idx = malloc ((nifs + 1) * sizeof (struct if_nameindex)); if (idx == NULL) { - close(fd); + close_not_cancel_no_status (fd); __set_errno(ENOBUFS); return NULL; } @@ -141,7 +142,7 @@ if_nameindex (void) for (j = 0; j < i; ++j) free (idx[j].if_name); free(idx); - close(fd); + close_not_cancel_no_status (fd); if (saved_errno == EINVAL) saved_errno = ENOSYS; else if (saved_errno == ENOMEM) @@ -155,7 +156,7 @@ if_nameindex (void) idx[i].if_index = 0; idx[i].if_name = NULL; - close(fd); + close_not_cancel_no_status (fd); return idx; #endif } @@ -298,14 +299,14 @@ if_indextoname (unsigned int ifindex, char *ifname) if (ioctl (fd, SIOCGIFNAME, &ifr) < 0) { int serrno = errno; - close (fd); + close_not_cancel_no_status (fd); if (serrno == ENODEV) /* POSIX requires ENXIO. */ serrno = ENXIO; __set_errno (serrno); return NULL; } - close (fd); + close_not_cancel_no_status (fd); return strncpy (ifname, ifr.ifr_name, IFNAMSIZ); # else diff --git a/libc/inet/socketcalls.c b/libc/inet/socketcalls.c index 8bb09cabb..e4bdbcb59 100644 --- a/libc/inet/socketcalls.c +++ b/libc/inet/socketcalls.c @@ -33,27 +33,41 @@ extern int __socketcall(int call, unsigned long *args) attribute_hidden; #define SYS_RECVMSG 17 #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#include <pthreadP.h> +#else +#define SINGLE_THREAD_P 1 +#endif #ifdef L_accept -# ifdef __NR_accept -_syscall3(int, accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen) -# elif defined(__NR_socketcall) -int accept(int s, struct sockaddr *addr, socklen_t * addrlen) +extern __typeof(accept) __libc_accept; +#ifdef __NR_accept +#define __NR___libc_accept __NR_accept +_syscall3(int, __libc_accept, int, call, struct sockaddr *, addr, socklen_t *,addrlen) +#elif defined(__NR_socketcall) +int __libc_accept(int s, struct sockaddr *addr, socklen_t * addrlen) { unsigned long args[3]; args[0] = s; args[1] = (unsigned long) addr; args[2] = (unsigned long) addrlen; - return __socketcall(SYS_ACCEPT, args); + + if (SINGLE_THREAD_P) + return __socketcall(SYS_ACCEPT, args); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_ACCEPT, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif + } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(accept) -# else +#endif +weak_alias(__libc_accept,accept) libc_hidden_weak(accept) -strong_alias(accept,__libc_accept) -# endif #endif #ifdef L_bind @@ -74,25 +88,32 @@ libc_hidden_def(bind) #endif #ifdef L_connect -# ifdef __NR_connect -_syscall3(int, connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen) -# elif defined(__NR_socketcall) -int connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen) +extern __typeof(connect) __libc_connect; +#ifdef __NR_connect +#define __NR___libc_connect __NR_connect +_syscall3(int, __libc_connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen) +#elif defined(__NR_socketcall) +int __libc_connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen) { unsigned long args[3]; args[0] = sockfd; args[1] = (unsigned long) saddr; args[2] = addrlen; - return __socketcall(SYS_CONNECT, args); + + if (SINGLE_THREAD_P) + return __socketcall(SYS_CONNECT, args); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_CONNECT, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(connect) -# else +#endif +weak_alias(__libc_connect,connect) libc_hidden_weak(connect) -strong_alias(connect,__libc_connect) -# endif #endif #ifdef L_getpeername @@ -164,12 +185,14 @@ libc_hidden_def(listen) #endif #ifdef L_recv -# ifdef __NR_recv -_syscall4(ssize_t, recv, int, sockfd, __ptr_t, buffer, size_t, len, +extern __typeof(recv) __libc_recv; +#ifdef __NR_recv +#define __NR___libc_recv __NR_recv +_syscall4(ssize_t, __libc_recv, int, sockfd, __ptr_t, buffer, size_t, len, int, flags) -# elif defined(__NR_socketcall) +#elif defined(__NR_socketcall) /* recv, recvfrom added by bir7@leland.stanford.edu */ -ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags) +ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags) { unsigned long args[4]; @@ -177,29 +200,36 @@ ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags) args[1] = (unsigned long) buffer; args[2] = len; args[3] = flags; - return (__socketcall(SYS_RECV, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_RECV, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_RECV, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# elif defined(__NR_recvfrom) -ssize_t recv(int sockfd, __ptr_t buffer, size_t len, int flags) +#elif defined(__NR_recvfrom) +ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags) { return (recvfrom(sockfd, buffer, len, flags, NULL, NULL)); } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(recv) -# else +#endif +weak_alias(__libc_recv,recv) libc_hidden_weak(recv) -strong_alias(recv,__libc_recv) -# endif #endif #ifdef L_recvfrom -# ifdef __NR_recvfrom -_syscall6(ssize_t, recvfrom, int, sockfd, __ptr_t, buffer, size_t, len, +extern __typeof(recvfrom) __libc_recvfrom; +#ifdef __NR_recvfrom +#define __NR___libc_recvfrom __NR_recvfrom +_syscall6(ssize_t, __libc_recvfrom, int, sockfd, __ptr_t, buffer, size_t, len, int, flags, struct sockaddr *, to, socklen_t *, tolen) -# elif defined(__NR_socketcall) +#elif defined(__NR_socketcall) /* recv, recvfrom added by bir7@leland.stanford.edu */ -ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags, +ssize_t __libc_recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags, struct sockaddr *to, socklen_t * tolen) { unsigned long args[6]; @@ -210,45 +240,59 @@ ssize_t recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags, args[3] = flags; args[4] = (unsigned long) to; args[5] = (unsigned long) tolen; - return (__socketcall(SYS_RECVFROM, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_RECVFROM, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_RECVFROM, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(recvfrom) -# else +#endif +weak_alias(__libc_recvfrom,recvfrom) libc_hidden_weak(recvfrom) -strong_alias(recvfrom,__libc_recvfrom) -# endif #endif #ifdef L_recvmsg -# ifdef __NR_recvmsg -_syscall3(ssize_t, recvmsg, int, sockfd, struct msghdr *, msg, int, flags) -# elif defined(__NR_socketcall) -ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) +extern __typeof(recvmsg) __libc_recvmsg; +#ifdef __NR_recvmsg +#define __NR___libc_recvmsg __NR_recvmsg +_syscall3(ssize_t, __libc_recvmsg, int, sockfd, struct msghdr *, msg, int, flags) +#elif defined(__NR_socketcall) +ssize_t __libc_recvmsg(int sockfd, struct msghdr *msg, int flags) { unsigned long args[3]; args[0] = sockfd; args[1] = (unsigned long) msg; args[2] = flags; - return (__socketcall(SYS_RECVMSG, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_RECVMSG, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_RECVMSG, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(recvmsg) -# else +#endif +weak_alias(__libc_recvmsg,recvmsg) libc_hidden_weak(recvmsg) -strong_alias(recvmsg,__libc_recvmsg) -# endif #endif #ifdef L_send -# ifdef __NR_send -_syscall4(ssize_t, send, int, sockfd, const void *, buffer, size_t, len, int, flags) -# elif defined(__NR_socketcall) +extern __typeof(send) __libc_send; +#ifdef __NR_send +#define __NR___libc_send __NR_send +_syscall4(ssize_t, __libc_send, int, sockfd, const void *, buffer, size_t, len, int, flags) +#elif defined(__NR_socketcall) /* send, sendto added by bir7@leland.stanford.edu */ -ssize_t send(int sockfd, const void *buffer, size_t len, int flags) +ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags) { unsigned long args[4]; @@ -256,51 +300,65 @@ ssize_t send(int sockfd, const void *buffer, size_t len, int flags) args[1] = (unsigned long) buffer; args[2] = len; args[3] = flags; - return (__socketcall(SYS_SEND, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_SEND, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_SEND, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# elif defined(__NR_sendto) -ssize_t send(int sockfd, const void *buffer, size_t len, int flags) +#elif defined(__NR_sendto) +ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags) { return (sendto(sockfd, buffer, len, flags, NULL, 0)); } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(send) -# else +#endif +weak_alias(__libc_send,send) libc_hidden_weak(send) -strong_alias(send,__libc_send) -# endif #endif #ifdef L_sendmsg -# ifdef __NR_sendmsg -_syscall3(ssize_t, sendmsg, int, sockfd, const struct msghdr *, msg, int, flags) -# elif defined(__NR_socketcall) -ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) +extern __typeof(sendmsg) __libc_sendmsg; +#ifdef __NR_sendmsg +#define __NR___libc_sendmsg __NR_sendmsg +_syscall3(ssize_t, __libc_sendmsg, int, sockfd, const struct msghdr *, msg, int, flags) +#elif defined(__NR_socketcall) +ssize_t __libc_sendmsg(int sockfd, const struct msghdr *msg, int flags) { unsigned long args[3]; args[0] = sockfd; args[1] = (unsigned long) msg; args[2] = flags; - return (__socketcall(SYS_SENDMSG, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_SENDMSG, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_SENDMSG, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(sendmsg) -# else +#endif +weak_alias(__libc_sendmsg,sendmsg) libc_hidden_weak(sendmsg) -strong_alias(sendmsg,__libc_sendmsg) -# endif #endif #ifdef L_sendto -# ifdef __NR_sendto -_syscall6(ssize_t, sendto, int, sockfd, const void *, buffer, +extern __typeof(sendto) __libc_sendto; +#ifdef __NR_sendto +#define __NR___libc_sendto __NR_sendto +_syscall6(ssize_t, __libc_sendto, int, sockfd, const void *, buffer, size_t, len, int, flags, const struct sockaddr *, to, socklen_t, tolen) -# elif defined(__NR_socketcall) +#elif defined(__NR_socketcall) /* send, sendto added by bir7@leland.stanford.edu */ -ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags, +ssize_t __libc_sendto(int sockfd, const void *buffer, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { unsigned long args[6]; @@ -311,15 +369,20 @@ ssize_t sendto(int sockfd, const void *buffer, size_t len, int flags, args[3] = flags; args[4] = (unsigned long) to; args[5] = tolen; - return (__socketcall(SYS_SENDTO, args)); + + if (SINGLE_THREAD_P) + return (__socketcall(SYS_SENDTO, args)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __socketcall(SYS_SENDTO, args); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -# endif -# ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(sendto) -# else +#endif +weak_alias(__libc_sendto,sendto) libc_hidden_weak(sendto) -strong_alias(sendto,__libc_sendto) -# endif #endif #ifdef L_setsockopt diff --git a/libc/misc/Makefile.in b/libc/misc/Makefile.in index 838081d66..6c09d3142 100644 --- a/libc/misc/Makefile.in +++ b/libc/misc/Makefile.in @@ -21,6 +21,7 @@ include $(top_srcdir)libc/misc/gnu/Makefile.in include $(top_srcdir)libc/misc/internals/Makefile.in include $(top_srcdir)libc/misc/locale/Makefile.in include $(top_srcdir)libc/misc/mntent/Makefile.in +include $(top_srcdir)libc/misc/pthread/Makefile.in include $(top_srcdir)libc/misc/regex/Makefile.in include $(top_srcdir)libc/misc/search/Makefile.in include $(top_srcdir)libc/misc/statfs/Makefile.in diff --git a/libc/misc/dirent/closedir.c b/libc/misc/dirent/closedir.c index cca03b8f7..dfb53f888 100644 --- a/libc/misc/dirent/closedir.c +++ b/libc/misc/dirent/closedir.c @@ -9,6 +9,7 @@ #include <stdlib.h> #include <unistd.h> #include "dirstream.h" +#include <not-cancel.h> int closedir(DIR * dir) @@ -31,6 +32,6 @@ int closedir(DIR * dir) __UCLIBC_MUTEX_UNLOCK(dir->dd_lock); free(dir->dd_buf); free(dir); - return close(fd); + return close_not_cancel(fd); } libc_hidden_def(closedir) diff --git a/libc/misc/dirent/opendir.c b/libc/misc/dirent/opendir.c index b43f60814..4a23ab061 100644 --- a/libc/misc/dirent/opendir.c +++ b/libc/misc/dirent/opendir.c @@ -12,6 +12,7 @@ #include <unistd.h> #include <sys/dir.h> #include <sys/stat.h> +#include <not-cancel.h> #include <dirent.h> #include "dirstream.h" @@ -81,7 +82,7 @@ DIR *opendir(const char *name) } # define O_DIRECTORY 0 #endif - fd = open(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC); + fd = open_not_cancel_2(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC); if (fd < 0) return NULL; /* Note: we should check to make sure that between the stat() and open() @@ -93,7 +94,7 @@ DIR *opendir(const char *name) /* this close() never fails *int saved_errno; *saved_errno = errno; */ - close(fd); + close_not_cancel_no_status(fd); /*__set_errno(saved_errno);*/ return NULL; } @@ -102,12 +103,13 @@ DIR *opendir(const char *name) * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>. */ #ifndef __ASSUME_O_CLOEXEC - fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl_not_cancel(fd, F_SETFD, FD_CLOEXEC); #endif ptr = fd_to_DIR(fd, statbuf.st_blksize); + if (!ptr) { - close(fd); + close_not_cancel_no_status(fd); __set_errno(ENOMEM); } return ptr; diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index b166aaaa7..85dbe7123 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -1,5 +1,6 @@ /* - * Copyright (C) Feb 2001 Manuel Novoa III + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2001 by Manuel Novoa III <mjn3@uclibc.org> * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -13,8 +14,10 @@ * avoided in the static library case. */ -#define _ERRNO_H #include <features.h> +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ +#define _ERRNO_H +#endif #include <unistd.h> #include <stdlib.h> #include <string.h> @@ -22,10 +25,17 @@ #include <link.h> #include <bits/uClibc_page.h> #include <paths.h> +#include <unistd.h> #include <asm/errno.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/sysmacros.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <pthread-functions.h> +#include <not-cancel.h> +#include <atomic.h> +#endif #ifndef SHARED @@ -64,16 +74,17 @@ void internal_function _dl_aux_init (ElfW(auxv_t) *av); * Prototypes. */ extern int *weak_const_function __errno_location(void); -libc_hidden_proto(__errno_location) extern int *weak_const_function __h_errno_location(void); -libc_hidden_proto(__h_errno_location) - extern void weak_function _stdio_init(void) attribute_hidden; #ifdef __UCLIBC_HAS_LOCALE__ extern void weak_function _locale_init(void) attribute_hidden; #endif #ifdef __UCLIBC_HAS_THREADS__ +#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED) extern void weak_function __pthread_initialize_minimal(void); +#else +extern void __pthread_initialize_minimal(void); +#endif #endif /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation and finalisation @@ -126,7 +137,7 @@ static void __check_one_fd(int fd, int mode) int nullfd = open(_PATH_DEVNULL, mode); /* /dev/null is major=1 minor=3. Make absolutely certain * that is in fact the device that we have opened and not - * some other weird file... [removed in uclibc] */ + * some other wierd file... [removed in uclibc] */ if (nullfd!=fd) { abort(); @@ -183,7 +194,9 @@ void __uClibc_init(void) * __pthread_initialize_minimal so we can use pthread_locks * whenever they are needed. */ +#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED) if (likely(__pthread_initialize_minimal!=NULL)) +#endif __pthread_initialize_minimal(); #endif @@ -267,6 +280,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, ElfW(auxv_t) auxvt[AT_EGID + 1]; #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + /* Result of the 'main' function. */ + int result; +#endif + #ifndef SHARED __libc_stack_end = stack_end; #endif @@ -386,34 +404,57 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, if (likely(__h_errno_location!=NULL)) *(__h_errno_location()) = 0; - /* - * Finally, invoke application's main and then exit. - */ - exit(main(argc, argv, __environ)); -} +#if defined HAVE_CLEANUP_JMP_BUF && defined __UCLIBC_HAS_THREADS_NATIVE__ + /* Memory for the cancellation buffer. */ + struct pthread_unwind_buf unwind_buf; -#if defined(__UCLIBC_HAS_THREADS__) && !defined(SHARED) -/* Weaks for internal library use only. - * - * We need to define weaks here to cover all the pthread functions that - * libc itself will use so that we aren't forced to link libc against - * libpthread. This file is only used in libc.a and since we have - * weaks here, they will be automatically overridden by libpthread.a - * if it gets linked in. - */ + int not_first_call; + not_first_call = + setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + if (__builtin_expect (! not_first_call, 1)) + { + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); + + /* Run the program. */ + result = main (argc, argv, __environ); + } + else + { + /* Remove the thread-local data. */ +# ifdef SHARED + __libc_pthread_functions.ptr__nptl_deallocate_tsd (); +# else + extern void __nptl_deallocate_tsd (void) __attribute ((weak)); + __nptl_deallocate_tsd (); +# endif -static int __pthread_return_0 (void) { return 0; } -static void __pthread_return_void (void) { return; } - -weak_alias (__pthread_return_0, __pthread_mutex_init) -weak_alias (__pthread_return_0, __pthread_mutex_lock) -weak_alias (__pthread_return_0, __pthread_mutex_trylock) -weak_alias (__pthread_return_0, __pthread_mutex_unlock) -weak_alias (__pthread_return_void, _pthread_cleanup_push_defer) -weak_alias (__pthread_return_void, _pthread_cleanup_pop_restore) -# ifdef __UCLIBC_HAS_THREADS_NATIVE__ -weak_alias (__pthread_return_0, __pthread_mutexattr_init) -weak_alias (__pthread_return_0, __pthread_mutexattr_destroy) -weak_alias (__pthread_return_0, __pthread_mutexattr_settype) + /* One less thread. Decrement the counter. If it is zero we + terminate the entire process. */ + result = 0; +# ifdef SHARED + unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads; +# else + extern unsigned int __nptl_nthreads __attribute ((weak)); + unsigned int *const ptr = &__nptl_nthreads; # endif + + if (! atomic_decrement_and_test (ptr)) + /* Not much left to do but to exit the thread, not the process. */ + __exit_thread_inline (0); + } + + exit (result); +#else + /* + * Finally, invoke application's main and then exit. + */ + exit (main (argc, argv, __environ)); #endif +} diff --git a/libc/misc/internals/tempname.c b/libc/misc/internals/tempname.c index cbd4ced7a..4145c9478 100644 --- a/libc/misc/internals/tempname.c +++ b/libc/misc/internals/tempname.c @@ -168,14 +168,14 @@ static void brain_damaged_fillrand(unsigned char *buf, unsigned int len) KIND may be one of: __GT_NOCREATE: simply verify that the name does not exist - at the time of the call. + at the time of the call. mode argument is ignored. __GT_FILE: create the file using open(O_CREAT|O_EXCL) - and return a read-write fd. The file is mode 0600. + and return a read-write fd with given mode. __GT_BIGFILE: same as __GT_FILE but use open64(). - __GT_DIR: create a directory, which will be mode 0700. + __GT_DIR: create a directory with given mode. */ -int attribute_hidden __gen_tempname (char *tmpl, int kind) +int __gen_tempname (char *tmpl, int kind, mode_t mode) { char *XXXXXX; unsigned int i; @@ -217,15 +217,15 @@ int attribute_hidden __gen_tempname (char *tmpl, int kind) fd = 0; } case __GT_FILE: - fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode); break; #if defined __UCLIBC_HAS_LFS__ case __GT_BIGFILE: - fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode); break; #endif case __GT_DIR: - fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); + fd = mkdir (tmpl, mode); break; default: fd = -1; diff --git a/libc/misc/internals/tempname.h b/libc/misc/internals/tempname.h index ac40bef6e..017dc5190 100644 --- a/libc/misc/internals/tempname.h +++ b/libc/misc/internals/tempname.h @@ -3,13 +3,14 @@ #define __need_size_t #include <stddef.h> +#include <sys/types.h> /* Disable support for $TMPDIR */ extern int ___path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx /*, int try_tmpdir */) attribute_hidden; #define __path_search(tmpl, tmpl_len, dir, pfx, try_tmpdir) ___path_search(tmpl, tmpl_len, dir, pfx) -extern int __gen_tempname (char *__tmpl, int __kind) attribute_hidden; +extern int __gen_tempname (char *__tmpl, int __kind, mode_t mode); /* The __kind argument to __gen_tempname may be one of: */ #define __GT_FILE 0 /* create a file */ diff --git a/libc/misc/pthread/Makefile.in b/libc/misc/pthread/Makefile.in index ceea1c21b..48e816236 100644 --- a/libc/misc/pthread/Makefile.in +++ b/libc/misc/pthread/Makefile.in @@ -10,6 +10,7 @@ subdirs += libc/misc/pthread MISC_PTHREAD_DIR := $(top_srcdir)libc/misc/pthread MISC_PTHREAD_OUT := $(top_builddir)libc/misc/pthread +libc-shared-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/tsd.os libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/unlock.o libc-$(UCLIBC_HAS_THREADS) += $(MISC_PTHREAD_OUT)/weaks.o diff --git a/libc/misc/pthread/tsd.c b/libc/misc/pthread/tsd.c new file mode 100644 index 000000000..835ee22ce --- /dev/null +++ b/libc/misc/pthread/tsd.c @@ -0,0 +1,10 @@ +/* libpthread sets _dl_error_catch_tsd to point to this function. + We define it here instead of in libpthread so t here instead of in libpthread so that it doesn't + need to have a TLS segment of its own just for this one pointer. */ + +void ** __attribute__ ((const)) +__libc_dl_error_tsd (void) +{ + static __thread void *data __attribute__ ((tls_model ("initial-exec"))); + return &data; +} diff --git a/libc/misc/sysvipc/msgq.c b/libc/misc/sysvipc/msgq.c index dac886f7f..e20e3ca64 100644 --- a/libc/misc/sysvipc/msgq.c +++ b/libc/misc/sysvipc/msgq.c @@ -1,6 +1,11 @@ #include <errno.h> #include <sys/msg.h> #include "ipc.h" +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include "sysdep-cancel.h" +#else +#define SINGLE_THREAD_P 1 +#endif #ifdef L_msgctl @@ -43,31 +48,65 @@ struct new_msg_buf{ #ifdef L_msgrcv #ifdef __NR_msgrcv -_syscall5(ssize_t, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long int, msgtyp, int, msgflg) -#else -ssize_t msgrcv (int msqid, void *msgp, size_t msgsz, - long int msgtyp, int msgflg) +#define __NR___syscall_msgrcv __NR_msgrcv +static inline _syscall5(ssize_t, __syscall_msgrcv, int, msqid, void *, msgp, + size_t, msgsz, long int, msgtyp, int, msgflg) +#endif +static inline ssize_t do_msgrcv (int msqid, void *msgp, size_t msgsz, + long int msgtyp, int msgflg) { +#ifdef __NR_msgrcv + return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); +#else struct new_msg_buf temp; temp.r_msgtyp = msgtyp; temp.oldmsg = msgp; return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0); +#endif } +int msgrcv (int msqid, void *msgp, size_t msgsz, + long int msgtyp, int msgflg) +{ + if (SINGLE_THREAD_P) + return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); + LIBC_CANCEL_RESET (oldtype); + return result; #endif +} #endif #ifdef L_msgsnd #ifdef __NR_msgsnd -_syscall4(int, msgsnd, int, msqid, const void *, msgp, size_t, msgsz, int, msgflg) -#else +#define __NR___syscall_msgsnd __NR_msgsnd +static inline _syscall4(int, __syscall_msgsnd, int, msqid, const void *, msgp, + size_t, msgsz, int, msgflg) +#endif /* Send message to message queue. */ -int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) +static inline int do_msgsnd (int msqid, const void *msgp, size_t msgsz, + int msgflg) { +#ifdef __NR_msgsnd + return __syscall_msgsnd(msqid, msgp, msgsz, msgflg); +#else return __syscall_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, (void *)msgp, 0); +#endif } +int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) +{ + if (SINGLE_THREAD_P) + return do_msgsnd(msqid, msgp, msgsz, msgflg); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = do_msgsnd(msqid, msgp, msgsz, msgflg); + LIBC_CANCEL_RESET (oldtype); + return result; #endif +} #endif diff --git a/libc/misc/utmp/utent.c b/libc/misc/utmp/utent.c index 336c0239b..a3f01b6e9 100644 --- a/libc/misc/utmp/utent.c +++ b/libc/misc/utmp/utent.c @@ -19,6 +19,7 @@ #include <errno.h> #include <string.h> #include <utmp.h> +#include <not-cancel.h> #include <bits/uClibc_mutex.h> __UCLIBC_MUTEX_STATIC(utmplock, PTHREAD_MUTEX_INITIALIZER); @@ -34,16 +35,16 @@ static const char *static_ut_name = default_file_name; static void __setutent(void) { if (static_fd < 0) { - static_fd = open(static_ut_name, O_RDWR | O_CLOEXEC); + static_fd = open_not_cancel_2(static_ut_name, O_RDWR | O_CLOEXEC); if (static_fd < 0) { - static_fd = open(static_ut_name, O_RDONLY | O_CLOEXEC); + static_fd = open_not_cancel_2(static_ut_name, O_RDONLY | O_CLOEXEC); if (static_fd < 0) { return; /* static_fd remains < 0 */ } } #ifndef __ASSUME_O_CLOEXEC /* Make sure the file will be closed on exec() */ - fcntl(static_fd, F_SETFD, FD_CLOEXEC); + fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC); #endif return; } @@ -70,7 +71,7 @@ static struct utmp *__getutent(void) } } - if (read(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) { + if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) { ret = &static_utmp; } @@ -81,7 +82,7 @@ void endutent(void) { __UCLIBC_MUTEX_LOCK(utmplock); if (static_fd >= 0) - close(static_fd); + close_not_cancel_no_status(static_fd); static_fd = -1; __UCLIBC_MUTEX_UNLOCK(utmplock); } @@ -182,7 +183,7 @@ int utmpname(const char *new_ut_name) } if (static_fd >= 0) { - close(static_fd); + close_not_cancel_no_status(static_fd); static_fd = -1; } __UCLIBC_MUTEX_UNLOCK(utmplock); diff --git a/libc/misc/utmp/wtent.c b/libc/misc/utmp/wtent.c index e73d99feb..5ab743d9b 100644 --- a/libc/misc/utmp/wtent.c +++ b/libc/misc/utmp/wtent.c @@ -13,6 +13,7 @@ #include <utmp.h> #include <fcntl.h> #include <sys/file.h> +#include <not-cancel.h> #if 0 /* This is enabled in uClibc/libutil/logwtmp.c */ @@ -36,12 +37,12 @@ void updwtmp(const char *wtmp_file, const struct utmp *lutmp) { int fd; - fd = open(wtmp_file, O_APPEND | O_WRONLY); + fd = open_not_cancel(wtmp_file, O_APPEND | O_WRONLY, 0); if (fd >= 0) { if (lockf(fd, F_LOCK, 0) == 0) { - write(fd, lutmp, sizeof(*lutmp)); + write_not_cancel(fd, lutmp, sizeof(struct utmp)); lockf(fd, F_ULOCK, 0); - close(fd); + close_not_cancel_no_status(fd); } } } diff --git a/libc/signal/Makefile.in b/libc/signal/Makefile.in index f768b7019..be9ddac94 100644 --- a/libc/signal/Makefile.in +++ b/libc/signal/Makefile.in @@ -21,6 +21,10 @@ ifeq ($(UCLIBC_SUSV4_LEGACY),y) CSRC += sigintr.c endif +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC:=$(filter-out raise.c sigaction.c,$(CSRC)) +endif + ifneq ($(strip $(ARCH_OBJS)),) CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)),$(CSRC)) endif diff --git a/libc/signal/sigpause.c b/libc/signal/sigpause.c index e465fac7a..8c4e83e76 100644 --- a/libc/signal/sigpause.c +++ b/libc/signal/sigpause.c @@ -23,7 +23,9 @@ #define __FAVOR_BSD #include <signal.h> #include <stddef.h> /* For NULL. */ -#include <string.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#endif #include "sigset-cvt-mask.h" @@ -45,6 +47,9 @@ int __sigpause (int sig_or_mask, int is_sig) else sigset_set_old_mask (&set, sig_or_mask); + /* Note the sigpause() is a cancellation point. But since we call + sigsuspend() which itself is a cancellation point we do not have + to do anything here. */ return sigsuspend (&set); } libc_hidden_def(__sigpause) @@ -56,5 +61,18 @@ libc_hidden_def(__sigpause) the BSD version. So make this the default. */ int sigpause (int mask) { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + if (SINGLE_THREAD_P) + return __sigpause (mask, 0); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = __sigpause (mask, 0); + + LIBC_CANCEL_RESET (oldtype); + + return result; +#else return __sigpause (mask, 0); +#endif } diff --git a/libc/signal/sigset-cvt-mask.h b/libc/signal/sigset-cvt-mask.h index 76dd01c7e..d4c2dc7ca 100644 --- a/libc/signal/sigset-cvt-mask.h +++ b/libc/signal/sigset-cvt-mask.h @@ -19,6 +19,8 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <string.h> + static __inline__ void __attribute__ ((unused)) sigset_set_old_mask (sigset_t *set, int mask) { diff --git a/libc/signal/sigwait.c b/libc/signal/sigwait.c index 6bca1b1e5..917e3d7be 100644 --- a/libc/signal/sigwait.c +++ b/libc/signal/sigwait.c @@ -1,7 +1,8 @@ /* vi: set sw=4 ts=4: */ /* sigwait * - * Copyright (C) 2003 by Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2003-2005 by Erik Andersen <andersen@uclibc.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,19 +23,86 @@ #include <signal.h> #include <string.h> -#if defined __UCLIBC_HAS_REALTIME__ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include <sysdep-cancel.h> -int sigwait(const sigset_t *set, int *sig) +# ifdef __NR_rt_sigtimedwait + +/* Return any pending signal or wait for one for the given time. */ +static int do_sigwait(const sigset_t *set, int *sig) +{ + int ret; + +# ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy(&tmpset, set, _NSIG / 8); + __sigdelset(&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset(&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +# endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + INTERNAL_SYSCALL_DECL(err); + do + ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set, NULL, + NULL, _NSIG / 8); + while (INTERNAL_SYSCALL_ERROR_P (ret, err) + && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR); + if (! INTERNAL_SYSCALL_ERROR_P (ret, err)) + { + *sig = ret; + ret = 0; + } +else + ret = INTERNAL_SYSCALL_ERRNO (ret, err); + + return ret; +} + +int sigwait (const sigset_t *set, int *sig) +{ + if(SINGLE_THREAD_P) + return do_sigwait(set, sig); + + int oldtype = LIBC_CANCEL_ASYNC(); + + int result = do_sigwait(set, sig); + + LIBC_CANCEL_RESET(oldtype); + + return result; +} +# else /* __NR_rt_sigtimedwait */ +# error We must have rt_sigtimedwait defined!!! +# endif +#else /* __UCLIBC_HAS_THREADS_NATIVE__ */ + +# if defined __UCLIBC_HAS_REALTIME__ + +int sigwait (const sigset_t *set, int *sig) { - int ret = sigwaitinfo(set, NULL); - if (ret != -1) { + int ret = 1; + if ((ret = sigwaitinfo(set, NULL)) != -1) { *sig = ret; return 0; } return 1; } -#else /* __UCLIBC_HAS_REALTIME__ */ +# else /* __UCLIBC_HAS_REALTIME__ */ /* variant without REALTIME extensions */ static smallint was_sig; /* obviously not thread-safe */ @@ -94,4 +162,5 @@ int sigwait (const sigset_t *set, int *sig) *sig = was_sig; return was_sig == -1 ? -1 : 0; } -#endif /* __UCLIBC_HAS_REALTIME__ */ +# endif /* __UCLIBC_HAS_REALTIME__ */ +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/stdio/_fopen.c b/libc/stdio/_fopen.c index 96377ee44..2db27a898 100644 --- a/libc/stdio/_fopen.c +++ b/libc/stdio/_fopen.c @@ -99,7 +99,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode, #ifdef __UCLIBC_HAS_THREADS__ /* We only initialize the mutex in the non-freopen case. */ /* stream->__user_locking = _stdio_user_locking; */ - __stdio_init_mutex(&stream->__lock); + STDIO_INIT_MUTEX(stream->__lock); #endif } @@ -197,7 +197,7 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode, #ifdef __UCLIBC_HAS_THREADS__ /* Even in the freopen case, we reset the user locking flag. */ stream->__user_locking = _stdio_user_locking; - /* __stdio_init_mutex(&stream->__lock); */ + /* STDIO_INIT_MUTEX(stream->__lock); */ #endif #ifdef __STDIO_HAS_OPENLIST diff --git a/libc/stdio/_scanf.c b/libc/stdio/_scanf.c index 914311877..34c1c9abd 100644 --- a/libc/stdio/_scanf.c +++ b/libc/stdio/_scanf.c @@ -235,7 +235,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap) #ifdef __UCLIBC_HAS_THREADS__ f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.__lock); + STDIO_INIT_MUTEX(f.__lock); #endif f.__nextopen = NULL; @@ -283,7 +283,7 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap) #ifdef __UCLIBC_HAS_THREADS__ f.f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.f.__lock); + STDIO_INIT_MUTEX(f.f.__lock); #endif f.f.__nextopen = NULL; @@ -388,8 +388,10 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format, { FILE f; - f.__bufstart = f.__bufpos = (unsigned char *) str; - f.__bufread = f.__bufend = (unsigned char *) (str + wcslen(str)); + f.__bufstart = + f.__bufpos = (char *) str; + f.__bufread = + f.__bufend = (char *)(str + wcslen(str)); __STDIO_STREAM_DISABLE_GETC(&f); __STDIO_STREAM_DISABLE_PUTC(&f); @@ -414,7 +416,7 @@ int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format, #ifdef __UCLIBC_HAS_THREADS__ f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.__lock); + STDIO_INIT_MUTEX(f.__lock); #endif f.__nextopen = NULL; diff --git a/libc/stdio/_stdio.c b/libc/stdio/_stdio.c index 3c8d667d2..6c11451fc 100644 --- a/libc/stdio/_stdio.c +++ b/libc/stdio/_stdio.c @@ -74,8 +74,13 @@ #endif #ifdef __UCLIBC_HAS_THREADS__ +#ifdef __USE_STDIO_FUTEXES__ +#define __STDIO_FILE_INIT_THREADSAFE \ + 2, _LIBC_LOCK_RECURSIVE_INITIALIZER, +#else #define __STDIO_FILE_INIT_THREADSAFE \ 2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +#endif #else #define __STDIO_FILE_INIT_THREADSAFE #endif @@ -152,14 +157,13 @@ FILE *__stdout = _stdio_streams + 1; /* For putchar() macro. */ FILE *_stdio_openlist = _stdio_streams; # ifdef __UCLIBC_HAS_THREADS__ -__UCLIBC_MUTEX_INIT(_stdio_openlist_add_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); -#ifdef __STDIO_BUFFERS -__UCLIBC_MUTEX_INIT(_stdio_openlist_del_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); +__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_add_lock); +# ifdef __STDIO_BUFFERS +__UCLIBC_IO_MUTEX_INIT(_stdio_openlist_del_lock); volatile int _stdio_openlist_use_count = 0; int _stdio_openlist_del_count = 0; -#endif +# endif # endif - #endif /**********************************************************************/ #ifdef __UCLIBC_HAS_THREADS__ @@ -167,6 +171,7 @@ int _stdio_openlist_del_count = 0; /* 2 if threading not initialized and 0 otherwise; */ int _stdio_user_locking = 2; +#ifndef __USE_STDIO_FUTEXES__ void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m) { const __UCLIBC_MUTEX_STATIC(__stdio_mutex_initializer, @@ -174,6 +179,7 @@ void attribute_hidden __stdio_init_mutex(__UCLIBC_MUTEX_TYPE *m) memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer)); } +#endif #endif /**********************************************************************/ @@ -189,10 +195,10 @@ void attribute_hidden _stdio_term(void) * locked, then I suppose there is a chance that a pointer in the * chain might be corrupt due to a partial store. */ - __stdio_init_mutex(&_stdio_openlist_add_lock); + STDIO_INIT_MUTEX(_stdio_openlist_add_lock); #warning check #ifdef __STDIO_BUFFERS - __stdio_init_mutex(&_stdio_openlist_del_lock); + STDIO_INIT_MUTEX(_stdio_openlist_del_lock); #endif /* Next we need to worry about the streams themselves. If a stream @@ -214,7 +220,7 @@ void attribute_hidden _stdio_term(void) } ptr->__user_locking = 1; /* Set locking mode to "by caller". */ - __stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */ + STDIO_INIT_MUTEX(ptr->__lock); /* Shouldn't be necessary, but... */ } #endif diff --git a/libc/stdio/_stdio.h b/libc/stdio/_stdio.h index aaa3ad656..ec98f9e0e 100644 --- a/libc/stdio/_stdio.h +++ b/libc/stdio/_stdio.h @@ -24,18 +24,18 @@ #include <bits/uClibc_mutex.h> #define __STDIO_THREADLOCK_OPENLIST_ADD \ - __UCLIBC_MUTEX_LOCK(_stdio_openlist_add_lock) + __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_add_lock) #define __STDIO_THREADUNLOCK_OPENLIST_ADD \ - __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_add_lock) + __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_add_lock) #ifdef __STDIO_BUFFERS #define __STDIO_THREADLOCK_OPENLIST_DEL \ - __UCLIBC_MUTEX_LOCK(_stdio_openlist_del_lock) + __UCLIBC_IO_MUTEX_LOCK(_stdio_openlist_del_lock) #define __STDIO_THREADUNLOCK_OPENLIST_DEL \ - __UCLIBC_MUTEX_UNLOCK(_stdio_openlist_del_lock) + __UCLIBC_IO_MUTEX_UNLOCK(_stdio_openlist_del_lock) #ifdef __UCLIBC_HAS_THREADS__ diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c index 8b918d6bb..d9104a42f 100644 --- a/libc/stdio/fflush.c +++ b/libc/stdio/fflush.c @@ -18,11 +18,11 @@ * when all (lbf) writing streams are flushed. */ #define __MY_STDIO_THREADLOCK(__stream) \ - __UCLIBC_MUTEX_CONDITIONAL_LOCK((__stream)->__lock, \ + __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock, \ (_stdio_user_locking != 2)) #define __MY_STDIO_THREADUNLOCK(__stream) \ - __UCLIBC_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock, \ + __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock, \ (_stdio_user_locking != 2)) #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) diff --git a/libc/stdio/tempnam.c b/libc/stdio/tempnam.c index faf7c5ecb..66c905db8 100644 --- a/libc/stdio/tempnam.c +++ b/libc/stdio/tempnam.c @@ -36,7 +36,7 @@ tempnam (const char *dir, const char *pfx) if (__path_search (buf, FILENAME_MAX, dir, pfx, 1)) return NULL; - if (__gen_tempname (buf, __GT_NOCREATE)) + if (__gen_tempname (buf, __GT_NOCREATE, 0)) return NULL; return strdup (buf); diff --git a/libc/stdio/tmpfile.c b/libc/stdio/tmpfile.c index 2f973c329..c6b2dc8a9 100644 --- a/libc/stdio/tmpfile.c +++ b/libc/stdio/tmpfile.c @@ -18,8 +18,10 @@ #include <features.h> #include <stdio.h> +#include <sys/stat.h> #include <unistd.h> #include "../misc/internals/tempname.h" +#include <not-cancel.h> /* This returns a new stream opened on a temporary file (generated @@ -34,7 +36,7 @@ FILE * tmpfile (void) if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0)) return NULL; - fd = __gen_tempname (buf, __GT_FILE); + fd = __gen_tempname (buf, __GT_FILE, S_IRUSR | S_IWUSR); if (fd < 0) return NULL; @@ -43,7 +45,7 @@ FILE * tmpfile (void) (void) remove (buf); if ((f = fdopen (fd, "w+b")) == NULL) - close (fd); + close_not_cancel (fd); return f; } diff --git a/libc/stdio/tmpnam.c b/libc/stdio/tmpnam.c index 1f180e08a..323105ba4 100644 --- a/libc/stdio/tmpnam.c +++ b/libc/stdio/tmpnam.c @@ -41,7 +41,7 @@ tmpnam (char *s) 0)) return NULL; - if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE), 0)) + if (__builtin_expect (__gen_tempname (tmpbuf, __GT_NOCREATE, 0), 0)) return NULL; if (s == NULL) diff --git a/libc/stdio/tmpnam_r.c b/libc/stdio/tmpnam_r.c index eec589e39..8f616b273 100644 --- a/libc/stdio/tmpnam_r.c +++ b/libc/stdio/tmpnam_r.c @@ -28,7 +28,7 @@ char * tmpnam_r (char *s) if (__path_search (s, L_tmpnam, NULL, NULL, 0)) return NULL; - if (__gen_tempname (s, __GT_NOCREATE)) + if (__gen_tempname (s, __GT_NOCREATE, 0)) return NULL; return s; diff --git a/libc/stdio/vdprintf.c b/libc/stdio/vdprintf.c index e3405e411..457018bcf 100644 --- a/libc/stdio/vdprintf.c +++ b/libc/stdio/vdprintf.c @@ -49,7 +49,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg) * only because of fflush_unlocked. TODO? */ #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__) f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.__lock); + STDIO_INIT_MUTEX(f.__lock); #endif f.__nextopen = NULL; diff --git a/libc/stdio/vsnprintf.c b/libc/stdio/vsnprintf.c index 07cff3410..31adc52b6 100644 --- a/libc/stdio/vsnprintf.c +++ b/libc/stdio/vsnprintf.c @@ -43,7 +43,7 @@ int vsnprintf(char *__restrict buf, size_t size, #if (defined(__STDIO_BUFFERS) || defined(__USE_OLD_VFPRINTF__)) && defined(__UCLIBC_HAS_THREADS__) f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.__lock); + STDIO_INIT_MUTEX(f.__lock); #endif f.__nextopen = NULL; @@ -117,7 +117,7 @@ int vsnprintf(char *__restrict buf, size_t size, #ifdef __UCLIBC_HAS_THREADS__ f.f.__user_locking = 1; /* Set user locking. */ - __stdio_init_mutex(&f.f.__lock); + STDIO_INIT_MUTEX(f.f.__lock); #endif f.f.__nextopen = NULL; diff --git a/libc/stdlib/Makefile.in b/libc/stdlib/Makefile.in index 48ee5f227..af8be6451 100644 --- a/libc/stdlib/Makefile.in +++ b/libc/stdlib/Makefile.in @@ -13,7 +13,7 @@ include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in CSRC := \ abort.c getenv.c mkdtemp.c realpath.c mkstemp.c \ - rand.c random.c random_r.c setenv.c system.c div.c ldiv.c lldiv.c \ + rand.c random.c random_r.c setenv.c div.c ldiv.c lldiv.c \ getpt.c drand48-iter.c jrand48.c \ jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \ nrand48_r.c rand_r.c srand48.c srand48_r.c seed48.c seed48_r.c \ @@ -40,7 +40,6 @@ ifeq ($(UCLIBC_SUSV3_LEGACY),y) CSRC += mktemp.c endif - # multi source stdlib.c CSRC += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \ qsort.c bsearch.c \ @@ -92,7 +91,9 @@ STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC)) STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC)) libc-y += $(STDLIB_OBJ) -libc-static-y += $(STDLIB_OUT)/atexit.o +libc-static-y += $(STDLIB_OUT)/atexit.o $(STDLIB_OUT)/system.o +libc-shared-y += $(STDLIB_OUT)/system.oS + # this should always be the PIC version, because it could be used in shared libs libc-nonshared-y += $(STDLIB_OUT)/atexit.os diff --git a/libc/stdlib/mkdtemp.c b/libc/stdlib/mkdtemp.c index fa9ae3b05..2bf15ae06 100644 --- a/libc/stdlib/mkdtemp.c +++ b/libc/stdlib/mkdtemp.c @@ -19,6 +19,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" #ifdef __USE_BSD @@ -29,7 +30,7 @@ (This function comes from OpenBSD.) */ char * mkdtemp (char *template) { - if (__gen_tempname (template, __GT_DIR)) + if (__gen_tempname (template, __GT_DIR, S_IRUSR | S_IWUSR | S_IXUSR)) return NULL; else return template; diff --git a/libc/stdlib/mkstemp.c b/libc/stdlib/mkstemp.c index c569ceaf5..ce7d7dba0 100644 --- a/libc/stdlib/mkstemp.c +++ b/libc/stdlib/mkstemp.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@ Then open the file and return a fd. */ int mkstemp (char *template) { - return __gen_tempname (template, __GT_FILE); + return __gen_tempname (template, __GT_FILE, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mkstemp64.c b/libc/stdlib/mkstemp64.c index 02a03f00e..2cdee70a2 100644 --- a/libc/stdlib/mkstemp64.c +++ b/libc/stdlib/mkstemp64.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@ Then open the file and return a fd. */ int mkstemp64 (char *template) { - return __gen_tempname (template, __GT_BIGFILE); + return __gen_tempname (template, __GT_BIGFILE, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mktemp.c b/libc/stdlib/mktemp.c index f3af1c15c..3c922e328 100644 --- a/libc/stdlib/mktemp.c +++ b/libc/stdlib/mktemp.c @@ -25,7 +25,7 @@ * they are replaced with a string that makes the filename unique. */ char *mktemp(char *template) { - if (__gen_tempname (template, __GT_NOCREATE) < 0) + if (__gen_tempname (template, __GT_NOCREATE, 0) < 0) /* We return the null string if we can't find a unique file name. */ template[0] = '\0'; diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index 99f7970c8..7026a8d20 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -10,8 +10,15 @@ #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sched.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include <sysdep-cancel.h> +#endif +#if !defined __UCLIBC_HAS_THREADS_NATIVE__ /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ #include <sys/syscall.h> #ifndef __NR_vfork @@ -61,4 +68,198 @@ int __libc_system(const char *command) signal(SIGCHLD, save_chld); return wait_val; } +#else +/* We have to and actually can handle cancelable system(). The big + problem: we have to kill the child process if necessary. To do + this a cleanup handler has to be registered and is has to be able + to find the PID of the child. The main problem is to reliable have + the PID when needed. It is not necessary for the parent thread to + return. It might still be in the kernel when the cancellation + request comes. Therefore we have to use the clone() calls ability + to have the kernel write the PID into the user-level variable. */ + +libc_hidden_proto(sigaction) +libc_hidden_proto(waitpid) + +#if defined __ia64__ +# define FORK() \ + INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ + &pid, NULL, NULL) +#elif defined __sparc__ +# define FORK() \ + INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +#elif defined __s390__ +# define FORK() \ + INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +#else +# define FORK() \ + INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +#endif + +static void cancel_handler (void *arg); + +# define CLEANUP_HANDLER \ + __libc_cleanup_region_start (1, cancel_handler, &pid) + +# define CLEANUP_RESET \ + __libc_cleanup_region_end (0) + +static struct sigaction intr, quit; +static int sa_refcntr; +__libc_lock_define_initialized (static, lock); + +# define DO_LOCK() __libc_lock_lock (lock) +# define DO_UNLOCK() __libc_lock_unlock (lock) +# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; }) +# define ADD_REF() sa_refcntr++ +# define SUB_REF() --sa_refcntr + +/* Execute LINE as a shell command, returning its status. */ +static int +do_system (const char *line) +{ + int status, save; + pid_t pid; + struct sigaction sa; + sigset_t omask; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + __sigemptyset (&sa.sa_mask); + + DO_LOCK (); + if (ADD_REF () == 0) + { + if (sigaction (SIGINT, &sa, &intr) < 0) + { + SUB_REF (); + goto out; + } + if (sigaction (SIGQUIT, &sa, &quit) < 0) + { + save = errno; + SUB_REF (); + goto out_restore_sigint; + } + } + DO_UNLOCK (); + + /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); + save = errno; + if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) + { + { + DO_LOCK (); + if (SUB_REF () == 0) + { + save = errno; + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + out_restore_sigint: + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + __set_errno (save); + } + out: + DO_UNLOCK (); + return -1; + } + } + + CLEANUP_HANDLER; + + pid = FORK (); + if (pid == (pid_t) 0) + { + /* Child side. */ + const char *new_argv[4]; + new_argv[0] = "/bin/sh"; + new_argv[1] = "-c"; + new_argv[2] = line; + new_argv[3] = NULL; + + /* Restore the signals. */ + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); + INIT_LOCK (); + + /* Exec the shell. */ + (void) execve ("/bin/sh", (char *const *) new_argv, __environ); + _exit (127); + } + else if (pid < (pid_t) 0) + /* The fork failed. */ + status = -1; + else + /* Parent side. */ + { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + status = -1; + } + + CLEANUP_RESET; + + save = errno; + DO_LOCK (); + if ((SUB_REF () == 0 + && (sigaction (SIGINT, &intr, (struct sigaction *) NULL) + | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) + || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) + { + status = -1; + } + DO_UNLOCK (); + + return status; +} + + +int +__libc_system (const char *line) +{ + if (line == NULL) + /* Check that we have a command processor available. It might + not be available after a chroot(), for example. */ + return do_system ("exit 0") == 0; + + if (SINGLE_THREAD_P) + return do_system (line); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_system (line); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} + + +/* The cancellation handler. */ +static void +cancel_handler (void *arg) +{ + pid_t child = *(pid_t *) arg; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); + + TEMP_FAILURE_RETRY (waitpid (child, NULL, 0)); + + DO_LOCK (); + + if (SUB_REF () == 0) + { + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + } + + DO_UNLOCK (); +} +#endif +#ifdef IS_IN_libc weak_alias(__libc_system,system) +#endif diff --git a/libc/string/Makefile.in b/libc/string/Makefile.in index 08a1856b7..67679ece7 100644 --- a/libc/string/Makefile.in +++ b/libc/string/Makefile.in @@ -18,7 +18,10 @@ STRING_SUBARCH_OUT := $(top_builddir)libc/string/$(TARGET_ARCH)/$(TARGET_SUBARCH STRING_SUBARCH_SSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.S) STRING_SUBARCH_SOBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.S,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_SSRC)) -STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ) +STRING_SUBARCH_CSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.c) +STRING_SUBARCH_COBJ := $(patsubst $(STRING_SUBARCH_DIR)/%.c,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_CSRC)) + +STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ) $(STRING_SUBARCH_COBJ) endif # Collect the arch specific implementation (asm, c files) diff --git a/libc/string/sh/memchr.S b/libc/string/sh/memchr.S new file mode 100644 index 000000000..6b7142f69 --- /dev/null +++ b/libc/string/sh/memchr.S @@ -0,0 +1,30 @@ +/* $Id: memchr.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ + * + * "memchr" implementation of SuperH + * + * Copyright (C) 1999 Niibe Yutaka + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + * void *memchr(const void *s, int c, size_t n); + */ + +#include <sysdep.h> + +ENTRY(memchr) + tst r6,r6 + bt/s 2f + exts.b r5,r5 +1: mov.b @r4,r1 + cmp/eq r1,r5 + bt/s 3f + dt r6 + bf/s 1b + add #1,r4 +2: mov #0,r4 +3: rts + mov r4,r0 +END(memchr) +libc_hidden_def (memchr) diff --git a/libc/string/sh/sh4/memcpy.S b/libc/string/sh/sh4/memcpy.S index 0954bce85..efdaf8bba 100644 --- a/libc/string/sh/sh4/memcpy.S +++ b/libc/string/sh/sh4/memcpy.S @@ -6,6 +6,9 @@ * Modified from memcpy.S and micro-optimised for SH4 * Stuart Menefy (stuart.menefy@st.com) * + * Copyright (c) 2009 STMicroelectronics Ltd + * Optimised using prefetching and 64bit data transfer via FPU + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> */ /* @@ -15,8 +18,25 @@ * If there is an overlap, then the results are undefined. */ +#include <sysdep.h> #include <endian.h> +#ifdef __LITTLE_ENDIAN__ +#define MEMCPY_USES_FPU +/* Use paired single precision load or store mode for 64-bit tranfering. + * FPSCR.SZ=1,FPSCR.SZ=0 is well defined on both SH4-200 and SH4-300. + * Currenlty it has been only implemented and tested for little endian mode. */ +.macro FPU_SET_PAIRED_PREC + sts fpscr, r7 + mov #0x10, r6 ! PR=0 SZ=1 + shll16 r6 + lds r6, fpscr +.endm +.macro RESTORE_FPSCR + lds r7, fpscr +.endm +#endif + ! ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. ! @@ -157,12 +177,7 @@ 9: rts nop -/* void * memcpy(void *dst, const void *src, size_t len) */ -.text -.align 4 -.type memcpy,@function -.globl memcpy; -memcpy: +ENTRY(memcpy) ! Calculate the invariants which will be used in the remainder ! of the code: @@ -189,9 +204,7 @@ memcpy: mov r4, r0 ! 5 MT (0 cycle latency) add r6, r0 ! 49 EX - mov #16, r1 ! 6 EX bt/s .Lcase00 ! 111 BR (aligned) - sub r4, r5 ! 75 EX ! Arguments are not nicely long word aligned or zero len. @@ -207,6 +220,7 @@ memcpy: ! However the penalty for getting it 'wrong' is much higher for long word ! aligned data (and this is more common), so use a value of 16. + mov #16, r1 ! 6 EX cmp/gt r6,r1 ! 56 MT add #-1,r5 ! 50 EX @@ -447,6 +461,92 @@ memcpy: mov.l r7, @-r0 ! 30 LS +#ifdef MEMCPY_USES_FPU + ! Copy the cache line aligned blocks by using the FPU registers. + ! If src and dst are well aligned adopt 64-bit data transfer. + ! We also need r0 as a temporary (for movca), so 'undo' the invariant: + ! r5: src (was r0+r5) + ! r1: dest (was r0) +1: + add r0, r5 + mov r0, r1 + + add #-0x1c, r5 + mov r5, r0 + + tst #7, r0 ! src is 8byte aligned + mov r5, r3 + + add #-64, r3 ! To pefetch head + bt/s 3f + + pref @r3 + +2: fmov.s @r5+, fr0 + mov r1, r6 + fmov.s @r5+, fr1 + add #-32, r6 + fmov.s @r5+, fr2 + fmov.s @r5+, fr3 + fmov.s @r5+, fr4 + fmov.s @r5+, fr5 + fmov.s @r5+, fr6 + fmov.s @r5+, fr7 + add #-0x40, r5 + + movca.l r0, @r6 ! Cache allocate + store on dst-32. + + fmov.s fr7, @-r1 + fmov.s fr6, @-r1 + fmov.s fr5, @-r1 + fmov.s fr4, @-r1 + fmov.s fr3, @-r1 + fmov.s fr2, @-r1 + fmov.s fr1, @-r1 + fmov.s fr0, @-r1 + + add #-32, r3 + cmp/eq r2,r1 + + bf/s 2b + pref @r3 ! Prefetch the next cache line. + + bra 5f + +3: FPU_SET_PAIRED_PREC + +4: fmov @r5+, dr0 + mov r1, r6 + fmov @r5+, dr2 + add #-32, r6 + fmov @r5+, dr4 + fmov @r5+, dr6 + add #-0x40, r5 + + movca.l r0, @r6 + + fmov dr6, @-r1 + fmov dr4, @-r1 + fmov dr2, @-r1 + fmov dr0, @-r1 + add #-32, r3 + cmp/eq r2,r1 + + bf/s 4b + pref @r3 + + RESTORE_FPSCR + +5: mov r1, r0 + + cmp/eq r4, r0 ! 54 MT + bf/s 1f ! 109 BR + sub r1, r5 ! 75 EX + + rts + nop +1: +#else ! Copy the cache line aligned blocks ! ! In use: r0, r2, r4, r5 @@ -512,6 +612,7 @@ memcpy: rts 1: mov.l @r15+, r8 ! 15 LS +#endif sub r4, r1 ! 75 EX (len remaining) ! number of trailing bytes is non-zero @@ -803,6 +904,5 @@ memcpy: rts mov.b r1,@-r0 -.size memcpy,.-memcpy; - +END(memcpy) libc_hidden_def (memcpy) diff --git a/libc/string/sh/sh4/memmove.c b/libc/string/sh/sh4/memmove.c new file mode 100644 index 000000000..4d52db2ca --- /dev/null +++ b/libc/string/sh/sh4/memmove.c @@ -0,0 +1,117 @@ +/* memmove implementation for SH4 + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <string.h> + + +#define FPSCR_SR (1 << 20) +#define STORE_FPSCR(x) __asm__ volatile("sts fpscr, %0" : "=r"(x)) +#define LOAD_FPSCR(x) __asm__ volatile("lds %0, fpscr" : : "r"(x)) + +static void fpu_optimised_copy_fwd(void *dest, const void *src, size_t len) +{ + char *d = (char *)dest; + char *s = (char *)src; + + if (len >= 64) { + unsigned long fpscr; + int *s1; + int *d1; + + /* Align the dest to 4 byte boundary. */ + while ((unsigned)d & 0x7) { + *d++ = *s++; + len--; + } + + s1 = (int *)s; + d1 = (int *)d; + + /* check if s is well aligned to use FPU */ + if (!((unsigned)s1 & 0x7)) { + + /* Align the dest to cache-line boundary */ + while ((unsigned)d1 & 0x1c) { + *d1++ = *s1++; + len -= 4; + } + + /* Use paired single precision load or store mode for + * 64-bit tranfering.*/ + STORE_FPSCR(fpscr); + LOAD_FPSCR(FPSCR_SR); + + while (len >= 32) { + __asm__ volatile ("fmov @%0+,dr0":"+r" (s1)); + __asm__ volatile ("fmov @%0+,dr2":"+r" (s1)); + __asm__ volatile ("fmov @%0+,dr4":"+r" (s1)); + __asm__ volatile ("fmov @%0+,dr6":"+r" (s1)); + __asm__ + volatile ("fmov dr0,@%0"::"r" + (d1):"memory"); + d1 += 2; + __asm__ + volatile ("fmov dr2,@%0"::"r" + (d1):"memory"); + d1 += 2; + __asm__ + volatile ("fmov dr4,@%0"::"r" + (d1):"memory"); + d1 += 2; + __asm__ + volatile ("fmov dr6,@%0"::"r" + (d1):"memory"); + d1 += 2; + len -= 32; + } + LOAD_FPSCR(fpscr); + } + s = (char *)s1; + d = (char *)d1; + /*TODO: other subcases could be covered here?!?*/ + } + /* Go to per-byte copy */ + while (len > 0) { + *d++ = *s++; + len--; + } + return; +} + +void *memmove(void *dest, const void *src, size_t len) +{ + unsigned long int d = (long int)dest; + unsigned long int s = (long int)src; + unsigned long int res; + + if (d >= s) + res = d - s; + else + res = s - d; + /* + * 1) dest and src are not overlap ==> memcpy (BWD/FDW) + * 2) dest and src are 100% overlap ==> memcpy (BWD/FDW) + * 3) left-to-right overlap ==> Copy from the beginning to the end + * 4) right-to-left overlap ==> Copy from the end to the beginning + */ + + if (res == 0) /* 100% overlap */ + memcpy(dest, src, len); /* No overlap */ + else if (res >= len) + memcpy(dest, src, len); + else { + if (d > s) /* right-to-left overlap */ + memcpy(dest, src, len); /* memcpy is BWD */ + else /* cannot use SH4 memcpy for this case */ + fpu_optimised_copy_fwd(dest, src, len); + } + return (dest); +} + +libc_hidden_def(memmove) diff --git a/libc/string/sh/sh4/memset.S b/libc/string/sh/sh4/memset.S new file mode 100644 index 000000000..1a57cb969 --- /dev/null +++ b/libc/string/sh/sh4/memset.S @@ -0,0 +1,146 @@ +/* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ + * + * "memset" implementation of SuperH + * + * Copyright (C) 1999 Niibe Yutaka + * + * Copyright (c) 2009 STMicroelectronics Ltd + * Optimised using 64bit data transfer via FPU + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + * void *memset(void *s, int c, size_t n); + */ + +#include <sysdep.h> + +#ifdef __LITTLE_ENDIAN__ +#define MEMSET_USES_FPU +/* Use paired single precision load or store mode for 64-bit tranfering. + * FPSCR.SZ=1,FPSCR.SZ=0 is well defined on both SH4-200 and SH4-300. + * Currenlty it has been only implemented and tested for little endian mode. */ +.macro FPU_SET_PAIRED_PREC + sts fpscr, r3 + mov #0x10, r0 ! PR=0 SZ=1 + shll16 r0 + lds r0, fpscr +.endm +.macro RESTORE_FPSCR + lds r3, fpscr +.endm +#endif + +ENTRY(memset) + tst r6,r6 + bt/s 5f ! if n=0, do nothing + add r6,r4 + mov #12,r0 + cmp/gt r6,r0 + bt/s 4f ! if it's too small, set a byte at once + mov r4,r0 + and #3,r0 + cmp/eq #0,r0 + bt/s 2f ! It's aligned + sub r0,r6 +1: + dt r0 + bf/s 1b + mov.b r5,@-r4 +2: ! make VVVV + extu.b r5,r5 + swap.b r5,r0 ! V0 + or r0,r5 ! VV + swap.w r5,r0 ! VV00 + or r0,r5 ! VVVV + + ! Enough bytes need to be copied + mov #0x40, r0 ! (MT) + cmp/gt r6,r0 ! (MT) 64 > len => slow loop + + bt/s 22f + mov r6,r0 + + ! align the dst to the cache block size if necessary + mov r4, r3 + mov #~(0x1f), r1 + + and r3, r1 + cmp/eq r3, r1 + + bt/s 11f ! dst is already aligned + sub r1, r3 ! r3-r1 -> r3 + shlr2 r3 ! number of loops + +10: mov.l r5,@-r4 + dt r3 + bf/s 10b + add #-4, r6 + +11: ! dst is 32byte aligned + mov r6,r2 + mov #-5,r0 + shld r0,r2 ! number of loops + +#ifdef MEMSET_USES_FPU + lds r5, fpul ! (CO) + fsts fpul, fr0 ! Dr0 will be 'VVVVVVVV' + fsts fpul, fr1 + + FPU_SET_PAIRED_PREC +12: + add #-0x20, r6 !(MT) + fmov dr0, @-r4 + fmov dr0, @-r4 + fmov dr0, @-r4 + dt r2 + bf/s 12b !(BR) + fmov dr0, @-r4 + + RESTORE_FPSCR +#else +12: + mov.l r5,@-r4 + mov.l r5,@-r4 + mov.l r5,@-r4 + mov.l r5,@-r4 + mov.l r5,@-r4 + mov.l r5,@-r4 + add #-0x20, r6 + mov.l r5,@-r4 + dt r2 + bf/s 12b + mov.l r5,@-r4 +#endif + tst r6,r6 + bt/s 5f + mov #8, r0 + + cmp/ge r0, r6 + bf/s 4f + mov r6,r0 +22: + shlr2 r0 + shlr r0 ! r0 = r6 >> 3 +3: + dt r0 + mov.l r5,@-r4 ! set 8-byte at once + bf/s 3b + mov.l r5,@-r4 + ! + mov #7,r0 + and r0,r6 + tst r6,r6 + bt 5f + ! fill bytes +4: + dt r6 + bf/s 4b + mov.b r5,@-r4 +5: + rts + mov r4,r0 +END(memset) +libc_hidden_def (memset) diff --git a/libc/string/sh/sh4/strcpy.S b/libc/string/sh/sh4/strcpy.S new file mode 100644 index 000000000..0f8278017 --- /dev/null +++ b/libc/string/sh/sh4/strcpy.S @@ -0,0 +1,28 @@ +/* strcpy implementation for SUPERH + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + char *strcpy(char *dest, const char *src); + */ + +#include <sysdep.h> + +ENTRY(strcpy) + mov r4,r2 +1: + mov.b @r5+,r1 + tst r1,r1 + mov.b r1,@r2 + bf/s 1b + add #1,r2 + + rts + mov r4,r0 +END(strcpy) +libc_hidden_def (strcpy) diff --git a/libc/string/sh/sh4/strncpy.S b/libc/string/sh/sh4/strncpy.S new file mode 100644 index 000000000..8a16f39d4 --- /dev/null +++ b/libc/string/sh/sh4/strncpy.S @@ -0,0 +1,43 @@ +/* strncpy implementation for SUPERH + * + * Copyright (C) 2009 STMicroelectronics Ltd. + * + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + char *strncpy(char *dest, const char *src, size_t n); + */ + +#include <sysdep.h> + +ENTRY(strncpy) + mov #0,r0 + bra 2f + mov r4,r2 +1: + mov.b r1,@(r0,r2) + add #1,r0 +2: + cmp/hs r6,r0 + bt 5f + mov.b @(r0,r5),r1 + tst r1,r1 + bf/s 1b + cmp/hs r6,r0 + bra 4f + nop +3: + mov.b r1,@(r0,r2) + add #1,r0 + cmp/hs r6,r0 +4: + bf/s 3b + mov #0,r1 +5: + rts + mov r2,r0 +END(strncpy) +libc_hidden_def(strncpy) diff --git a/libc/string/sh/strlen.S b/libc/string/sh/strlen.S new file mode 100644 index 000000000..1ccecc17b --- /dev/null +++ b/libc/string/sh/strlen.S @@ -0,0 +1,75 @@ +/* $Id: strlen.S,v 1.2 2001/06/29 14:07:15 gniibe Exp $ + * + * "strlen" implementation of SuperH + * + * Copyright (C) 1999 Kaz Kojima + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* size_t strlen (const char *s) */ + +#include <sysdep.h> +#include <endian.h> + +ENTRY(strlen) + mov r4,r0 + and #3,r0 + tst r0,r0 + bt/s 1f + mov #0,r2 + + add #-1,r0 + shll2 r0 + shll r0 + braf r0 + nop + + mov.b @r4+,r1 + tst r1,r1 + bt 8f + add #1,r2 + + mov.b @r4+,r1 + tst r1,r1 + bt 8f + add #1,r2 + + mov.b @r4+,r1 + tst r1,r1 + bt 8f + add #1,r2 + +1: + mov #0,r3 +2: + mov.l @r4+,r1 + cmp/str r3,r1 + bf/s 2b + add #4,r2 + + add #-4,r2 +#ifndef __LITTLE_ENDIAN__ + swap.b r1,r1 + swap.w r1,r1 + swap.b r1,r1 +#endif + extu.b r1,r0 + tst r0,r0 + bt/s 8f + shlr8 r1 + add #1,r2 + extu.b r1,r0 + tst r0,r0 + bt/s 8f + shlr8 r1 + add #1,r2 + extu.b r1,r0 + tst r0,r0 + bt 8f + add #1,r2 +8: + rts + mov r2,r0 +END(strlen) +libc_hidden_def (strlen) diff --git a/libc/sysdeps/linux/arm/Makefile.arch b/libc/sysdeps/linux/arm/Makefile.arch index c3c55258a..bec06ff44 100644 --- a/libc/sysdeps/linux/arm/Makefile.arch +++ b/libc/sysdeps/linux/arm/Makefile.arch @@ -5,14 +5,24 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC := brk.c ioperm.c iopl.c mmap.c sigaction.c __syscall_error.c +CSRC := brk.c ioperm.c iopl.c mmap.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif SSRC := \ - __longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S \ + __longjmp.S setjmp.S bsd-setjmp.S \ bsd-_setjmp.S sigrestorer.S mmap64.S +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += libc-aeabi_read_tp.S libc-thumb_atomics.S +else +SSRC += vfork.S clone.S +endif + ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) - CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c endif ifeq ($(CONFIG_ARM_EABI),y) diff --git a/libc/sysdeps/linux/arm/clone.S b/libc/sysdeps/linux/arm/clone.S index d9483735d..fdc05b88b 100644 --- a/libc/sysdeps/linux/arm/clone.S +++ b/libc/sysdeps/linux/arm/clone.S @@ -30,12 +30,12 @@ /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ .text -.global clone -.type clone,%function +.global __clone +.type __clone,%function .align 2 #if defined(THUMB1_ONLY) .thumb_func -clone: +__clone: @ sanity check args cmp r0, #0 beq __einval @@ -52,9 +52,15 @@ clone: @ get flags mov r0, r2 @ new sp is already in r1 + @ load remaining arguments off the stack + stmfd sp!, {r4} + ldr r2, [sp, #4] + ldr r3, [sp, #8] + ldr r4, [sp, #12] DO_CALL (clone) movs a1, a1 blt __error + ldmnefd sp!, {r4} beq 1f bx lr 1: @@ -80,7 +86,7 @@ __error: POP_RET .pool #else -clone: +__clone: @ sanity check args cmp r0, #0 IT(te, ne) @@ -98,9 +104,15 @@ clone: @ get flags mov r0, r2 @ new sp is already in r1 + @ load remaining arguments off the stack + stmfd sp!, {r4} + ldr r2, [sp, #4] + ldr r3, [sp, #8] + ldr r4, [sp, #12] DO_CALL (clone) movs a1, a1 blt __error + ldmnefd sp!, {r4} IT(t, ne) #if defined(__USE_BX__) bxne lr @@ -120,6 +132,7 @@ __error: b __syscall_error #endif -.size clone,.-clone +.size __clone,.-__clone +weak_alias(__clone, clone) #endif diff --git a/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S new file mode 100644 index 000000000..3aa135bf2 --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-aeabi_read_tp.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libc/sysdeps/linux/arm/libc-thumb_atomics.S b/libc/sysdeps/linux/arm/libc-thumb_atomics.S new file mode 100644 index 000000000..e7bc8950d --- /dev/null +++ b/libc/sysdeps/linux/arm/libc-thumb_atomics.S @@ -0,0 +1 @@ +#include <ldso/ldso/arm/thumb_atomics.S> diff --git a/libc/sysdeps/linux/arm/vfork.S b/libc/sysdeps/linux/arm/vfork.S index 42595b026..17d6a4db0 100644 --- a/libc/sysdeps/linux/arm/vfork.S +++ b/libc/sysdeps/linux/arm/vfork.S @@ -12,6 +12,15 @@ #include <bits/errno.h> #include <sys/syscall.h> +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + + #ifdef __NR_fork .text .global __vfork @@ -23,7 +32,9 @@ .thumb_func __vfork: #ifdef __NR_vfork + SAVE_PID DO_CALL (vfork) + RESTORE_PID ldr r1, =0xfffff000 cmp r0, r1 bcs 1f @@ -57,7 +68,9 @@ __error: __vfork: #ifdef __NR_vfork + SAVE_PID DO_CALL (vfork) + RESTORE_PID cmn r0, #4096 IT(t, cc) #if defined(__USE_BX__) diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index ec889ca0d..64c2432f5 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -34,6 +34,15 @@ CSRC := $(filter-out capget.c capset.c inotify.c ioperm.c iopl.c madvise.c \ sync_file_range.c sysctl.c sysinfo.c timerfd.c uselib.c vhangup.c,$(CSRC)) endif +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC := $(filter-out fork.c getpid.c raise.c open.c close.c read.c write.c, $(CSRC)) +ifneq ($(TARGET_ARCH),arm) +CSRC := $(filter-out waitpid.c, $(CSRC)) +else +CSRC := $(filter-out vfork.c, $(CSRC)) +endif +endif + ifneq ($(UCLIBC_BSD_SPECIFIC),y) # we need these internally: getdomainname.c CSRC := $(filter-out mincore.c setdomainname.c,$(CSRC)) @@ -75,6 +84,18 @@ ifneq ($(UCLIBC_SV4_DEPRECATED),y) CSRC := $(filter-out ustat.c,$(CSRC)) endif +ifeq ($(TARGET_ARCH),sh) +CSRC := $(filter-out longjmp.c vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),sparc) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif + # fails for some reason ifneq ($(strip $(ARCH_OBJS)),) CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)) $(ARCH_OBJ_FILTEROUT),$(CSRC)) diff --git a/libc/sysdeps/linux/common/__rt_sigtimedwait.c b/libc/sysdeps/linux/common/__rt_sigtimedwait.c index f9ec0eabf..554c6b9cb 100644 --- a/libc/sysdeps/linux/common/__rt_sigtimedwait.c +++ b/libc/sysdeps/linux/common/__rt_sigtimedwait.c @@ -2,44 +2,97 @@ /* * __rt_sigtimedwait() for uClibc * - * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> * - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * GNU Library General Public License (LGPL) version 2 or later. */ #include <sys/syscall.h> #include <signal.h> -#define __need_NULL -#include <stddef.h> +#include <string.h> +libc_hidden_proto(memcpy) #ifdef __NR_rt_sigtimedwait -#define __NR___rt_sigtimedwait __NR_rt_sigtimedwait -static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, siginfo_t *, info, - const struct timespec *, timeout, size_t, setsize) +#include <string.h> +libc_hidden_proto(memcpy) -int sigwaitinfo(const sigset_t * set, siginfo_t * info) +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include <sysdep-cancel.h> + +static int do_sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) { - return __rt_sigtimedwait(set, info, NULL, _NSIG / 8); +# ifdef SIGCANCEL + sigset_t tmpset; + + if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +# endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, + timeout, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; } -int sigtimedwait(const sigset_t * set, siginfo_t * info, - const struct timespec *timeout) +/* Return any pending signal or wait for one for the given time. */ +int __sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) { - return __rt_sigtimedwait(set, info, timeout, _NSIG / 8); + if(SINGLE_THREAD_P) + return do_sigtimedwait(set, info, timeout); + + int oldtype = LIBC_CANCEL_ASYNC(); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigtimedwait(set, info, timeout); + + LIBC_CANCEL_RESET(oldtype); + + return result; } -#else -int sigwaitinfo(const sigset_t * set, siginfo_t * info) +# else +# define __need_NULL +# include <stddef.h> +# define __NR___rt_sigtimedwait __NR_rt_sigtimedwait +static _syscall4(int, __rt_sigtimedwait, const sigset_t *, set, + siginfo_t *, info, const struct timespec *, timeout, + size_t, setsize); + +int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info, + const struct timespec *timeout) { - if (set == NULL) - __set_errno(EINVAL); - else - __set_errno(ENOSYS); - return -1; + return __rt_sigtimedwait(set, info, timeout, _NSIG / 8); } - -int sigtimedwait(const sigset_t * set, siginfo_t * info, - const struct timespec *timeout) +# endif /* !__UCLIBC_HAS_THREADS_NATIVE__ */ +#else +int attribute_hidden __sigtimedwait(const sigset_t * set, siginfo_t * info, + const struct timespec *timeout) { if (set == NULL) __set_errno(EINVAL); @@ -48,5 +101,4 @@ int sigtimedwait(const sigset_t * set, siginfo_t * info, return -1; } #endif -libc_hidden_def(sigwaitinfo) -libc_hidden_def(sigtimedwait) +weak_alias(__sigtimedwait,sigtimedwait) diff --git a/libc/sysdeps/linux/common/__rt_sigwaitinfo.c b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c new file mode 100644 index 000000000..c8953bfbc --- /dev/null +++ b/libc/sysdeps/linux/common/__rt_sigwaitinfo.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * __rt_sigwaitinfo() for uClibc + * + * Copyright (C) 2006 by Steven Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> + * + * GNU Library General Public License (LGPL) version 2 or later. + */ + +#include <sys/syscall.h> +#include <signal.h> +#include <string.h> + +libc_hidden_proto(memcpy) + +#ifdef __NR_rt_sigtimedwait + +#include <string.h> + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include <sysdep-cancel.h> + +static int do_sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ +# ifdef SIGCANCEL + sigset_t tmpset; + + if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +# endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, info, + NULL, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; +} + +/* Return any pending signal or wait for one for the given time. */ +int __sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ + if(SINGLE_THREAD_P) + return do_sigwaitinfo(set, info); + + int oldtype = LIBC_CANCEL_ASYNC(); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigwaitinfo(set, info); + + LIBC_CANCEL_RESET(oldtype); + + return result; +} +# else +# define __need_NULL +# include <stddef.h> +# define __NR___rt_sigwaitinfo __NR_rt_sigtimedwait +static _syscall4(int, __rt_sigwaitinfo, const sigset_t *, set, + siginfo_t *, info, const struct timespec *, timeout, + size_t, setsize); + +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ + return __rt_sigwaitinfo(set, info, NULL, _NSIG / 8); +} +# endif +#else +int attribute_hidden __sigwaitinfo(const sigset_t * set, siginfo_t * info) +{ + if (set == NULL) + __set_errno(EINVAL); + else + __set_errno(ENOSYS); + return -1; +} +#endif +libc_hidden_proto(sigwaitinfo) +weak_alias (__sigwaitinfo, sigwaitinfo) +libc_hidden_weak(sigwaitinfo) diff --git a/libc/sysdeps/linux/common/__syscall_fcntl.c b/libc/sysdeps/linux/common/__syscall_fcntl.c index 355b22b00..4e3bc23df 100644 --- a/libc/sysdeps/linux/common/__syscall_fcntl.c +++ b/libc/sysdeps/linux/common/__syscall_fcntl.c @@ -2,6 +2,7 @@ /* * __syscall_fcntl() for uClibc * + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com> * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -9,42 +10,83 @@ #include <sys/syscall.h> #include <stdarg.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> /* Must come before <fcntl.h>. */ +#endif #include <fcntl.h> #include <bits/wordsize.h> -#define __NR___syscall_fcntl __NR_fcntl -static __always_inline -_syscall3(int, __syscall_fcntl, int, fd, int, cmd, long, arg) +extern __typeof(fcntl) __libc_fcntl; +libc_hidden_proto(__libc_fcntl) -int fcntl(int fd, int cmd, ...) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +int __fcntl_nocancel (int fd, int cmd, ...) { - long arg; - va_list list; + va_list ap; + void *arg; - va_start(list, cmd); - arg = va_arg(list, long); - va_end(list); + va_start (ap, cmd); + arg = va_arg (ap, void *); + va_end (ap); -#if __WORDSIZE == 32 +# if __WORDSIZE == 32 if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) { -#if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 - return fcntl64(fd, cmd, arg); -#else +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 + return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else __set_errno(ENOSYS); return -1; -#endif +# endif } +# endif + return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +} #endif - return (__syscall_fcntl(fd, cmd, arg)); -} -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(fcntl) +int __libc_fcntl (int fd, int cmd, ...) +{ + va_list ap; + void *arg; + + va_start (ap, cmd); + arg = va_arg (ap, void *); + va_end (ap); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64)) +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 + return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else + return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +# endif + + int oldtype = LIBC_CANCEL_ASYNC (); + +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 + int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else + int result = INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); +# endif + + LIBC_CANCEL_RESET (oldtype); + + return result; #else -libc_hidden_weak(fcntl) -strong_alias(fcntl,__libc_fcntl) +# if __WORDSIZE == 32 + if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) { +# if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 + return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); +# else + __set_errno(ENOSYS); + return -1; +# endif + } +# endif + return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg); #endif +} +libc_hidden_def(__libc_fcntl) -#if ! defined __NR_fcntl64 && defined __UCLIBC_HAS_LFS__ -strong_alias(fcntl,fcntl64) -#endif +libc_hidden_proto(fcntl) +weak_alias(__libc_fcntl,fcntl) +libc_hidden_weak(fcntl) diff --git a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c index b4b007d02..006b38a2a 100644 --- a/libc/sysdeps/linux/common/__syscall_rt_sigaction.c +++ b/libc/sysdeps/linux/common/__syscall_rt_sigaction.c @@ -12,7 +12,9 @@ #ifdef __NR_rt_sigaction #include <signal.h> -int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, struct sigaction *__oldact, size_t __size) attribute_hidden; +int __syscall_rt_sigaction (int __signum, const struct sigaction *__act, + struct sigaction *__oldact, size_t __size); + #define __NR___syscall_rt_sigaction __NR_rt_sigaction _syscall4(int, __syscall_rt_sigaction, int, signum, const struct sigaction *, act, struct sigaction *, oldact, diff --git a/libc/sysdeps/linux/common/_exit.c b/libc/sysdeps/linux/common/_exit.c index 6cece0878..51117d109 100644 --- a/libc/sysdeps/linux/common/_exit.c +++ b/libc/sysdeps/linux/common/_exit.c @@ -12,13 +12,23 @@ #include <unistd.h> #include <sys/types.h> #include <sys/syscall.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep.h> +#endif void attribute_noreturn _exit(int status) { /* The loop is added only to keep gcc happy. */ while(1) + { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# ifdef __NR_exit_group + INLINE_SYSCALL(exit_group, 1, status); +# endif +#endif INLINE_SYSCALL(exit, 1, status); + } } libc_hidden_def(_exit) weak_alias(_exit,_Exit) diff --git a/libc/sysdeps/linux/common/bits/kernel-features.h b/libc/sysdeps/linux/common/bits/kernel-features.h index 88297349a..923341b35 100644 --- a/libc/sysdeps/linux/common/bits/kernel-features.h +++ b/libc/sysdeps/linux/common/bits/kernel-features.h @@ -26,23 +26,126 @@ #endif #include <linux/version.h> -#define __LINUX_KERNEL_VERSION LINUX_VERSION_CODE +#define __LINUX_KERNEL_VERSION LINUX_VERSION_CODE + +/* We assume for __LINUX_KERNEL_VERSION the same encoding used in + linux/version.h. I.e., the major, minor, and subminor all get a + byte with the major number being in the highest byte. This means + we can do numeric comparisons. + + In the following we will define certain symbols depending on + whether the describes kernel feature is available in the kernel + version given by __LINUX_KERNEL_VERSION. We are not always exactly + recording the correct versions in which the features were + introduced. If somebody cares these values can afterwards be + corrected. Most of the numbers here are set corresponding to + 2.2.0. */ + +/* `getcwd' system call. */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_GETCWD_SYSCALL 1 +#endif /* Real-time signal became usable in 2.1.70. */ #if __LINUX_KERNEL_VERSION >= 131398 # define __ASSUME_REALTIME_SIGNALS 1 #endif -/* Beginning with 2.5.63 support for realtime and monotonic clocks and - timers based on them is available. */ -#if __LINUX_KERNEL_VERSION >= 132415 -# define __ASSUME_POSIX_TIMERS 1 +/* When were the `pread'/`pwrite' syscalls introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_PREAD_SYSCALL 1 +# define __ASSUME_PWRITE_SYSCALL 1 #endif -/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its - semantics was changed in 2.5.30, and again after 2.5.31. */ -#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__ -# define __ASSUME_SET_THREAD_AREA_SYSCALL 1 +/* When was `poll' introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_POLL_SYSCALL 1 +#endif + +/* The `lchown' syscall was introduced in 2.1.80. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_LCHOWN_SYSCALL 1 +#endif + +/* When did the `setresuid' sysall became available? */ +#if __LINUX_KERNEL_VERSION >= 131584 && !defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +#endif + +/* The SIOCGIFNAME ioctl is available starting with 2.1.50. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_SIOCGIFNAME 1 +#endif + +/* MSG_NOSIGNAL was at least available with Linux 2.2.0. */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_MSG_NOSIGNAL 1 +#endif + +/* On x86 another `getrlimit' syscall was added in 2.3.25. */ +#if __LINUX_KERNEL_VERSION >= 131865 && defined __i386__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* On x86 the truncate64/ftruncate64 syscalls were introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +#endif + +/* On x86 the mmap2 syscall was introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* On x86 the stat64/lstat64/fstat64 syscalls were introduced in 2.3.34. */ +#if __LINUX_KERNEL_VERSION >= 131874 && defined __i386__ +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* On sparc and ARM the truncate64/ftruncate64/mmap2/stat64/lstat64/fstat64 + syscalls were introduced in 2.3.35. */ +#if __LINUX_KERNEL_VERSION >= 131875 && (defined __sparc__ || defined __arm__) +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* I know for sure that getrlimit are in 2.3.35 on powerpc. */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* I know for sure that these are in 2.3.35 on powerpc. But PowerPC64 does not + support separate 64-bit syscalls, already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ \ + && !defined __powerpc64__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* Linux 2.3.39 introduced 32bit UID/GIDs. Some platforms had 32 + bit type all along. */ +#if __LINUX_KERNEL_VERSION >= 131879 || defined __powerpc__ || defined __mips__ +# define __ASSUME_32BITUIDS 1 +#endif + +/* Linux 2.3.39 sparc added setresuid. */ +#if __LINUX_KERNEL_VERSION >= 131879 && defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +#endif + +#if __LINUX_KERNEL_VERSION >= 131879 +# define __ASSUME_SETRESGID_SYSCALL 1 +#endif + +/* Linux 2.3.39 introduced IPC64. Except for powerpc. */ +#if __LINUX_KERNEL_VERSION >= 131879 && !defined __powerpc__ +# define __ASSUME_IPC64 1 +#endif + +/* MIPS platforms had IPC64 all along. */ +#if defined __mips__ +# define __ASSUME_IPC64 1 #endif /* We can use the LDTs for threading with Linux 2.3.99 and newer. */ @@ -50,6 +153,74 @@ # define __ASSUME_LDT_WORKS 1 #endif +/* Linux 2.4.0 on PPC introduced a correct IPC64. But PowerPC64 does not + support a separate 64-bit sys call, already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __powerpc__ \ + && !defined __powerpc64__ +# define __ASSUME_IPC64 1 +#endif + +/* SH kernels got stat64, mmap2, and truncate64 during 2.4.0-test. */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __sh__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* The changed st_ino field appeared in 2.4.0-test6. But we cannot + distinguish this version from other 2.4.0 releases. Therefore play + save and assume it available is for 2.4.1 and up. However, SH is lame, + and still does not have a 64-bit inode field. */ +#if __LINUX_KERNEL_VERSION >= 132097 && !defined __alpha__ && !defined __sh__ +# define __ASSUME_ST_INO_64_BIT 1 +#endif + +/* To support locking of large files a new fcntl() syscall was introduced + in 2.4.0-test7. We test for 2.4.1 for the earliest version we know + the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__) +# define __ASSUME_FCNTL64 1 +#endif + +/* The AT_CLKTCK auxiliary vector entry was introduction in the 2.4.0 + series. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_CLKTCK 1 +#endif + +/* Arm got fcntl64 in 2.4.4, PowerPC and SH have it also in 2.4.4 (I + don't know when it got introduced). But PowerPC64 does not support + separate FCNTL64 call, FCNTL is already 64-bit */ +#if __LINUX_KERNEL_VERSION >= 132100 \ + && (defined __arm__ || defined __powerpc__ || defined __sh__) \ + && !defined __powerpc64__ +# define __ASSUME_FCNTL64 1 +#endif + +/* The getdents64 syscall was introduced in 2.4.0-test7. We test for + 2.4.1 for the earliest version we know the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif + +/* When did O_DIRECTORY became available? Early in 2.3 but when? + Be safe, use 2.3.99. */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_O_DIRECTORY 1 +#endif + +/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes + up the page size information. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_PAGESIZE 1 +#endif + +/* Starting with at least 2.4.0 the kernel passes the uid/gid unconditionally + up to the child. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_XID 1 +#endif + /* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way and the vfork syscall made it into the official kernel. */ #if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ @@ -57,17 +228,72 @@ # define __ASSUME_VFORK_SYSCALL 1 #endif +/* Starting with 2.4.5 kernels the mmap2 syscall made it into the official + kernel. But PowerPC64 does not support a separate MMAP2 call. */ +#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ \ + && !defined __powerpc64__ +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* Starting with 2.4.21 PowerPC implements the new prctl syscall. + This allows applications to get/set the Floating Point Exception Mode. */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__ +# define __ASSUME_NEW_PRCTL_SYSCALL 1 +#endif + +/* Starting with 2.4.21 the PowerPC32 clone syscall works as expected. */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc__ \ + && !defined __powerpc64__ +# define __ASSUME_FIXED_CLONE_SYSCALL 1 +#endif + +/* Starting with 2.4.21 PowerPC64 implements the new rt_sigreturn syscall. + The new rt_sigreturn takes an ucontext pointer allowing rt_sigreturn + to be used in the set/swapcontext implementation. */ +#if __LINUX_KERNEL_VERSION >= (132096+21) && defined __powerpc64__ +# define __ASSUME_NEW_RT_SIGRETURN_SYSCALL 1 +#endif + +/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its + semantics was changed in 2.5.30, and again after 2.5.31. */ +#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__ +# define __ASSUME_SET_THREAD_AREA_SYSCALL 1 +#endif + /* The vfork syscall on x86 and arm was definitely available in 2.4. */ #if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __arm__) # define __ASSUME_VFORK_SYSCALL 1 #endif -/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type - * information as well and in between 2.6.5 and 2.6.8 most compat wrappers - * were fixed too. Except s390{,x} which was fixed in 2.6.11. */ -#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \ - || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__) -# define __ASSUME_GETDENTS32_D_TYPE 1 +/* There are an infinite number of PA-RISC kernel versions numbered + 2.4.0. But they've not really been released as such. We require + and expect the final version here. */ +#ifdef __hppa__ +# define __ASSUME_32BITUIDS 1 +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +# define __ASSUME_IPC64 1 +# define __ASSUME_ST_INO_64_BIT 1 +# define __ASSUME_FCNTL64 1 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif + +/* Alpha switched to a 64-bit timeval sometime before 2.2.0. */ +#if __LINUX_KERNEL_VERSION >= 131584 && defined __alpha__ +# define __ASSUME_TIMEVAL64 1 +#endif + +#if defined __mips__ && _MIPS_SIM == _ABIN32 +# define __ASSUME_FCNTL64 1 +#endif + +/* The late 2.5 kernels saw a lot of new CLONE_* flags. Summarize + their availability with one define. The changes were made first + for i386 and the have to be done separately for the other archs. + For i386 we pick 2.5.50 as the first version with support. */ +#if __LINUX_KERNEL_VERSION >= 132402 && defined __i386__ +# define __ASSUME_CLONE_THREAD_FLAGS 1 #endif /* Support for various CLOEXEC and NONBLOCK flags was added for x86, @@ -87,6 +313,137 @@ # define __ASSUME_VFORK_SYSCALL 1 #endif +/* Beginning with 2.5.63 support for realtime and monotonic clocks and + timers based on them is available. */ +#if __LINUX_KERNEL_VERSION >= 132415 +# define __ASSUME_POSIX_TIMERS 1 +#endif + +/* The late 2.5 kernels saw a lot of new CLONE_* flags. Summarize + their availability with one define. The changes were made first + for i386 and the have to be done separately for the other archs. + For ia64, s390*, PPC, x86-64 we pick 2.5.64 as the first version + with support. */ +#if __LINUX_KERNEL_VERSION >= 132416 \ + && (defined __ia64__ || defined __s390__ || defined __powerpc__ \ + || defined __x86_64__ || defined __sh__) +# define __ASSUME_CLONE_THREAD_FLAGS 1 +#endif + +/* With kernel 2.4.17 we always have netlink support. */ +#if __LINUX_KERNEL_VERSION >= (132096+17) +# define __ASSUME_NETLINK_SUPPORT 1 +#endif + +/* The requeue futex functionality was introduced in 2.5.70. */ +#if __LINUX_KERNEL_VERSION >= 132422 +# define __ASSUME_FUTEX_REQUEUE 1 +#endif + +/* The statfs64 syscalls are available in 2.5.74. */ +#if __LINUX_KERNEL_VERSION >= 132426 +# define __ASSUME_STATFS64 1 +#endif + +/* Starting with at least 2.5.74 the kernel passes the setuid-like exec + flag unconditionally up to the child. */ +#if __LINUX_KERNEL_VERSION >= 132426 +# define __ASSUME_AT_SECURE 1 +#endif + +/* Starting with the 2.5.75 kernel the kernel fills in the correct value + in the si_pid field passed as part of the siginfo_t struct to signal + handlers. */ +#if __LINUX_KERNEL_VERSION >= 132427 +# define __ASSUME_CORRECT_SI_PID 1 +#endif + +/* The tgkill syscall was instroduced for i386 in 2.5.75. For Alpha + it was introduced in 2.6.0-test1 which unfortunately cannot be + distinguished from 2.6.0. On x86-64, ppc, and ppc64 it was + introduced in 2.6.0-test3. */ +#if (__LINUX_KERNEL_VERSION >= 132427 && defined __i386__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __alpha__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __x86_64__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__) +# define __ASSUME_TGKILL 1 +#endif + +/* The utimes syscall has been available for some architectures + forever. For x86 it was introduced after 2.5.75, for x86-64, + ppc, and ppc64 it was introduced in 2.6.0-test3. */ +#if defined __alpha__ || defined __ia64__ || defined __hppa__ \ + || defined __sparc__ \ + || (__LINUX_KERNEL_VERSION > 132427 && defined __i386__) \ + || (__LINUX_KERNEL_VERSION > 132609 && defined __x86_64__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __powerpc__) \ + || (__LINUX_KERNEL_VERSION >= 132609 && defined __sh__) +# define __ASSUME_UTIMES 1 +#endif + +// XXX Disabled for now since the semantics we want is not achieved. +#if 0 +/* The CLONE_STOPPED flag was introduced in the 2.6.0-test1 series. */ +#if __LINUX_KERNEL_VERSION >= 132609 +# define __ASSUME_CLONE_STOPPED 1 +#endif +#endif + +/* The fixed version of the posix_fadvise64 syscall appeared in + 2.6.0-test3. At least for x86. Powerpc support appeared in + 2.6.2, but for 32-bit userspace only. */ +#if (__LINUX_KERNEL_VERSION >= 132609 && defined __i386__) \ + || (__LINUX_KERNEL_VERSION >= 132610 && defined __powerpc__ \ + && !defined __powerpc64__) +# define __ASSUME_FADVISE64_64_SYSCALL 1 +#endif + +/* The PROT_GROWSDOWN/PROT_GROWSUP flags were introduced in the 2.6.0-test + series. */ +#if __LINUX_KERNEL_VERSION >= 132609 +# define __ASSUME_PROT_GROWSUPDOWN 1 +#endif + +/* Starting with 2.6.0 PowerPC adds signal/swapcontext support for Vector + SIMD (AKA Altivec, VMX) instructions and register state. This changes + the overall size of the sigcontext and adds the swapcontext syscall. */ +#if __LINUX_KERNEL_VERSION >= 132608 && defined __powerpc__ +# define __ASSUME_SWAPCONTEXT_SYSCALL 1 +#endif + +/* The CLONE_DETACHED flag is not necessary in 2.6.2 kernels, it is + implied. */ +#if __LINUX_KERNEL_VERSION >= 132610 +# define __ASSUME_NO_CLONE_DETACHED 1 +#endif + +/* Starting with version 2.6.4-rc1 the getdents syscall returns d_type + information as well and in between 2.6.5 and 2.6.8 most compat wrappers + were fixed too. Except s390{,x} which was fixed in 2.6.11. */ +#if (__LINUX_KERNEL_VERSION >= 0x020608 && !defined __s390__) \ + || (__LINUX_KERNEL_VERSION >= 0x02060b && defined __s390__) +# define __ASSUME_GETDENTS32_D_TYPE 1 +#endif + +/* Starting with version 2.5.3, the initial location returned by `brk' + after exec is always rounded up to the next page. */ +#if __LINUX_KERNEL_VERSION >= 132355 +# define __ASSUME_BRK_PAGE_ROUNDED 1 +#endif + +/* Starting with version 2.6.9, the waitid system call is available. + Except for powerpc and powerpc64, where it is available in 2.6.12. */ +#if (__LINUX_KERNEL_VERSION >= 0x020609 && !defined __powerpc__) \ + || (__LINUX_KERNEL_VERSION >= 0x02060c && defined __powerpc__) +# define __ASSUME_WAITID_SYSCALL 1 +#endif + +/* Starting with version 2.6.9, SSI_IEEE_RAISE_EXCEPTION exists. */ +#if __LINUX_KERNEL_VERSION >= 0x020609 && defined __alpha__ +#define __ASSUME_IEEE_RAISE_EXCEPTION 1 +#endif + /* This header was added somewhere around 2.6.13 */ #if __LINUX_KERNEL_VERSION >= 132621 # define HAVE_LINUX_CPUMASK_H 1 diff --git a/libc/sysdeps/linux/common/bits/kernel_sigaction.h b/libc/sysdeps/linux/common/bits/kernel_sigaction.h index f74e0a28a..0a35ac8cb 100644 --- a/libc/sysdeps/linux/common/bits/kernel_sigaction.h +++ b/libc/sysdeps/linux/common/bits/kernel_sigaction.h @@ -25,12 +25,12 @@ struct old_kernel_sigaction { */ extern int __syscall_sigaction(int, const struct old_kernel_sigaction *, - struct old_kernel_sigaction *) attribute_hidden; + struct old_kernel_sigaction *); #endif extern int __syscall_rt_sigaction(int, const struct sigaction *, - struct sigaction *, size_t) attribute_hidden; + struct sigaction *, size_t); #endif /* _BITS_SIGACTION_STRUCT_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_mutex.h b/libc/sysdeps/linux/common/bits/uClibc_mutex.h index 14aeb9c80..c6094c3d2 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_mutex.h +++ b/libc/sysdeps/linux/common/bits/uClibc_mutex.h @@ -62,7 +62,55 @@ #define __UCLIBC_MUTEX_UNLOCK(M) \ __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) -#else +#ifdef __USE_STDIO_FUTEXES__ + +#include <bits/stdio-lock.h> + +#define __UCLIBC_IO_MUTEX(M) _IO_lock_t M +#define __UCLIBC_IO_MUTEX_LOCK(M) _IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK(M) _IO_lock_unlock(M) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M) _IO_lock_trylock(M) +#define __UCLIBC_IO_MUTEX_INIT(M) _IO_lock_t M = _IO_lock_initializer +#define __UCLIBC_IO_MUTEX_EXTERN(M) extern _IO_lock_t M + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C) \ + if (C) { \ + _IO_lock_lock(M); \ + } + +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C) \ + if (C) { \ + _IO_lock_unlock(M); \ + } + +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V) \ + __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,((A=(V))) == 0) + +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A) \ + __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,((A) == 0)) + +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M) _IO_lock_lock(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M) _IO_lock_unlock(M) + +#else /* of __USE_STDIO_FUTEXES__ */ + +#define __UCLIBC_IO_MUTEX(M) __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M) __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M) __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M) __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M) __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M) __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V) __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A) __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M) __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M) __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C) __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C) __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __USE_STDIO_FUTEXES__ */ + + +#else /* of __UCLIBC_HAS_THREADS__ */ #define __UCLIBC_MUTEX(M) void *__UCLIBC_MUTEX_DUMMY_ ## M #define __UCLIBC_MUTEX_INIT(M,I) extern void *__UCLIBC_MUTEX_DUMMY_ ## M @@ -83,6 +131,22 @@ #define __UCLIBC_MUTEX_LOCK(M) ((void)0) #define __UCLIBC_MUTEX_UNLOCK(M) ((void)0) -#endif +#define __UCLIBC_IO_MUTEX(M) __UCLIBC_MUTEX(M) +#define __UCLIBC_IO_MUTEX_LOCK(M) __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_UNLOCK(M) __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) +#define __UCLIBC_IO_MUTEX_TRYLOCK(M) __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_INIT(M) __UCLIBC_MUTEX_INIT(M, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#define __UCLIBC_IO_MUTEX_EXTERN(M) __UCLIBC_MUTEX_EXTERN(M) +#define __UCLIBC_IO_MUTEX_AUTO_LOCK(M,A,V) __UCLIBC_MUTEX_AUTO_LOCK(M,A,V) +#define __UCLIBC_IO_MUTEX_AUTO_UNLOCK(M,A) __UCLIBC_MUTEX_AUTO_UNLOCK(M,A) +#define __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(M) __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(M) __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(M) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK(M,C) __UCLIBC_MUTEX_CONDITIONAL_LOCK(M, 1) +#define __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK(M,C) __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(M, 1) + +#endif /* of __UCLIBC_HAS_THREADS__ */ + +#define __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE(M) \ + __UCLIBC_IO_MUTEX_TRYLOCK(M) #endif /* _UCLIBC_MUTEX_H */ diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 3631ef79f..a8cf4eb56 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -134,26 +134,26 @@ __UCLIBC_MUTEX_AUTO_LOCK_VAR(__infunc_user_locking) #define __STDIO_AUTO_THREADLOCK(__stream) \ - __UCLIBC_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking, \ + __UCLIBC_IO_MUTEX_AUTO_LOCK((__stream)->__lock, __infunc_user_locking, \ (__stream)->__user_locking) #define __STDIO_AUTO_THREADUNLOCK(__stream) \ - __UCLIBC_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking) + __UCLIBC_IO_MUTEX_AUTO_UNLOCK((__stream)->__lock, __infunc_user_locking) #define __STDIO_ALWAYS_THREADLOCK(__stream) \ - __UCLIBC_MUTEX_LOCK((__stream)->__lock) + __UCLIBC_IO_MUTEX_LOCK((__stream)->__lock) #define __STDIO_ALWAYS_THREADUNLOCK(__stream) \ - __UCLIBC_MUTEX_UNLOCK((__stream)->__lock) + __UCLIBC_IO_MUTEX_UNLOCK((__stream)->__lock) #define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream) \ - __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock) + __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE((__stream)->__lock) #define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream) \ - __UCLIBC_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock) + __UCLIBC_IO_MUTEX_TRYLOCK_CANCEL_UNSAFE((__stream)->__lock) #define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream) \ - __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock) + __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE((__stream)->__lock) #ifdef __UCLIBC_HAS_THREADS__ #define __STDIO_SET_USER_LOCKING(__stream) ((__stream)->__user_locking = 1) @@ -161,6 +161,14 @@ #define __STDIO_SET_USER_LOCKING(__stream) ((void)0) #endif +#ifdef __UCLIBC_HAS_THREADS__ +#ifdef __USE_STDIO_FUTEXES__ +#define STDIO_INIT_MUTEX(M) _IO_lock_init(M) +#else +#define STDIO_INIT_MUTEX(M) __stdio_init_mutex(& M) +#endif +#endif + /**********************************************************************/ #define __STDIO_IOFBF 0 /* Fully buffered. */ @@ -275,7 +283,7 @@ struct __STDIO_FILE_STRUCT { #endif #ifdef __UCLIBC_HAS_THREADS__ int __user_locking; - __UCLIBC_MUTEX(__lock); + __UCLIBC_IO_MUTEX(__lock); #endif /* Everything after this is unimplemented... and may be trashed. */ #if __STDIO_BUILTIN_BUF_SIZE > 0 @@ -351,9 +359,9 @@ extern void _stdio_term(void) attribute_hidden; extern struct __STDIO_FILE_STRUCT *_stdio_openlist; #ifdef __UCLIBC_HAS_THREADS__ -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_add_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_add_lock); #ifdef __STDIO_BUFFERS -__UCLIBC_MUTEX_EXTERN(_stdio_openlist_del_lock); +__UCLIBC_IO_MUTEX_EXTERN(_stdio_openlist_del_lock); extern volatile int _stdio_openlist_use_count; /* _stdio_openlist_del_lock */ extern int _stdio_openlist_del_count; /* _stdio_openlist_del_lock */ #endif diff --git a/libc/sysdeps/linux/common/fsync.c b/libc/sysdeps/linux/common/fsync.c index 774efc9ce..711811f23 100644 --- a/libc/sysdeps/linux/common/fsync.c +++ b/libc/sysdeps/linux/common/fsync.c @@ -10,9 +10,28 @@ #include <sys/syscall.h> #include <unistd.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(fsync) weak_function fsync; -strong_alias(fsync,__libc_fsync) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include "sysdep-cancel.h" +#else +#define SINGLE_THREAD_P 1 #endif -_syscall1(int, fsync, int, fd) +#define __NR___syscall_fsync __NR_fsync +static inline _syscall1(int, __syscall_fsync, int, fd) + +extern __typeof(fsync) __libc_fsync; + +int __libc_fsync(int fd) +{ + if (SINGLE_THREAD_P) + return __syscall_fsync(fd); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_fsync(fd); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif +} + +weak_alias(__libc_fsync, fsync) diff --git a/libc/sysdeps/linux/common/ioctl.c b/libc/sysdeps/linux/common/ioctl.c index 7ac8f16c2..f2f0f539a 100644 --- a/libc/sysdeps/linux/common/ioctl.c +++ b/libc/sysdeps/linux/common/ioctl.c @@ -11,20 +11,36 @@ #include <stdarg.h> #include <sys/ioctl.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif + +libc_hidden_proto(ioctl) #define __NR___syscall_ioctl __NR_ioctl static __always_inline -_syscall3(int, __syscall_ioctl, int, fd, int, request, void *, arg) +_syscall3(int, __syscall_ioctl, int, fd, unsigned long int, request, void *, arg) int ioctl(int fd, unsigned long int request, ...) { - void *arg; - va_list list; + void *arg; + va_list list; + + va_start(list, request); + arg = va_arg(list, void *); + + va_end(list); - va_start(list, request); - arg = va_arg(list, void *); - va_end(list); + if (SINGLE_THREAD_P) + return __syscall_ioctl(fd, request, arg); - return __syscall_ioctl(fd, request, arg); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_ioctl(fd, request, arg); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } libc_hidden_def(ioctl) diff --git a/libc/sysdeps/linux/common/msync.c b/libc/sysdeps/linux/common/msync.c index 7a46f0c32..2629bd4aa 100644 --- a/libc/sysdeps/linux/common/msync.c +++ b/libc/sysdeps/linux/common/msync.c @@ -9,16 +9,33 @@ #include <sys/syscall.h> #include <unistd.h> +#include <sys/mman.h> -#if defined __NR_msync && defined __ARCH_USE_MMU__ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif -#include <sys/mman.h> +#define __NR___syscall_msync __NR_msync +static __always_inline _syscall3(int, __syscall_msync, void *, addr, size_t, length, + int, flags) -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(msync) weak_function msync; -strong_alias(msync,__libc_msync) +extern __typeof(msync) __libc_msync; +int __libc_msync(void * addr, size_t length, int flags) +{ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype, result; #endif -_syscall3(int, msync, void *, addr, size_t, length, int, flags) + if (SINGLE_THREAD_P) + return __syscall_msync(addr, length, flags); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + oldtype = LIBC_CANCEL_ASYNC (); + result = __syscall_msync(addr, length, flags); + LIBC_CANCEL_RESET (oldtype); + return result; #endif +} +weak_alias(__libc_msync,msync) diff --git a/libc/sysdeps/linux/common/nanosleep.c b/libc/sysdeps/linux/common/nanosleep.c index 0849127db..0be59c511 100644 --- a/libc/sysdeps/linux/common/nanosleep.c +++ b/libc/sysdeps/linux/common/nanosleep.c @@ -10,13 +10,32 @@ #include <sys/syscall.h> #include <time.h> -#if defined __USE_POSIX199309 && defined __NR_nanosleep -_syscall2(int, nanosleep, const struct timespec *, req, - struct timespec *, rem) -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(nanosleep) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#include <pthreadP.h> #else -libc_hidden_weak(nanosleep) -strong_alias(nanosleep,__libc_nanosleep) +#define SINGLE_THREAD_P 1 #endif + +#define __NR___syscall_nanosleep __NR_nanosleep +static inline _syscall2(int, __syscall_nanosleep, const struct timespec *, req, + struct timespec *, rem); + +extern __typeof(nanosleep) __libc_nanosleep; + +int __libc_nanosleep(const struct timespec *req, struct timespec *rem) +{ + if (SINGLE_THREAD_P) + return __syscall_nanosleep(req, rem); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_nanosleep(req, rem); + LIBC_CANCEL_RESET (oldtype); + return result; #endif +} + +libc_hidden_proto(nanosleep) +weak_alias(__libc_nanosleep,nanosleep) +libc_hidden_weak(nanosleep) diff --git a/libc/sysdeps/linux/common/not-cancel.h b/libc/sysdeps/linux/common/not-cancel.h new file mode 100644 index 000000000..ebdc6078d --- /dev/null +++ b/libc/sysdeps/linux/common/not-cancel.h @@ -0,0 +1,19 @@ +/* By default we have none. Map the name to the normal functions. */ +#define open_not_cancel(name, flags, mode) \ + open (name, flags, mode) +#define open_not_cancel_2(name, flags) \ + open (name, flags) +#define close_not_cancel(fd) \ + close (fd) +#define close_not_cancel_no_status(fd) \ + (void) close (fd) +#define read_not_cancel(fd, buf, n) \ + read (fd, buf, n) +#define write_not_cancel(fd, buf, n) \ + write (fd, buf, n) +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) writev (fd, iov, n) +#define fcntl_not_cancel(fd, cmd, val) \ + fcntl (fd, cmd, val) +# define waitpid_not_cancel(pid, stat_loc, options) \ + waitpid (pid, stat_loc, options) diff --git a/libc/sysdeps/linux/common/open64.c b/libc/sysdeps/linux/common/open64.c index cfe471c64..c1f5400b8 100644 --- a/libc/sysdeps/linux/common/open64.c +++ b/libc/sysdeps/linux/common/open64.c @@ -7,6 +7,10 @@ #include <features.h> #include <fcntl.h> #include <stdarg.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> +#endif #ifdef __UCLIBC_HAS_LFS__ @@ -28,7 +32,20 @@ int open64 (const char *file, int oflag, ...) va_end (arg); } - return open(file, oflag | O_LARGEFILE, mode); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + if (SINGLE_THREAD_P) + return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); + + LIBC_CANCEL_RESET (oldtype); + + return result; +#else + return open(file, oflag | O_LARGEFILE, mode); +#endif } #ifndef __LINUXTHREADS_OLD__ libc_hidden_def(open64) diff --git a/libc/sysdeps/linux/common/pause.c b/libc/sysdeps/linux/common/pause.c index 19ba30706..cd0ea4a77 100644 --- a/libc/sysdeps/linux/common/pause.c +++ b/libc/sysdeps/linux/common/pause.c @@ -10,18 +10,30 @@ #define __UCLIBC_HIDE_DEPRECATED__ #include <sys/syscall.h> #include <unistd.h> -#include <signal.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(pause) weak_function pause; -strong_alias(pause, __libc_pause) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> #endif -#ifdef __NR_pause -_syscall0(int, pause) -#else -int pause(void) +#include <signal.h> + +/* Suspend the process until a signal arrives. + This always returns -1 and sets errno to EINTR. */ +int +__libc_pause (void) { - return __sigpause(sigblock(0), 0); + sigset_t set; + + __sigemptyset (&set); + sigprocmask (SIG_BLOCK, NULL, &set); + + /* pause is a cancellation point, but so is sigsuspend. + So no need for anything special here. */ + + return sigsuspend (&set); } +weak_alias (__libc_pause, pause) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +LIBC_CANCEL_HANDLED (); /* sigsuspend handles our cancellation. */ #endif diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c index 4a6f06e19..f50e92c8e 100644 --- a/libc/sysdeps/linux/common/poll.c +++ b/libc/sysdeps/linux/common/poll.c @@ -20,30 +20,33 @@ #include <sys/syscall.h> #include <sys/poll.h> -#ifdef __NR_poll +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif -_syscall3(int, poll, struct pollfd *, fds, - unsigned long int, nfds, int, timeout) +libc_hidden_proto(poll) -#elif defined(__NR_ppoll) && defined __UCLIBC_LINUX_SPECIFIC__ +#ifdef __NR_poll + +#define __NR___syscall_poll __NR_poll +static inline _syscall3(int, __syscall_poll, struct pollfd *, fds, + unsigned long int, nfds, int, timeout); int poll(struct pollfd *fds, nfds_t nfds, int timeout) { - struct timespec *ts = NULL, tval; - if (timeout > 0) { - tval.tv_sec = timeout / 1000; - tval.tv_nsec = (timeout % 1000) * 1000000; - ts = &tval; - } else if (timeout == 0) { - tval.tv_sec = 0; - tval.tv_nsec = 0; - ts = &tval; - } - return ppoll(fds, nfds, ts, NULL); + if (SINGLE_THREAD_P) + return __syscall_poll(fds, nfds, timeout); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_poll(fds, nfds, timeout); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } - -#else -/* ugh, this arch lacks poll, so we need to emulate this crap ... */ +#else /* !__NR_poll */ #include <alloca.h> #include <sys/types.h> @@ -53,6 +56,9 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) #include <sys/param.h> #include <unistd.h> +libc_hidden_proto(getdtablesize) +libc_hidden_proto(select) + /* uClinux 2.0 doesn't have poll, emulate it using select */ /* Poll the file descriptors described by the NFDS structures starting at @@ -220,10 +226,4 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) } #endif - -#ifndef __LINUXTHREADS_OLD__ libc_hidden_def(poll) -#else -libc_hidden_weak(poll) -strong_alias(poll,__libc_poll) -#endif diff --git a/libc/sysdeps/linux/common/pselect.c b/libc/sysdeps/linux/common/pselect.c index 63ab0dbb1..7e93537dd 100644 --- a/libc/sysdeps/linux/common/pselect.c +++ b/libc/sysdeps/linux/common/pselect.c @@ -22,9 +22,12 @@ #include <stddef.h> /* For NULL. */ #include <sys/time.h> #include <sys/select.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#endif -extern __typeof(pselect) __libc_pselect; - +libc_hidden_proto(sigprocmask) +libc_hidden_proto(select) /* Check the first NFDS descriptors each in READFDS (if not NULL) for read @@ -33,8 +36,13 @@ extern __typeof(pselect) __libc_pselect; after waiting the interval specified therein. Additionally set the sigmask SIGMASK for this call. Returns the number of ready descriptors, or -1 for errors. */ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +static int +__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +#else int -__libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, +#endif const struct timespec *timeout, const sigset_t *sigmask) { struct timeval tval; @@ -64,4 +72,23 @@ __libc_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, return retval; } -weak_alias(__libc_pselect,pselect) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +int +pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + const struct timespec *timeout, const sigset_t *sigmask) +{ + if (SINGLE_THREAD_P) + return __pselect (nfds, readfds, writefds, exceptfds, + timeout, sigmask); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = __pselect (nfds, readfds, writefds, exceptfds, + timeout, sigmask); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +#endif diff --git a/libc/sysdeps/linux/common/readv.c b/libc/sysdeps/linux/common/readv.c index 3c40a0d8d..fce396d5f 100644 --- a/libc/sysdeps/linux/common/readv.c +++ b/libc/sysdeps/linux/common/readv.c @@ -2,7 +2,8 @@ /* * readv() for uClibc * - * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com> + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ @@ -10,5 +11,40 @@ #include <sys/syscall.h> #include <sys/uio.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> + +/* We should deal with kernel which have a smaller UIO_FASTIOV as well + as a very big count. */ +static ssize_t __readv (int fd, const struct iovec *vector, int count) +{ + ssize_t bytes_read; + + bytes_read = INLINE_SYSCALL (readv, 3, fd, vector, count); + + if (bytes_read >= 0 || errno != EINVAL || count <= UIO_FASTIOV) + return bytes_read; + + /* glibc tries again, but we do not. */ + //return __atomic_readv_replacement (fd, vector, count); + + return -1; +} + +ssize_t readv (int fd, const struct iovec *vector, int count) +{ + if (SINGLE_THREAD_P) + return __readv (fd, vector, count); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = __readv (fd, vector, count); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +#else _syscall3(ssize_t, readv, int, filedes, const struct iovec *, vector, int, count) +#endif diff --git a/libc/sysdeps/linux/common/select.c b/libc/sysdeps/linux/common/select.c index caff28d7c..0c2d91984 100644 --- a/libc/sysdeps/linux/common/select.c +++ b/libc/sysdeps/linux/common/select.c @@ -11,15 +11,21 @@ #include <sys/select.h> #include <stdint.h> -extern __typeof(select) __libc_select; +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif #define USEC_PER_SEC 1000000L +extern __typeof(select) __libc_select; + #if !defined(__NR__newselect) && !defined(__NR_select) && defined __USE_XOPEN2K # define __NR___libc_pselect6 __NR_pselect6 _syscall6(int, __libc_pselect6, int, n, fd_set *, readfds, fd_set *, writefds, - fd_set *, exceptfds, const struct timespec *, timeout, - const sigset_t *, sigmask) + fd_set *, exceptfds, const struct timespec *, timeout, + const sigset_t *, sigmask) int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) @@ -30,12 +36,12 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, _ts.tv_sec = timeout->tv_sec; /* GNU extension: allow for timespec values where the sub-sec - * field is equal to or more than 1 second. The kernel will - * reject this on us, so take care of the time shift ourself. - * Some applications (like readline and linphone) do this. - * See 'clarification on select() type calls and invalid timeouts' - * on the POSIX general list for more information. - */ + * field is equal to or more than 1 second. The kernel will + * reject this on us, so take care of the time shift ourself. + * Some applications (like readline and linphone) do this. + * See 'clarification on select() type calls and invalid timeouts' + * on the POSIX general list for more information. + */ usec = timeout->tv_usec; if (usec >= USEC_PER_SEC) { _ts.tv_sec += usec / USEC_PER_SEC; @@ -46,18 +52,41 @@ int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, ts = &_ts; } - return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); + if (SINGLE_THREAD_P) + return __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __libc_pselect6(n, readfds, writefds, exceptfds, ts, 0); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif + } #else #ifdef __NR__newselect -# define __NR___libc_select __NR__newselect +# define __NR___syscall_select __NR__newselect #else -# define __NR___libc_select __NR_select +# define __NR___syscall_select __NR_select #endif -_syscall5(int, __libc_select, int, n, fd_set *, readfds, fd_set *, writefds, - fd_set *, exceptfds, struct timeval *, timeout) + +_syscall5(int, __syscall_select, int, n, fd_set *, readfds, + fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout); + +int __libc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + if (SINGLE_THREAD_P) + return __syscall_select(n, readfds, writefds, exceptfds, timeout); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_select(n, readfds, writefds, exceptfds, timeout); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif +} #endif diff --git a/libc/sysdeps/linux/common/sigprocmask.c b/libc/sysdeps/linux/common/sigprocmask.c index 13bb2beb7..011d7b367 100644 --- a/libc/sysdeps/linux/common/sigprocmask.c +++ b/libc/sysdeps/linux/common/sigprocmask.c @@ -14,6 +14,7 @@ #undef sigprocmask +libc_hidden_proto(sigprocmask) #ifdef __NR_rt_sigprocmask @@ -24,20 +25,28 @@ _syscall4(int, __rt_sigprocmask, int, how, const sigset_t *, set, int sigprocmask(int how, const sigset_t * set, sigset_t * oldset) { - if (set && -# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2) - (((unsigned int) how) > 2) -# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3) - (((unsigned int)(how-1)) > 2) -# else -# warning "compile time assumption violated.. slow path..." - ((how != SIG_BLOCK) && (how != SIG_UNBLOCK) - && (how != SIG_SETMASK)) +#ifdef SIGCANCEL + sigset_t local_newmask; + + /* + * The only thing we have to make sure here is that SIGCANCEL and + * SIGSETXID are not blocked. + */ + if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + local_newmask = *set; + __sigdelset (&local_newmask, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&local_newmask, SIGSETXID); # endif - ) { - __set_errno(EINVAL); - return -1; + set = &local_newmask; } +#endif + return __rt_sigprocmask(how, set, oldset, _NSIG / 8); } @@ -51,20 +60,28 @@ _syscall3(int, __syscall_sigprocmask, int, how, const sigset_t *, set, int sigprocmask(int how, const sigset_t * set, sigset_t * oldset) { - if (set && -# if (SIG_BLOCK == 0) && (SIG_UNBLOCK == 1) && (SIG_SETMASK == 2) - (((unsigned int) how) > 2) -# elif (SIG_BLOCK == 1) && (SIG_UNBLOCK == 2) && (SIG_SETMASK == 3) - (((unsigned int)(how-1)) > 2) -# else -# warning "compile time assumption violated.. slow path..." - ((how != SIG_BLOCK) && (how != SIG_UNBLOCK) - && (how != SIG_SETMASK)) +#ifdef SIGCANCEL + sigset_t local_newmask; + + /* + * The only thing we have to make sure here is that SIGCANCEL and + * SIGSETXID are not blocked. + */ + if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + local_newmask = *set; + __sigdelset (&local_newmask, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&local_newmask, SIGSETXID); # endif - ) { - __set_errno(EINVAL); - return -1; + set = &local_newmask; } +#endif + return (__syscall_sigprocmask(how, set, oldset)); } #endif diff --git a/libc/sysdeps/linux/common/sigsuspend.c b/libc/sysdeps/linux/common/sigsuspend.c index 3648e76b5..789eeda89 100644 --- a/libc/sysdeps/linux/common/sigsuspend.c +++ b/libc/sysdeps/linux/common/sigsuspend.c @@ -11,27 +11,49 @@ #if defined __USE_POSIX #include <signal.h> +#undef sigsuspend -extern __typeof(sigsuspend) __libc_sigsuspend; +libc_hidden_proto(sigsuspend) #ifdef __NR_rt_sigsuspend # define __NR___rt_sigsuspend __NR_rt_sigsuspend -static __inline__ _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size) -int __libc_sigsuspend(const sigset_t * mask) +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include <errno.h> +# include <sysdep-cancel.h> + +/* Change the set of blocked signals to SET, + wait until a signal arrives, and restore the set of blocked signals. */ +int sigsuspend (const sigset_t *set) +{ + if (SINGLE_THREAD_P) + return INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +# else +static inline _syscall2(int, __rt_sigsuspend, const sigset_t *, mask, size_t, size); + +int sigsuspend(const sigset_t * mask) { return __rt_sigsuspend(mask, _NSIG / 8); } +# endif #else # define __NR___syscall_sigsuspend __NR_sigsuspend static __inline__ _syscall3(int, __syscall_sigsuspend, int, a, unsigned long int, b, unsigned long int, c) -int __libc_sigsuspend(const sigset_t * set) +int sigsuspend(const sigset_t * set) { return __syscall_sigsuspend(0, 0, set->__val[0]); } #endif -weak_alias(__libc_sigsuspend,sigsuspend) -libc_hidden_weak(sigsuspend) +libc_hidden_def(sigsuspend) #endif diff --git a/libc/sysdeps/linux/common/wait.c b/libc/sysdeps/linux/common/wait.c index b16495314..d4b79bd37 100644 --- a/libc/sysdeps/linux/common/wait.c +++ b/libc/sysdeps/linux/common/wait.c @@ -1,23 +1,43 @@ /* + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com> * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ - #include <stdlib.h> #include <syscall.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/resource.h> -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(wait) weak_function wait; -strong_alias(wait,__libc_wait) -#endif +/* Wait for a child to die. When one does, put its status in *STAT_LOC + * and return its process ID. For errors, return (pid_t) -1. */ +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> + +pid_t attribute_hidden +__libc_wait (__WAIT_STATUS_DEFN stat_loc) +{ + if (SINGLE_THREAD_P) + return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, + (struct rusage *) NULL); + int oldtype = LIBC_CANCEL_ASYNC (); + + pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, + (struct rusage *) NULL); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +#else /* Wait for a child to die. When one does, put its status in *STAT_LOC * and return its process ID. For errors, return (pid_t) -1. */ -__pid_t wait(__WAIT_STATUS_DEFN stat_loc) +__pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc) { - return wait4(WAIT_ANY, stat_loc, 0, NULL); + return wait4 (WAIT_ANY, stat_loc, 0, (struct rusage *) NULL); } +#endif +weak_alias(__libc_wait,wait) diff --git a/libc/sysdeps/linux/common/waitpid.c b/libc/sysdeps/linux/common/waitpid.c index e46499377..d0437194d 100644 --- a/libc/sysdeps/linux/common/waitpid.c +++ b/libc/sysdeps/linux/common/waitpid.c @@ -1,5 +1,6 @@ /* vi: set sw=4 ts=4: */ /* + * Copyright (C) 2006 Steven J. Hill <sjhill@realitydiluted.com> * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. @@ -10,13 +11,27 @@ #include <sys/wait.h> #include <sys/resource.h> -__pid_t waitpid(__pid_t pid, int *wait_stat, int options) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include "sysdep-cancel.h" +#else +#define SINGLE_THREAD_P 1 +#endif + +libc_hidden_proto(wait4) + +extern __typeof(waitpid) __libc_waitpid; +__pid_t __libc_waitpid(__pid_t pid, int *wait_stat, int options) { - return wait4(pid, wait_stat, options, NULL); + if (SINGLE_THREAD_P) + return wait4(pid, wait_stat, options, NULL); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = wait4(pid, wait_stat, options, NULL); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } -#ifndef __LINUXTHREADS_OLD__ -libc_hidden_def(waitpid) -#else +libc_hidden_proto(waitpid) +weak_alias(__libc_waitpid,waitpid) libc_hidden_weak(waitpid) -strong_alias(waitpid,__libc_waitpid) -#endif diff --git a/libc/sysdeps/linux/common/writev.c b/libc/sysdeps/linux/common/writev.c index 99de7e43d..bd0e4077d 100644 --- a/libc/sysdeps/linux/common/writev.c +++ b/libc/sysdeps/linux/common/writev.c @@ -10,5 +10,41 @@ #include <sys/syscall.h> #include <sys/uio.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <errno.h> +#include <sysdep-cancel.h> + +/* We should deal with kernel which have a smaller UIO_FASTIOV as well + as a very big count. */ +static ssize_t __writev (int fd, const struct iovec *vector, int count) +{ + ssize_t bytes_written; + + bytes_written = INLINE_SYSCALL (writev, 3, fd, vector, count); + + if (bytes_written >= 0 || errno != EINVAL || count <= UIO_FASTIOV) + return bytes_written; + + /* glibc tries again, but we do not. */ + /* return __atomic_writev_replacement (fd, vector, count); */ + + return -1; +} + +ssize_t writev (int fd, const struct iovec *vector, int count) +{ + if (SINGLE_THREAD_P) + return __writev (fd, vector, count); + + int oldtype = LIBC_CANCEL_ASYNC (); + + ssize_t result = __writev (fd, vector, count); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +#else _syscall3(ssize_t, writev, int, filedes, const struct iovec *, vector, int, count) +#endif diff --git a/libc/sysdeps/linux/i386/Makefile.arch b/libc/sysdeps/linux/i386/Makefile.arch index 2bf2b7607..668cca742 100644 --- a/libc/sysdeps/linux/i386/Makefile.arch +++ b/libc/sysdeps/linux/i386/Makefile.arch @@ -5,8 +5,17 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC := brk.c sigaction.c __syscall_error.c +CSRC := brk.c __syscall_error.c + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +endif SSRC := \ - __longjmp.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ + __longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ sync_file_range.S syscall.S mmap.S mmap64.S posix_fadvise64.S + + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +SSRC += vfork.S clone.S +endif diff --git a/libc/sysdeps/linux/i386/bits/syscalls.h b/libc/sysdeps/linux/i386/bits/syscalls.h index 23d872a29..f9ea54ac7 100644 --- a/libc/sysdeps/linux/i386/bits/syscalls.h +++ b/libc/sysdeps/linux/i386/bits/syscalls.h @@ -102,7 +102,7 @@ __asm__ (".L__X'%ebx = 1\n\t" "int $0x80\n\t" \ RESTOREARGS_##nr \ : "=a" (resultvar) \ - : "i" (name) ASMFMT_##nr(args) : "memory", "cc"); \ + : "g" (name) ASMFMT_##nr(args) : "memory", "cc"); \ (int) resultvar; }) #define LOADARGS_0 diff --git a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h index deeec03d5..536e9c155 100644 --- a/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/i386/bits/uClibc_arch_features.h @@ -37,7 +37,7 @@ #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__ /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ /* define if target supports IEEE signed zero floats */ #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/i386/clone.S b/libc/sysdeps/linux/i386/clone.S index 14fc25ca1..a7de3fe27 100644 --- a/libc/sysdeps/linux/i386/clone.S +++ b/libc/sysdeps/linux/i386/clone.S @@ -79,7 +79,10 @@ clone: movl %eax,8(%ecx) /* Don't leak any information. */ movl $0,4(%ecx) +#ifndef RESET_PID movl $0,(%ecx) +#endif + /* Do the system call */ pushl %ebx @@ -90,6 +93,10 @@ clone: movl FLAGS+12(%esp),%ebx movl CTID+12(%esp),%edi movl $__NR_clone,%eax +#ifdef RESET_PID + /* Remember the flag value. */ + movl %ebx, (%ecx) +#endif int $0x80 popl %edi popl %esi @@ -121,3 +128,4 @@ __error: jmp __syscall_error .size clone,.-clone +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/i386/vfork.S b/libc/sysdeps/linux/i386/vfork.S index 8005ff1d2..c9db2f48c 100644 --- a/libc/sysdeps/linux/i386/vfork.S +++ b/libc/sysdeps/linux/i386/vfork.S @@ -18,9 +18,19 @@ __vfork: popl %ecx + +#ifdef SAVE_PID + SAVE_PID +#endif + movl $__NR_vfork,%eax int $0x80 pushl %ecx + +#ifdef RESTORE_PID + RESTORE_PID +#endif + cmpl $-4095,%eax jae __syscall_error ret diff --git a/libc/sysdeps/linux/mips/Makefile.arch b/libc/sysdeps/linux/mips/Makefile.arch index 2570a6988..73e64991c 100644 --- a/libc/sysdeps/linux/mips/Makefile.arch +++ b/libc/sysdeps/linux/mips/Makefile.arch @@ -7,11 +7,15 @@ CSRC := \ __longjmp.c brk.c setjmp_aux.c mmap.c __syscall_error.c \ - cacheflush.c pread_write.c sysmips.c _test_and_set.c sigaction.c \ + cacheflush.c pread_write.c sysmips.c _test_and_set.c \ readahead.c ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) - CSRC += posix_fadvise.c posix_fadvise64.c +CSRC += posix_fadvise.c posix_fadvise64.c +endif + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c endif SSRC := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S syscall.S pipe.S diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S index 15fa29558..a53d5c492 100644 --- a/libc/sysdeps/linux/mips/clone.S +++ b/libc/sysdeps/linux/mips/clone.S @@ -132,3 +132,4 @@ L(__thread_start): jal _exit #endif .end __thread_start +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/mips/sys/asm.h b/libc/sysdeps/linux/mips/sys/asm.h index 79d143975..d424ed3b1 100644 --- a/libc/sysdeps/linux/mips/sys/asm.h +++ b/libc/sysdeps/linux/mips/sys/asm.h @@ -472,4 +472,20 @@ symbol = value # define MTC0 dmtc0 #endif +/* The MIPS archtectures do not have a uniform memory model. Particular + platforms may provide additional guarantees - for instance, the R4000 + LL and SC instructions implicitly perform a SYNC, and the 4K promises + strong ordering. + + However, in the absence of those guarantees, we must assume weak ordering + and SYNC explicitly where necessary. + + Some obsolete MIPS processors may not support the SYNC instruction. This + applies to "true" MIPS I processors; most of the processors which compile + using MIPS I implement parts of MIPS II. */ + +#ifndef MIPS_SYNC +# define MIPS_SYNC sync +#endif + #endif /* sys/asm.h */ diff --git a/libc/sysdeps/linux/mips/sys/regdef.h b/libc/sysdeps/linux/mips/sys/regdef.h index 9d2c4c1c4..2d94130af 100644 --- a/libc/sysdeps/linux/mips/sys/regdef.h +++ b/libc/sysdeps/linux/mips/sys/regdef.h @@ -20,6 +20,8 @@ #ifndef _SYS_REGDEF_H #define _SYS_REGDEF_H +#include <sgidefs.h> + /* * Symbolic register names for 32 bit ABI */ diff --git a/libc/sysdeps/linux/mips/syscall_error.S b/libc/sysdeps/linux/mips/syscall_error.S new file mode 100644 index 000000000..1e348ad4a --- /dev/null +++ b/libc/sysdeps/linux/mips/syscall_error.S @@ -0,0 +1,82 @@ +/* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Brendan Kehoe (brendan@zen.org). + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/asm.h> +#include <sysdep.h> +#include <bits/errno.h> + +#ifdef __UCLIBC_HAS_THREADS__ + +LOCALSZ= 3 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +RAOFF= FRAMESZ-(1*SZREG) +GPOFF= FRAMESZ-(2*SZREG) +V0OFF= FRAMESZ-(3*SZREG) + +ENTRY(__syscall_error) +#ifdef __PIC__ + .set noat + SETUP_GPX (AT) + .set at +#endif + PTR_SUBU sp, FRAMESZ + .set noat + SETUP_GPX64(GPOFF,AT) + .set at +#ifdef __PIC__ + SAVE_GP(GPOFF) +#endif + REG_S v0, V0OFF(sp) + REG_S ra, RAOFF(sp) + + /* Find our per-thread errno address */ + jal __errno_location + + /* Store the error value. */ + REG_L t0, V0OFF(sp) + sw t0, 0(v0) + + /* And just kick back a -1. */ + REG_L ra, RAOFF(sp) + RESTORE_GP64 + PTR_ADDU sp, FRAMESZ + li v0, -1 + j ra + END(__syscall_error) + +#else /* __UCLIBC_HAS_THREADS__ */ + + +ENTRY(__syscall_error) +#ifdef __PIC__ + SETUP_GPX (AT) +#endif + SETUP_GPX64 (t9, AT) + + /* Store it in errno... */ + sw v0, errno + + /* And just kick back a -1. */ + li v0, -1 + + RESTORE_GP64 + j ra + END(__syscall_error) +#endif /* __UCLIBC_HAS_THREADS__ */ diff --git a/libc/sysdeps/linux/mips/sysdep.h b/libc/sysdeps/linux/mips/sysdep.h new file mode 100644 index 000000000..38d4ce903 --- /dev/null +++ b/libc/sysdeps/linux/mips/sysdep.h @@ -0,0 +1,54 @@ +/* Adapted from glibc's sysdeps/unix/mips/sysdep.h */ + +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Brendan Kehoe (brendan@zen.org). + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> + +#if __UCLIBC_HAS_THREADS_NATIVE__ +#include_next <sysdep.h> + +#else + +#ifdef __ASSEMBLER__ + +#include <sgidefs.h> +#include <sys/regdef.h> + +#define ENTRY(name) \ + .globl name; \ + .align 2; \ + .ent name,0; \ + name##: + +#undef END +#define END(function) \ + .end function; \ + .size function,.-function + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +#endif + +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/sysdeps/linux/mips/vfork.S b/libc/sysdeps/linux/mips/vfork.S new file mode 100644 index 000000000..8400df052 --- /dev/null +++ b/libc/sysdeps/linux/mips/vfork.S @@ -0,0 +1,97 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* vfork() is just a special case of clone(). */ + +#include <sys/asm.h> +#include <sysdep.h> + +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + + +/* int vfork() */ + + .text +LOCALSZ= 1 +FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK +GPOFF= FRAMESZ-(1*SZREG) +NESTED(__vfork,FRAMESZ,sp) +#ifdef __PIC__ + SETUP_GP +#endif + PTR_SUBU sp, FRAMESZ + SETUP_GP64 (a5, __vfork) +#ifdef __PIC__ + SAVE_GP (GPOFF) +#endif +#ifdef PROF +# if (_MIPS_SIM != _ABIO32) + PTR_S a5, GPOFF(sp) +# endif + .set noat + move $1, ra +# if (_MIPS_SIM == _ABIO32) + subu sp,sp,8 +# endif + jal _mcount + .set at +# if (_MIPS_SIM != _ABIO32) + PTR_L a5, GPOFF(sp) +# endif +#endif + + PTR_ADDU sp, FRAMESZ + + SAVE_PID + + li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + move a1, sp + + /* Do the system call */ + li v0,__NR_clone + syscall + + RESTORE_PID + + bnez a3,L(error) + + /* Successful return from the parent or child. */ + RESTORE_GP64 + j ra + nop + + /* Something bad happened -- no child created. */ +L(error): +#ifdef __PIC__ + PTR_LA t9, __syscall_error + RESTORE_GP64 + jr t9 +#else + RESTORE_GP64 + j __syscall_error +#endif + END(__vfork) + +.weak vfork; + vfork = __vfork diff --git a/libc/sysdeps/linux/sh/Makefile.arch b/libc/sysdeps/linux/sh/Makefile.arch index 31beda111..3e32e1095 100644 --- a/libc/sysdeps/linux/sh/Makefile.arch +++ b/libc/sysdeps/linux/sh/Makefile.arch @@ -7,6 +7,6 @@ # CSRC := \ - mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c cacheflush.c + mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c longjmp.c cacheflush.c -SSRC := setjmp.S __longjmp.S vfork.S clone.S ___fpscr_values.S +SSRC := setjmp.S __longjmp.S ___fpscr_values.S diff --git a/libc/sysdeps/linux/sh/bits/atomic.h b/libc/sysdeps/linux/sh/bits/atomic.h index 6bb7255c5..a099b43a8 100644 --- a/libc/sysdeps/linux/sh/bits/atomic.h +++ b/libc/sysdeps/linux/sh/bits/atomic.h @@ -54,6 +54,10 @@ typedef uintmax_t uatomic_max_t; Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in Japanese). + Niibe Yutaka, "gUSA: User Space Atomicity with Little Kernel + Modification", LinuxTag 2003, Rome. + http://www.semmel.ch/Linuxtag-DVD/talks/170/paper.html (in English). + B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for Uniprocessors", Proceedings of the Fifth Architectural Support for Programming Languages and Operating Systems (ASPLOS), pp. 223-233, @@ -65,56 +69,44 @@ typedef uintmax_t uatomic_max_t; r1: saved stack pointer */ -#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ - ({ __typeof (*(mem)) __result; \ - __asm__ __volatile__ ("\ +/* Avoid having lots of different versions of compare and exchange, + by having this one complicated version. Parameters: + bwl: b, w or l for 8, 16 and 32 bit versions. + version: val or bool, depending on whether the result is the + previous value or a bool indicating whether the transfer + did happen (note this needs inverting before being + returned in atomic_compare_and_exchange_bool). +*/ + +#define __arch_compare_and_exchange_n(mem, newval, oldval, bwl, version) \ + ({ signed long __result; \ + __asm __volatile ("\ .align 2\n\ mova 1f,r0\n\ nop\n\ mov r15,r1\n\ mov #-8,r15\n\ - 0: mov.b @%1,%0\n\ + 0: mov." #bwl " @%1,%0\n\ cmp/eq %0,%3\n\ bf 1f\n\ - mov.b %2,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ - : "r0", "r1", "t", "memory"); \ + mov." #bwl " %2,@%1\n\ + 1: mov r1,r15\n\ + .ifeqs \"bool\",\"" #version "\"\n\ + movt %0\n\ + .endif\n" \ + : "=&r" (__result) \ + : "r" (mem), "r" (newval), "r" (oldval) \ + : "r0", "r1", "t", "memory"); \ __result; }) +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, val) + #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ - ({ __typeof (*(mem)) __result; \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - nop\n\ - mov r15,r1\n\ - mov #-8,r15\n\ - 0: mov.w @%1,%0\n\ - cmp/eq %0,%3\n\ - bf 1f\n\ - mov.w %2,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ - : "r0", "r1", "t", "memory"); \ - __result; }) + __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, val) #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ({ __typeof (*(mem)) __result; \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - nop\n\ - mov r15,r1\n\ - mov #-8,r15\n\ - 0: mov.l @%1,%0\n\ - cmp/eq %0,%3\n\ - bf 1f\n\ - mov.l %2,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \ - : "r0", "r1", "t", "memory"); \ - __result; }) + __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, val) /* XXX We do not really need 64-bit compare-and-exchange. At least not in the moment. Using it would mean causing portability @@ -122,298 +114,180 @@ typedef uintmax_t uatomic_max_t; such an operation. So don't define any code for now. */ # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ - (abort (), (__typeof (*mem)) 0) + (abort (), 0) + +/* For "bool" routines, return if the exchange did NOT occur */ + +#define __arch_compare_and_exchange_bool_8_acq(mem, newval, oldval) \ + (! __arch_compare_and_exchange_n(mem, newval, (int8_t)(oldval), b, bool)) + +#define __arch_compare_and_exchange_bool_16_acq(mem, newval, oldval) \ + (! __arch_compare_and_exchange_n(mem, newval, (int16_t)(oldval), w, bool)) + +#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \ + (! __arch_compare_and_exchange_n(mem, newval, (int32_t)(oldval), l, bool)) + +# define __arch_compare_and_exchange_bool_64_acq(mem, newval, oldval) \ + (abort (), 0) + +/* Similar to the above, have one template which can be used in a + number of places. This version returns both the old and the new + values of the location. Parameters: + bwl: b, w or l for 8, 16 and 32 bit versions. + oper: The instruction to perform on the old value. + Note old is not sign extended, so should be an unsigned long. +*/ + +#define __arch_operate_old_new_n(mem, value, old, new, bwl, oper) \ + (void) ({ __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + mov r15,r1\n\ + nop\n\ + mov #-8,r15\n\ + 0: mov." #bwl " @%2,%0\n\ + mov %0,%1\n\ + " #oper " %3,%1\n\ + mov." #bwl " %1,@%2\n\ + 1: mov r1,r15" \ + : "=&r" (old), "=&r"(new) \ + : "r" (mem), "r" (value) \ + : "r0", "r1", "memory"); \ + }) + +#define __arch_exchange_and_add_8_int(mem, value) \ + ({ int32_t __value = (value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, b, add); \ + __old; }) + +#define __arch_exchange_and_add_16_int(mem, value) \ + ({ int32_t __value = (value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, w, add); \ + __old; }) + +#define __arch_exchange_and_add_32_int(mem, value) \ + ({ int32_t __value = (value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, l, add); \ + __old; }) + +#define __arch_exchange_and_add_64_int(mem, value) \ + (abort (), 0) #define atomic_exchange_and_add(mem, value) \ - ({ __typeof (*(mem)) __result, __tmp, __value = (value); \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.b @%2,%0\n\ - add %0,%1\n\ - mov.b %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.w @%2,%0\n\ - add %0,%1\n\ - mov.w %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.l @%2,%0\n\ - add %0,%1\n\ - mov.l %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "memory"); \ - else \ - { \ - __typeof (mem) memp = (mem); \ - do \ - __result = *memp; \ - while (__arch_compare_and_exchange_val_64_acq \ - (memp, __result + __value, __result) == __result); \ - (void) __value; \ - } \ - __result; }) + __atomic_val_bysize (__arch_exchange_and_add, int, mem, value) + + +/* Again, another template. We get a slight optimisation when the old value + does not need to be returned. Parameters: + bwl: b, w or l for 8, 16 and 32 bit versions. + oper: The instruction to perform on the old value. +*/ + +#define __arch_operate_new_n(mem, value, bwl, oper) \ + ({ int32_t __value = (value), __new; \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + mov r15,r1\n\ + mov #-6,r15\n\ + 0: mov." #bwl " @%1,%0\n\ + " #oper " %2,%0\n\ + mov." #bwl " %0,@%1\n\ + 1: mov r1,r15" \ + : "=&r" (__new) \ + : "r" (mem), "r" (__value) \ + : "r0", "r1", "memory"); \ + __new; \ + }) + +#define __arch_add_8_int(mem, value) \ + __arch_operate_new_n(mem, value, b, add) + +#define __arch_add_16_int(mem, value) \ + __arch_operate_new_n(mem, value, w, add) + +#define __arch_add_32_int(mem, value) \ + __arch_operate_new_n(mem, value, l, add) + +#define __arch_add_64_int(mem, value) \ + (abort (), 0) #define atomic_add(mem, value) \ - (void) ({ __typeof (*(mem)) __tmp, __value = (value); \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.b @%1,r2\n\ - add r2,%0\n\ - mov.b %0,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__tmp) : "r" (mem), "0" (__value) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.w @%1,r2\n\ - add r2,%0\n\ - mov.w %0,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__tmp) : "r" (mem), "0" (__value) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.l @%1,r2\n\ - add r2,%0\n\ - mov.l %0,@%1\n\ - 1: mov r1,r15"\ - : "=&r" (__tmp) : "r" (mem), "0" (__value) \ - : "r0", "r1", "r2", "memory"); \ - else \ - { \ - __typeof (*(mem)) oldval; \ - __typeof (mem) memp = (mem); \ - do \ - oldval = *memp; \ - while (__arch_compare_and_exchange_val_64_acq \ - (memp, oldval + __value, oldval) == oldval); \ - (void) __value; \ - } \ - }) + ((void) __atomic_val_bysize (__arch_add, int, mem, value)) + + +#define __arch_add_negative_8_int(mem, value) \ + (__arch_operate_new_n(mem, value, b, add) < 0) + +#define __arch_add_negative_16_int(mem, value) \ + (__arch_operate_new_n(mem, value, w, add) < 0) + +#define __arch_add_negative_32_int(mem, value) \ + (__arch_operate_new_n(mem, value, l, add) < 0) + +#define __arch_add_negative_64_int(mem, value) \ + (abort (), 0) #define atomic_add_negative(mem, value) \ - ({ unsigned char __result; \ - __typeof (*(mem)) __tmp, __value = (value); \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.b @%2,r2\n\ - add r2,%1\n\ - mov.b %1,@%2\n\ - 1: mov r1,r15\n\ - shal %1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.w @%2,r2\n\ - add r2,%1\n\ - mov.w %1,@%2\n\ - 1: mov r1,r15\n\ - shal %1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.l @%2,r2\n\ - add r2,%1\n\ - mov.l %1,@%2\n\ - 1: mov r1,r15\n\ - shal %1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else \ - abort (); \ - __result; }) + __atomic_bool_bysize (__arch_add_negative, int, mem, value) + + +#define __arch_add_zero_8_int(mem, value) \ + (__arch_operate_new_n(mem, value, b, add) == 0) + +#define __arch_add_zero_16_int(mem, value) \ + (__arch_operate_new_n(mem, value, w, add) == 0) + +#define __arch_add_zero_32_int(mem, value) \ + (__arch_operate_new_n(mem, value, l, add) == 0) + +#define __arch_add_zero_64_int(mem, value) \ + (abort (), 0) #define atomic_add_zero(mem, value) \ - ({ unsigned char __result; \ - __typeof (*(mem)) __tmp, __value = (value); \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.b @%2,r2\n\ - add r2,%1\n\ - mov.b %1,@%2\n\ - 1: mov r1,r15\n\ - tst %1,%1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.w @%2,r2\n\ - add r2,%1\n\ - mov.w %1,@%2\n\ - 1: mov r1,r15\n\ - tst %1,%1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.l @%2,r2\n\ - add r2,%1\n\ - mov.l %1,@%2\n\ - 1: mov r1,r15\n\ - tst %1,%1\n\ - movt %0"\ - : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \ - : "r0", "r1", "r2", "t", "memory"); \ - else \ - abort (); \ - __result; }) + __atomic_bool_bysize (__arch_add_zero, int, mem, value) + #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1) #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) -#define atomic_bit_set(mem, bit) \ - (void) ({ unsigned int __mask = 1 << (bit); \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.b @%0,r2\n\ - or %1,r2\n\ - mov.b r2,@%0\n\ - 1: mov r1,r15"\ - : : "r" (mem), "r" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.w @%0,r2\n\ - or %1,r2\n\ - mov.w r2,@%0\n\ - 1: mov r1,r15"\ - : : "r" (mem), "r" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - mov r15,r1\n\ - mov #-6,r15\n\ - 0: mov.l @%0,r2\n\ - or %1,r2\n\ - mov.l r2,@%0\n\ - 1: mov r1,r15"\ - : : "r" (mem), "r" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else \ - abort (); \ - }) - -#define atomic_bit_test_set(mem, bit) \ - ({ unsigned int __mask = 1 << (bit); \ - unsigned int __result = __mask; \ - if (sizeof (*(mem)) == 1) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - nop\n\ - mov r15,r1\n\ - mov #-8,r15\n\ - 0: mov.b @%2,r2\n\ - or r2,%1\n\ - and r2,%0\n\ - mov.b %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__mask) \ - : "r" (mem), "0" (__result), "1" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 2) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - nop\n\ - mov r15,r1\n\ - mov #-8,r15\n\ - 0: mov.w @%2,r2\n\ - or r2,%1\n\ - and r2,%0\n\ - mov.w %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__mask) \ - : "r" (mem), "0" (__result), "1" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else if (sizeof (*(mem)) == 4) \ - __asm__ __volatile__ ("\ - .align 2\n\ - mova 1f,r0\n\ - nop\n\ - mov r15,r1\n\ - mov #-8,r15\n\ - 0: mov.l @%2,r2\n\ - or r2,%1\n\ - and r2,%0\n\ - mov.l %1,@%2\n\ - 1: mov r1,r15"\ - : "=&r" (__result), "=&r" (__mask) \ - : "r" (mem), "0" (__result), "1" (__mask) \ - : "r0", "r1", "r2", "memory"); \ - else \ - abort (); \ - __result; }) + +#define __arch_bit_set_8_int(mem, value) \ + __arch_operate_new_n(mem, 1<<(value), b, or) + +#define __arch_bit_set_16_int(mem, value) \ + __arch_operate_new_n(mem, 1<<(value), w, or) + +#define __arch_bit_set_32_int(mem, value) \ + __arch_operate_new_n(mem, 1<<(value), l, or) + +#define __arch_bit_set_64_int(mem, value) \ + (abort (), 0) + +#define __arch_add_64_int(mem, value) \ + (abort (), 0) + +#define atomic_bit_set(mem, value) \ + ((void) __atomic_val_bysize (__arch_bit_set, int, mem, value)) + + +#define __arch_bit_test_set_8_int(mem, value) \ + ({ int32_t __value = 1<<(value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, b, or); \ + __old & __value; }) + +#define __arch_bit_test_set_16_int(mem, value) \ + ({ int32_t __value = 1<<(value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, w, or); \ + __old & __value; }) + +#define __arch_bit_test_set_32_int(mem, value) \ + ({ int32_t __value = 1<<(value), __new, __old; \ + __arch_operate_old_new_n((mem), __value, __old, __new, l, or); \ + __old & __value; }) + +#define __arch_bit_test_set_64_int(mem, value) \ + (abort (), 0) + +#define atomic_bit_test_set(mem, value) \ + __atomic_val_bysize (__arch_bit_test_set, int, mem, value) diff --git a/libc/sysdeps/linux/sh/clone.S b/libc/sysdeps/linux/sh/clone.S index 3d18b6dd0..423a6c2f1 100644 --- a/libc/sysdeps/linux/sh/clone.S +++ b/libc/sysdeps/linux/sh/clone.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1999, 2000, 2003, 2004, 2007 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 @@ -20,93 +20,94 @@ and invokes a function in the right context after its all over. */ #include <features.h> -#include <sys/syscall.h> -#define _ERRNO_H +#include <asm/unistd.h> +#include <sysdep.h> +#define _ERRNO_H 1 #include <bits/errno.h> -#include <bits/sysnum.h> - - -#ifdef __PIC__ -#define PLTJMP(_x) _x@PLT -#else -#define PLTJMP(_x) _x +#ifdef RESET_PID +#include <tcb-offsets.h> #endif +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, void *tls, pid_t *ctid); */ - -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ - - .text - -.text -.align 4 -.type clone,@function -.globl clone; -clone: + .text +ENTRY(__clone) /* sanity check arguments. */ tst r4, r4 - bt 0f - tst r5, r5 - bf/s 1f - mov #+__NR_clone, r3 -0: - bra __syscall_error - mov #-EINVAL, r4 - + bt/s 0f + tst r5, r5 + bf 1f +0: + bra .Lsyscall_error + mov #-EINVAL,r0 1: /* insert the args onto the new stack */ mov.l r7, @-r5 /* save the function pointer as the 0th element */ mov.l r4, @-r5 - + /* do the system call */ mov r6, r4 - trapa #(__SH_SYSCALL_TRAP_BASE + 2) + mov.l @r15, r6 + mov.l @(8,r15), r7 + mov.l @(4,r15), r0 + mov #+SYS_ify(clone), r3 + trapa #0x15 mov r0, r1 -#ifdef __sh2__ -/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist! */ - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 - shar r1 -#else mov #-12, r2 shad r2, r1 -#endif - not r1, r1 /* r1=0 means r0 = -1 to -4095 */ - tst r1, r1 /* i.e. error in linux */ - bf/s 2f - tst r0, r0 - bra __syscall_error - mov r0, r4 - -2: - bt 3f + not r1, r1 // r1=0 means r0 = -1 to -4095 + tst r1, r1 // i.e. error in linux + bf .Lclone_end +.Lsyscall_error: + SYSCALL_ERROR_HANDLER +.Lclone_end: + tst r0, r0 + bt 2f +.Lpseudo_end: rts nop +2: + /* terminate the stack frame */ + mov #0, r14 +#ifdef RESET_PID + mov r4, r0 + shlr16 r0 + tst #1, r0 // CLONE_THREAD = (1 << 16) + bf/s 4f + mov r4, r0 + /* new pid */ + shlr8 r0 + tst #1, r0 // CLONE_VM = (1 << 8) + bf/s 3f + mov #-1, r0 + mov #+SYS_ify(getpid), r3 + trapa #0x15 3: + stc gbr, r1 + mov.w .Lpidoff, r2 + add r1, r2 + mov.l r0, @r2 + mov.w .Ltidoff, r2 + add r1, r2 + mov.l r0, @r2 +4: +#endif /* thread starts */ mov.l @r15, r1 jsr @r1 mov.l @(4,r15), r4 /* we are done, passing the return value through r0 */ - mov.l .L1, r1 -#ifdef __PIC__ + mov.l .L3, r1 +#ifdef SHARED mov.l r12, @-r15 sts.l pr, @-r15 mov r0, r4 - mova .LG, r0 /* .LG from syscall_error.S */ + mova .LG, r0 mov.l .LG, r12 add r0, r12 - mova .L1, r0 + mova .L3, r0 add r0, r1 jsr @r1 nop @@ -118,8 +119,16 @@ clone: mov r0, r4 #endif .align 2 -.L1: - .long PLTJMP( HIDDEN_JUMPTARGET(_exit)) -.size clone,.-clone; +.LG: + .long _GLOBAL_OFFSET_TABLE_ +.L3: + .long PLTJMP(C_SYMBOL_NAME(_exit)) +#ifdef RESET_PID +.Lpidoff: + .word PID - TLS_PRE_TCB_SIZE +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE +#endif +PSEUDO_END (__clone) -#include "syscall_error.S" +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sh/longjmp.c b/libc/sysdeps/linux/sh/longjmp.c new file mode 100644 index 000000000..dd0616d8a --- /dev/null +++ b/libc/sysdeps/linux/sh/longjmp.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991, 92, 94, 95, 97, 98, 2000 Free Software Foundation, Inc. + Copyright (C) 2001 Hewlett-Packard Australia + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU Library General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. + + This program 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 Library General Public License for more + details. + + You should have received a copy of the GNU Library General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Derived in part from the Linux-8086 C library, the GNU C Library, and several + other sundry sources. Files within this library are copyright by their + respective copyright holders. +*/ + +#include <stddef.h> +#include <setjmp.h> +#include <signal.h> + +libc_hidden_proto(sigprocmask) + +extern int __longjmp(char *env, int val); +libc_hidden_proto(__longjmp) + +extern void _longjmp_unwind (jmp_buf env, int val); + + +/* Set the signal mask to the one specified in ENV, and jump + to the position specified in ENV, causing the setjmp + call there to return VAL, or 1 if VAL is 0. */ +void __libc_siglongjmp (sigjmp_buf env, int val) +{ + /* Perform any cleanups needed by the frames being unwound. */ + + _longjmp_unwind (env, val); + + if (env[0].__mask_was_saved) + /* Restore the saved signal mask. */ + (void) sigprocmask (SIG_SETMASK, &env[0].__saved_mask, + (sigset_t *) NULL); + + /* Call the machine-dependent function to restore machine state. */ + __longjmp ((char *) env[0].__jmpbuf, val ?: 1); +} + +__asm__(".weak longjmp; longjmp = __libc_siglongjmp"); +__asm__(".weak _longjmp; _longjmp = __libc_siglongjmp"); +__asm__(".weak siglongjmp; siglongjmp = __libc_siglongjmp"); +strong_alias(__libc_siglongjmp, __libc_longjmp) diff --git a/libc/sysdeps/linux/sh/pread_write.c b/libc/sysdeps/linux/sh/pread_write.c index 84a28e766..86feb9cce 100644 --- a/libc/sysdeps/linux/sh/pread_write.c +++ b/libc/sysdeps/linux/sh/pread_write.c @@ -18,6 +18,13 @@ #include <stdint.h> #include <endian.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> +#else +#define SINGLE_THREAD_P 1 +#endif + + #ifdef __NR_pread64 /* Newer kernels renamed but it's the same. */ # ifdef __NR_pread # error "__NR_pread and __NR_pread64 both defined???" @@ -33,7 +40,15 @@ static __inline__ _syscall6(ssize_t, __syscall_pread, int, fd, void *, buf, ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset) { - return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); + if (SINGLE_THREAD_P) + return(__syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + ssize_t result = __syscall_pread(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } weak_alias(__libc_pread,pread) @@ -43,7 +58,16 @@ ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset) { uint32_t low = offset & 0xffffffff; uint32_t high = offset >> 32; - return(__syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + + if (SINGLE_THREAD_P) + return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + ssize_t result = __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } weak_alias(__libc_pread64,pread64) # endif /* __UCLIBC_HAS_LFS__ */ @@ -66,7 +90,16 @@ static __inline__ _syscall6(ssize_t, __syscall_pwrite, int, fd, const void *, bu ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset) { - return(__syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset))); + if (SINGLE_THREAD_P) + return __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + ssize_t result = __syscall_pwrite(fd,buf,count,0,__LONG_LONG_PAIR(offset >> 31,offset)); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif + } weak_alias(__libc_pwrite,pwrite) @@ -76,7 +109,16 @@ ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset) { uint32_t low = offset & 0xffffffff; uint32_t high = offset >> 32; - return(__syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low))); + + if (SINGLE_THREAD_P) + return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + ssize_t result = __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR (high, low)); + LIBC_CANCEL_RESET (oldtype); + return result; +#endif } weak_alias(__libc_pwrite64,pwrite64) # endif /* __UCLIBC_HAS_LFS__ */ diff --git a/libc/sysdeps/linux/sh/setjmp.S b/libc/sysdeps/linux/sh/setjmp.S index 00475a008..0a81424e1 100644 --- a/libc/sysdeps/linux/sh/setjmp.S +++ b/libc/sysdeps/linux/sh/setjmp.S @@ -77,7 +77,7 @@ __sigsetjmp_intern: mov.l r9, @-r4 mov.l r8, @-r4 -#ifdef __PIC__ +#ifdef __HAVE_SHARED__ mov.l .LG, r2 mova .LG, r0 add r0, r2 diff --git a/libc/sysdeps/linux/sh/syscall_error.S b/libc/sysdeps/linux/sh/syscall_error.S index f55dd535a..737950308 100644 --- a/libc/sysdeps/linux/sh/syscall_error.S +++ b/libc/sysdeps/linux/sh/syscall_error.S @@ -3,7 +3,7 @@ __syscall_error: /* Call errno_location, store '-r4' in errno and return -1 */ mov.l r12, @-r15 sts.l pr, @-r15 -#ifdef __PIC__ +#ifdef SHARED mova .LG, r0 mov.l .LG, r12 add r0, r12 @@ -27,7 +27,7 @@ __syscall_error: .align 4 -#ifdef __PIC__ +#ifdef SHARED 1: .long __errno_location@GOT .LG: .long _GLOBAL_OFFSET_TABLE_ #else diff --git a/libc/sysdeps/linux/sparc/Makefile.arch b/libc/sysdeps/linux/sparc/Makefile.arch index ffae27bc7..8a624205a 100644 --- a/libc/sysdeps/linux/sparc/Makefile.arch +++ b/libc/sysdeps/linux/sparc/Makefile.arch @@ -5,8 +5,15 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC := brk.c __syscall_error.c qp_ops.c sigaction.c +CSRC := brk.c __syscall_error.c qp_ops.c SSRC := \ - __longjmp.S fork.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ + __longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ syscall.S urem.S udiv.S umul.S sdiv.S rem.S pipe.S + +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) +CSRC += sigaction.c +SSRC += fork.S vfork.S +endif + + diff --git a/libc/sysdeps/linux/sparc/bits/atomic.h b/libc/sysdeps/linux/sparc/bits/atomic.h new file mode 100644 index 000000000..f625eb92a --- /dev/null +++ b/libc/sysdeps/linux/sparc/bits/atomic.h @@ -0,0 +1,329 @@ +/* Atomic operations. sparc32 version. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_ATOMIC_H +#define _BITS_ATOMIC_H 1 + +#include <stdint.h> + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int16_t atomic16_t; +typedef uint16_t uatomic16_t; +typedef int_fast16_t atomic_fast16_t; +typedef uint_fast16_t uatomic_fast16_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + + +/* We have no compare and swap, just test and set. + The following implementation contends on 64 global locks + per library and assumes no variable will be accessed using atomic.h + macros from two different libraries. */ + +__make_section_unallocated + (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits"); + +volatile unsigned char __sparc32_atomic_locks[64] + __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks" + __sec_comment), + visibility ("hidden"))); + +#define __sparc32_atomic_do_lock(addr) \ + do \ + { \ + unsigned int __old_lock; \ + unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \ + & 63; \ + do \ + __asm __volatile ("ldstub %1, %0" \ + : "=r" (__old_lock), \ + "=m" (__sparc32_atomic_locks[__idx]) \ + : "m" (__sparc32_atomic_locks[__idx]) \ + : "memory"); \ + while (__old_lock); \ + } \ + while (0) + +#define __sparc32_atomic_do_unlock(addr) \ + do \ + { \ + __sparc32_atomic_locks[(((long) addr >> 2) \ + ^ ((long) addr >> 12)) & 63] = 0; \ + __asm __volatile ("" ::: "memory"); \ + } \ + while (0) + +#define __sparc32_atomic_do_lock24(addr) \ + do \ + { \ + unsigned int __old_lock; \ + do \ + __asm __volatile ("ldstub %1, %0" \ + : "=r" (__old_lock), "=m" (*(addr)) \ + : "m" (*(addr)) \ + : "memory"); \ + while (__old_lock); \ + } \ + while (0) + +#define __sparc32_atomic_do_unlock24(addr) \ + do \ + { \ + *(char *) (addr) = 0; \ + __asm __volatile ("" ::: "memory"); \ + } \ + while (0) + + +#ifndef SHARED +# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +({ \ + register __typeof (*(mem)) __acev_tmp __asm ("%g6"); \ + register __typeof (mem) __acev_mem __asm ("%g1") = (mem); \ + register __typeof (*(mem)) __acev_oldval __asm ("%g5"); \ + __acev_tmp = (newval); \ + __acev_oldval = (oldval); \ + /* .word 0xcde05005 is cas [%g1], %g5, %g6. Can't use cas here though, \ + because as will then mark the object file as V8+ arch. */ \ + __asm __volatile (".word 0xcde05005" \ + : "+r" (__acev_tmp), "=m" (*__acev_mem) \ + : "r" (__acev_oldval), "m" (*__acev_mem), \ + "r" (__acev_mem) : "memory"); \ + __acev_tmp; }) +#endif + +/* The only basic operation needed is compare and exchange. */ +#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + if (__acev_ret == (oldval)) \ + *__acev_memp = __acev_newval; \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ __typeof (mem) __aceb_memp = (mem); \ + int __aceb_ret; \ + __typeof (*mem) __aceb_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__aceb_memp); \ + __aceb_ret = 0; \ + if (*__aceb_memp == (oldval)) \ + *__aceb_memp = __aceb_newval; \ + else \ + __aceb_ret = 1; \ + __sparc32_atomic_do_unlock (__aceb_memp); \ + __aceb_ret; }) + +#define __v7_exchange_acq(mem, newval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + *__acev_memp = __acev_newval; \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +#define __v7_exchange_and_add(mem, value) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + *__acev_memp = __acev_ret + (value); \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +/* Special versions, which guarantee that top 8 bits of all values + are cleared and use those bits as the ldstub lock. */ +#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock24 (__acev_memp); \ + __acev_ret = *__acev_memp & 0xffffff; \ + if (__acev_ret == (oldval)) \ + *__acev_memp = __acev_newval; \ + else \ + __sparc32_atomic_do_unlock24 (__acev_memp); \ + __asm __volatile ("" ::: "memory"); \ + __acev_ret; }) + +#define __v7_exchange_24_rel(mem, newval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock24 (__acev_memp); \ + __acev_ret = *__acev_memp & 0xffffff; \ + *__acev_memp = __acev_newval; \ + __asm __volatile ("" ::: "memory"); \ + __acev_ret; }) + +#ifdef SHARED + +/* When dynamically linked, we assume pre-v9 libraries are only ever + used on pre-v9 CPU. */ +# define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ + __v7_compare_and_exchange_val_acq (mem, newval, oldval) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + __v7_compare_and_exchange_bool_acq (mem, newval, oldval) + +# define atomic_exchange_acq(mem, newval) \ + __v7_exchange_acq (mem, newval) + +# define atomic_exchange_and_add(mem, value) \ + __v7_exchange_and_add (mem, value) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ \ + if (sizeof (*mem) != 4) \ + abort (); \ + __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); }) + +# define atomic_exchange_24_rel(mem, newval) \ + ({ \ + if (sizeof (*mem) != 4) \ + abort (); \ + __v7_exchange_24_rel (mem, newval); }) + +#else + + + +/* + Here's what we'd like to do: + + In libc.a/libpthread.a etc. we don't know if we'll be run on + pre-v9 or v9 CPU. To be interoperable with dynamically linked + apps on v9 CPUs e.g. with process shared primitives, use cas insn + on v9 CPUs and ldstub on pre-v9. + + However, we have no good way to test at run time that I know of, + so resort to the lowest common denominator (v7 ops) -austinf + */ +#define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ + else \ + __acev_wret \ + = __v7_compare_and_exchange_val_acq (mem, newval, oldval); \ + __acev_wret; }) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ \ + int __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + { \ + __typeof (oldval) __acev_woldval = (oldval); \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, \ + __acev_woldval) \ + != __acev_woldval; \ + } \ + else \ + __acev_wret \ + = __v7_compare_and_exchange_bool_acq (mem, newval, oldval); \ + __acev_wret; }) + +# define atomic_exchange_rel(mem, newval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + { \ + __typeof (mem) __acev_wmemp = (mem); \ + __typeof (*(mem)) __acev_wval = (newval); \ + do \ + __acev_wret = *__acev_wmemp; \ + while (__builtin_expect \ + (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\ + __acev_wval, \ + __acev_wret) \ + != __acev_wret, 0)); \ + } \ + else \ + __acev_wret = __v7_exchange_acq (mem, newval); \ + __acev_wret; }) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ + else \ + __acev_wret \ + = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\ + __acev_wret; }) + +# define atomic_exchange_24_rel(mem, newval) \ + ({ \ + __typeof (*mem) __acev_w24ret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_w24ret = atomic_exchange_rel (mem, newval); \ + else \ + __acev_w24ret = __v7_exchange_24_rel (mem, newval); \ + __acev_w24ret; }) + +#endif + +#endif /* bits/atomic.h */ diff --git a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h index 1dbfa2b55..2d8cdd78b 100644 --- a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h @@ -36,7 +36,7 @@ #undef __UCLIBC_HAVE_ASM_GLOBAL_DOT_NAME__ /* define if target supports CFI pseudo ops */ -#undef __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ /* define if target supports IEEE signed zero floats */ #define __UCLIBC_HAVE_SIGNED_ZERO__ diff --git a/libc/sysdeps/linux/sparc/clone.S b/libc/sysdeps/linux/sparc/clone.S index 0e41ee0cb..2b6609531 100644 --- a/libc/sysdeps/linux/sparc/clone.S +++ b/libc/sysdeps/linux/sparc/clone.S @@ -1,4 +1,5 @@ -/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson (rth@tamu.edu). @@ -20,47 +21,87 @@ /* clone() is even more special than fork() as it mucks with stacks and invokes a function in the right context after its all over. */ -#include <features.h> +#include <asm/errno.h> #include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 -.text -.global clone -.type clone,%function -.align 4 +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, void *tls, pid_t *ctid); */ -clone: + .text +ENTRY (__clone) save %sp,-96,%sp + cfi_def_cfa_register(%fp) + cfi_window_save + cfi_register(%o7, %i7) /* sanity check arguments */ - tst %i0 - be __error - orcc %i1,%g0,%o1 - be __error - mov %i2,%o0 + orcc %i0,%g0,%g2 + be .Leinval + orcc %i1,%g0,%o1 + be .Leinval + mov %i2,%o0 + + /* The child_stack is the top of the stack, allocate one + whole stack frame from that as this is what the kernel + expects. */ + sub %o1, 96, %o1 + mov %i3, %g3 + mov %i2, %g4 + + /* ptid */ + mov %i4,%o2 + /* tls */ + mov %i5,%o3 + /* ctid */ + ld [%fp+92],%o4 /* Do the system call */ set __NR_clone,%g1 ta 0x10 - bcs __error - tst %o1 + bcs .Lerror + tst %o1 bne __thread_start - nop - ret - restore %o0,%g0,%o0 - -__error: - jmp __syscall_error + nop + jmpl %i7 + 8, %g0 + restore %o0,%g0,%o0 -.size clone,.-clone - -.type __thread_start,%function +.Leinval: + mov EINVAL, %o0 +.Lerror: + call __errno_location + mov %o0, %i0 + st %i0,[%o0] + jmpl %i7 + 8, %g0 + restore %g0,-1,%o0 +END(__clone) + .type __thread_start,@function __thread_start: - call %i0 - mov %i3,%o0 - call HIDDEN_JUMPTARGET(_exit),0 - nop +#ifdef RESET_PID + sethi %hi(CLONE_THREAD), %l0 + andcc %g4, %l0, %g0 + bne 1f + andcc %g4, CLONE_VM, %g0 + bne,a 2f + mov -1,%o0 + set __NR_getpid,%g1 + ta 0x10 +2: + st %o0,[%g7 + PID] + st %o0,[%g7 + TID] +1: +#endif + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 + call exit,0 + nop + + .size __thread_start, .-__thread_start -.size __thread_start,.-__thread_start +weak_alias (__clone, clone) diff --git a/libc/sysdeps/linux/sparc/sparcv9/clone.S b/libc/sysdeps/linux/sparc/sparcv9/clone.S new file mode 100644 index 000000000..9d101e239 --- /dev/null +++ b/libc/sysdeps/linux/sparc/sparcv9/clone.S @@ -0,0 +1,102 @@ +/* Copyright (C) 1997, 2000, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson (rth@tamu.edu). + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* clone() is even more special than fork() as it mucks with stacks + and invokes a function in the right context after its all over. */ + +#include <asm/errno.h> +#include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> + +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 + +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, void *tls, pid_t *ctid); */ + + .register %g2,#scratch + .register %g3,#scratch + + .text + +ENTRY (__clone) + save %sp, -192, %sp + cfi_def_cfa_register(%fp) + cfi_window_save + cfi_register(%o7, %i7) + + /* sanity check arguments */ + brz,pn %i0, 99f /* fn non-NULL? */ + mov %i0, %g2 + brz,pn %i1, 99f /* child_stack non-NULL? */ + mov %i2, %o0 /* clone flags */ + + /* The child_stack is the top of the stack, allocate one + whole stack frame from that as this is what the kernel + expects. Also, subtract STACK_BIAS. */ + sub %i1, 192 + 0x7ff, %o1 + mov %i3, %g3 + mov %i2, %g4 + + mov %i4,%o2 /* PTID */ + mov %i5,%o3 /* TLS */ + ldx [%fp+0x7ff+176],%o4 /* CTID */ + + /* Do the system call */ + set __NR_clone, %g1 + ta 0x6d + bcs,pn %xcc, 98f + nop + brnz,pn %o1, __thread_start + nop + jmpl %i7 + 8, %g0 + restore %o0, %g0, %o0 +99: mov EINVAL, %o0 +98: call HIDDEN_JUMPTARGET(__errno_location) + mov %o0, %i0 + st %i0, [%o0] + jmpl %i7 + 8, %g0 + restore %g0,-1,%o0 +END(__clone) + + .type __thread_start,@function +__thread_start: +#ifdef RESET_PID + sethi %hi(CLONE_THREAD), %l0 + andcc %g4, %l0, %g0 + bne,pt %icc, 1f + andcc %g4, CLONE_VM, %g0 + bne,a,pn %icc, 2f + mov -1,%o0 + set __NR_getpid,%g1 + ta 0x6d +2: st %o0,[%g7 + PID] + st %o0,[%g7 + TID] +1: +#endif + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 + call HIDDEN_JUMPTARGET(_exit),0 + nop + + .size __thread_start, .-__thread_start + +weak_alias (__clone, clone) diff --git a/libc/termios/tcdrain.c b/libc/termios/tcdrain.c index ad94803ff..e0f423138 100644 --- a/libc/termios/tcdrain.c +++ b/libc/termios/tcdrain.c @@ -19,14 +19,31 @@ #include <errno.h> #include <termios.h> #include <sys/ioctl.h> - -#ifdef __LINUXTHREADS_OLD__ -extern __typeof(tcdrain) weak_function tcdrain; -strong_alias(tcdrain,__libc_tcdrain) +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep-cancel.h> #endif +libc_hidden_proto(ioctl) + +extern __typeof(tcdrain) __libc_tcdrain; /* Wait for pending output to be written on FD. */ -int tcdrain(int fd) +int __libc_tcdrain (int fd) { +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + if (SINGLE_THREAD_P) + /* With an argument of 1, TCSBRK for output to be drain. */ + return INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1); + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* With an argument of 1, TCSBRK for output to be drain. */ + int result = INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1); + + LIBC_CANCEL_RESET (oldtype); + + return result; +#else return ioctl(fd, TCSBRK, 1); +#endif } +weak_alias(__libc_tcdrain,tcdrain) diff --git a/libc/unistd/daemon.c b/libc/unistd/daemon.c index 741672ec0..c3b563179 100644 --- a/libc/unistd/daemon.c +++ b/libc/unistd/daemon.c @@ -46,6 +46,20 @@ #include <paths.h> #include <signal.h> #include <unistd.h> +#include <not-cancel.h> +#include <errno.h> + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sys/stat.h> +#endif + +#ifdef __UCLIBC_HAS_LFS__ +#define STAT stat64 +#define FSTAT fstat64 +#else +#define STAT stat +#define FSTAT fstat +#endif #if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98) @@ -97,15 +111,40 @@ int daemon(int nochdir, int noclose) if (setsid() == -1) return -1; +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ + /* Make certain we are not a session leader, or else we + * might reacquire a controlling terminal */ + if (fork()) + _exit(0); +#endif + if (!nochdir) chdir("/"); - if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > 2) - close(fd); + if (!noclose) + { + struct STAT st; + + if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1 + && (__builtin_expect (FSTAT (fd, &st), 0) == 0)) + { + if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } else { + /* We must set an errno value since no + function call actually failed. */ + close_not_cancel_no_status (fd); + __set_errno (ENODEV); + return -1; + } + } else { + close_not_cancel_no_status (fd); + return -1; + } } return 0; } diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c index 87206648e..b3eb12021 100644 --- a/libc/unistd/sysconf.c +++ b/libc/unistd/sysconf.c @@ -33,6 +33,9 @@ #ifdef __UCLIBC_HAS_REGEX__ #include <regex.h> #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sysdep.h> +#endif #ifdef HAVE_LINUX_CPUMASK_H # include <linux/cpumask.h> @@ -881,13 +884,32 @@ long int sysconf(int name) #endif case _SC_MONOTONIC_CLOCK: -#if defined __UCLIBC_HAS_REALTIME__ && defined __NR_clock_getres - /* Check using the clock_getres system call. */ +#ifdef __NR_clock_getres + /* Check using the clock_getres system call. */ +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ + { + struct timespec ts; + INTERNAL_SYSCALL_DECL (err); + int r; + r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); + return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; + } +# else if (clock_getres(CLOCK_MONOTONIC, NULL) >= 0) return _POSIX_VERSION; + + RETURN_NEG_1; +# endif #endif +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + case _SC_THREAD_CPUTIME: +# if _POSIX_THREAD_CPUTIME > 0 + return _POSIX_THREAD_CPUTIME; +# else RETURN_NEG_1; +# endif +#endif } } libc_hidden_def(sysconf) diff --git a/libpthread/nptl/.gitignore b/libpthread/nptl/.gitignore new file mode 100644 index 000000000..e20fba840 --- /dev/null +++ b/libpthread/nptl/.gitignore @@ -0,0 +1,17 @@ +# +# Never ignore these +# +!.gitignore + +# +# Generated files +# +pthread-errnos.[hcs] +tcb-offsets.[hcs] +lowlevelbarrier.[hcs] +lowlevelcond.[hcs] +lowlevelrwlock.[hcs] +unwindbuf.[hcs] +sysdeps/pthread/pt-sigaction.c +sysdeps/pthread/pt-sigfillset.c +sysdeps/pthread/pt-sigprocmask.c diff --git a/libpthread/nptl/ChangeLog b/libpthread/nptl/ChangeLog new file mode 100644 index 000000000..7d103e655 --- /dev/null +++ b/libpthread/nptl/ChangeLog @@ -0,0 +1,7267 @@ +2005-08-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c: Don't block SIGSETXID ever. + +2005-07-11 Jakub Jelinek <jakub@redhat.com> + + [BZ #1102] + * sysdeps/pthread/pthread.h (PTHREAD_MUTEX_INITIALIZER, + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, + PTHREAD_MUTEX_ADAPTIVE_NP, PTHREAD_RWLOCK_INITIALIZER, + PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP, + PTHREAD_COND_INITIALIZER): Supply zeros for all fields + in the structure. + * Makefile (tests): Add tst-initializers1. + (CFLAGS-tst-initializers1.c): Set. + * tst-initializers1.c: New test. + +2005-07-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_rwlock_t): + Make sure __flags are located at offset 48 from the start of the + structure. + +2005-07-02 Roland McGrath <roland@redhat.com> + + * Makeconfig: Comment fix. + +2005-07-05 Jakub Jelinek <jakub@redhat.com> + + * descr.h (PTHREAD_STRUCT_END_PADDING): Define. + * sysdeps/ia64/tls.h (TLS_PRE_TCB_SIZE): If PTHREAD_STRUCT_END_PADDING + is smaller than 8 bytes, increase TLS_PRE_TCB_SIZE by 16 bytes. + (THREAD_SYSINFO, THREAD_SELF, DB_THREAD_SELF): Don't assume + TLS_PRE_TCB_SIZE is sizeof (struct pthread). + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/ia64/tcb-offsets.sym (PID, TID, MULTIPLE_THREADS_OFFSET): + Use TLS_PRE_TCB_SIZE instead of sizeof (struct pthread). + * sysdeps/unix/sysv/linux/ia64/createthread.c (TLS_VALUE): Don't + assume TLS_PRE_TCB_SIZE is sizeof (struct pthread). + +2005-06-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (tcbhead_t): Add stack_guard field. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/x86_64/tls.h (tcbhead_t): Add sysinfo and stack_guard + fields. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/s390/tls.h (tcbhead_t): Add stack_guard + field. Put in sysinfo field unconditionally. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/powerpc/tls.h (tcbhead_t): Add stack_guard field. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * sysdeps/sparc/tls.h (tcbhead_t): Add sysinfo and stack_guard + fields. + (THREAD_SET_STACK_GUARD, THREAD_COPY_STACK_GUARD): Define. + * pthread_create.c (__pthread_create_2_1): Use + THREAD_COPY_STACK_GUARD macro. + * Makefile: Add rules to build and run tst-stackguard1{,-static} + tests. + * tst-stackguard1.c: New file. + * tst-stackguard1-static.c: New file. + +2005-06-14 Alan Modra <amodra@bigpond.net.au> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO): + Invoke CGOTSETUP and CGOTRESTORE. + (CGOTSETUP, CGOTRESTORE): Define. + +2005-05-29 Richard Henderson <rth@redhat.com> + + * tst-cancel4.c (WRITE_BUFFER_SIZE): New. + (tf_write, tf_writev): Use it. + (do_test): Use socketpair instead of pipe. Set SO_SNDBUF to + the system minimum. + +2005-05-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + [IS_IN_librt] (CENABLE, CDISABLE): Use JUMPTARGET instead of + __librt_*_asynccancel@local. + +2005-05-17 Alan Modra <amodra@bigpond.net.au> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Delete + all occurrences of JUMPTARGET. Instead append @local to labels. + +2005-05-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): Define to + size/alignment of struct pthread rather than tcbhead_t. + * sysdeps/x86_64/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + * sysdeps/s390/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + * sysdeps/sparc/tls.h (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN): + Likewise. + +2005-05-19 Richard Henderson <rth@redhat.com> + + * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use + __sync_val_compare_and_swap, not explicit _si variant. + * sysdeps/ia64/pthread_spin_trylock.c (pthread_spin_trylock): Likewise. + +2005-05-03 Ulrich Drepper <drepper@redhat.com> + + [BZ #915] + * sysdeps/pthread/pthread.h: Avoid empty initializers. + +2005-05-03 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Remove explicit + .eh_frame section, use cfi_* directives. + +2005-04-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: Use <> instead + of "" includes. + +2005-04-27 Ulrich Drepper <drepper@redhat.com> + + [BZ #1075] + * tst-cancel17.c (do_test): Add arbitrary factor to make sure + aio_write blocks. + +2005-04-27 Roland McGrath <roland@redhat.com> + + * Makefile (tests): Remove tst-clock2. + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Handle + CLOCK_PROCESS_CPUTIME_ID and CLOCK_PROCESS_THREAD_ID specially, + translating to the kernel clockid_t for our own process/thread clock. + + * sysdeps/unix/sysv/linux/pthread_getcpuclockid.c: New file. + +2005-04-15 Jakub Jelinek <jakub@redhat.com> + + * old_pthread_cond_init.c: Include <errno.h>. + (__pthread_cond_init_2_0): Fail with EINVAL if COND_ATTR is + process shared or uses clock other than CLOCK_REALTIME. + * pthread_cond_init.c (__pthread_cond_init): Remove bogus comment. + +2005-04-13 David S. Miller <davem@davemloft.net> + + * sysdeps/sparc/sparc64/jmpbuf-unwind.h: New file. + * sysdeps/sparc/sparc64/clone.S: New file. + +2005-04-05 Jakub Jelinek <jakub@redhat.com> + + [BZ #1102] + * sysdeps/pthread/pthread.h (__pthread_cleanup_routine): Use + __inline instead of inline. + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_routine): Likewise. + +2005-03-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Use + functionally equivalent, but shorter instructions. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + +2005-03-28 Daniel Jacobowitz <dan@codesourcery.com> + + * sysdeps/mips/Makefile: New file. + * sysdeps/mips/nptl-sysdep.S: New file. + * sysdeps/mips/tcb-offsets.sym: New file. + * sysdeps/mips/pthread_spin_lock.S: New file. + * sysdeps/mips/pthread_spin_trylock.S: New file. + * sysdeps/mips/pthreaddef.h: New file. + * sysdeps/mips/tls.h: New file. + * sysdeps/mips/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/mips/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/mips/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/mips/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/mips/fork.c: New file. + * sysdeps/unix/sysv/linux/mips/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/vfork.S: New file. + * sysdeps/unix/sysv/linux/mips/clone.S: New file. + * sysdeps/unix/sysv/linux/mips/createthread.c: New file. + * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file. + +2005-03-23 Ulrich Drepper <drepper@redhat.com> + + [BZ #1112] + * pthread_create.c (__pthread_create_2_1): Rename syscall error + variable to scerr. + +2005-03-10 Jakub Jelinek <jakub@redhat.com> + + * tst-getpid1.c (do_test): Align stack passed to clone{2,}. + +2005-02-25 Roland McGrath <roland@redhat.com> + + * alloca_cutoff.c: Correct license text. + * tst-unload.c: Likewise. + * sysdeps/pthread/allocalim.h: Likewise. + * sysdeps/pthread/pt-initfini.c: Likewise. + * sysdeps/pthread/bits/libc-lock.h: Likewise. + * sysdeps/pthread/bits/sigthread.h: Likewise. + * sysdeps/unix/sysv/linux/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise. + +2005-02-16 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Use unsigned int * for ptr_nthreads. + +2005-02-14 Alan Modra <amodra@bigpond.net.au> + + * sysdeps/powerpc/tcb-offsets.sym (thread_offsetof): Redefine to suit + gcc4. + +2005-02-07 Richard Henderson <rth@redhat.com> + + [BZ #787] + * sysdeps/pthread/pthread.h (__sigsetjmp): Use pointer as first + argument. + +2004-11-03 Marcus Brinkmann <marcus@gnu.org> + + * sysdeps/generic/lowlevellock.h (__generic_mutex_unlock): Fix + order of arguments in invocation of atomic_add_zero. + +2005-01-26 Jakub Jelinek <jakub@redhat.com> + + [BZ #737] + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S (__new_sem_trywait): + Use direct %gs segment access or, if NO_TLS_DIRECT_SEG_REFS, + at least gotntpoff relocation and addition. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait): + Likewise. + +2005-01-06 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (init_one_static_tls): Adjust initialization of DTV + entry for static tls deallocation fix. + * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which + also contains information whether the memory pointed to is static + TLS or not. + * sysdeps/i386/tls.h: Likewise. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/sparc/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + +2004-12-27 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Use __sigemptyset. + +2004-12-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (CALL_THREAD_FCT): Maintain 16 byte alignment of + %esp. + * Makefile (tests): Add tst-align2. + * tst-align2.c: New test. + * sysdeps/i386/Makefile (CFLAGS-tst-align{,2}.c): Add + -mpreferred-stack-boundary=4. + +2004-12-18 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h: + New file removed withdrawn for the moment. + +2004-12-17 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/clone.S: New file. + * sysdeps/alpha/tcb-offsets.sym (TID_OFFSET): New. + +2004-12-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/bits/local_lim.h: New file. + Increased PTHREAD_STACK_MIN. + + * tst-context1.c (stacks): Use bigger stack size. + +2004-12-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: New file. + * sysdeps/sparc/tcb-offsets.sym: Add TID. + +2004-12-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: New file. + * sysdeps/s390/tcb-offsets.sym (TID): Add. + +2004-12-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: New file. + +2004-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/powerpc/tcb-offsets.sym: Add TID. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: New file. + + * tst-getpid1.c: If child crashes, report this first. Print which + signal. + +2004-12-09 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Also unblock + SIGSETXID. + +2004-12-01 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_CPUTIME, + _POSIX_THREAD_CPUTIME): Define to 0. + * sysdeps/pthread/timer_create.c (timer_create): Remove unused code + handling CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID. + * sysdeps/pthread/timer_routines.c (__timer_signal_thread_pclk, + __timer_signal_thread_tclk): Remove. + (init_module): Remove their initialization. + (thread_cleanup): Remove their cleanup assertions. + * sysdeps/pthread/posix-timer.h (__timer_signal_thread_pclk, + __timer_signal_thread_tclk): Remove. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Removed. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Removed. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Removed. + +2004-12-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/tcb-offsets.sym (TID): Add. + * sysdeps/unix/sysv/linux/ia64/clone2.S: New file. + + * Makefile (tests): Add tst-getpid2. + * tst-getpid1.c (TEST_CLONE_FLAGS): Define. + (do_test): Use it. Use __clone2 instead of clone on ia64. + * tst-getpid2.c: New test. + +2004-12-07 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/clone.S: New file. + +2004-12-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-getpid1. + * tst-getpid1.c: New file. + * sysdeps/unix/sysv/linux/i386/clone.S: New file. + * sysdeps/unix/sysv/linux/x86_64/clone.S: New file. + +2004-12-02 Roland McGrath <roland@redhat.com> + + * Makefile (libpthread-nonshared): Variable removed. + ($(objpfx)libpthread_nonshared.a): Target removed. + ($(inst_libdir)/libpthread_nonshared.a): Likewise. + These are now handled by generic magic from + libpthread-static-only-routines being set. + +2004-11-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_PRIORITIZED_IO, + _POSIX2_CHAR_TERM, _POSIX_THREAD_PRIO_INHERIT, + _POSIX_THREAD_PRIO_PROTECT): Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2004-11-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_ADVISORY_INFO, + _POSIX_SPORADIC_SERVER, _POSIX_THREAD_SPORADIC_SERVER, _POSIX_TRACE, + _POSIX_TRACE_EVENT_FILTER, _POSIX_TRACE_INHERIT, _POSIX_TRACE_LOG, + _POSIX_TYPED_MEMORY_OBJECTS, _POSIX_IPV6, _POSIX_RAW_SOCKETS): Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2004-11-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/Makefile [nptl]: Define CFLAGS-pthread_create.c. + + * Makefile (libpthread-routines): Add pthread_setschedprio. + * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setschedprio. + * sysdeps/pthread/pthread.h: Declare pthread_setschedprio. + * pthread_setschedprio.c: New file. + +2004-11-20 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (pthread_cancel): Add PTHREAD_STATIC_FN_REQUIRE. + * pthread_cancel.c (pthread_create): Likewise. + + * Makefile (libpthread-routines): Add vars. + * sysdeps/pthread/createthread.c (__pthread_multiple_threads): Remove. + * init.c (__default_stacksize, __is_smp): Remove. + * vars.c: New file. + * pthreadP.h (__find_thread_by_id): If !SHARED, add weak_function + and define a wrapper macro. + (PTHREAD_STATIC_FN_REQUIRE): Define. + * allocatestack.c (__find_thread_by_id): Undefine. + * pthread_create (__pthread_keys): Remove. + (pthread_mutex_lock, pthread_mutex_unlock, pthread_once, + pthread_key_create, pthread_setspecific, pthread_getspecific): Add + PTHREAD_STATIC_FN_REQUIRE. + +2004-11-18 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tls.h (DB_THREAD_SELF): Set the correct bias + parameter to REGISTER macro. + +2004-11-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c (__start_helper_thread): + Make sure SIGCANCEL is blocked as well. + +2004-11-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/setxid.h: New file. + * sysdeps/pthread/pthread-functions.h (HAVE_PTR__NPTL_SETXID): Remove. + (struct xid_command): Add forward decl. + (struct pthread_functions): Change return type of __nptl_setxid hook + to int. + * pthreadP.h (__nptl_setxid): Change return type to int. + * allocatestack.c (__nptl_setxid): Call INTERNAL_SYSCALL_NCS in the + calling thread, return its return value and set errno on failure. + * descr.h (struct xid_command): Change id type to long array. + + * Makefile: Add rules to build and test tst-setuid1 and + tst-setuid1-static. + * tst-setuid1.c: New test. + * tst-setuid1-static.c: New test. + +2004-11-10 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-exit3. + * tst-exit3.c: New test. + +2004-11-09 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-exit2. + * tst-exit2.c: New file. + +2004-11-09 Roland McGrath <roland@redhat.com> + + [BZ #530] + * sysdeps/pthread/createthread.c (do_clone): Increment __nptl_nthreads + here, before calling clone. + * pthread_create.c (start_thread): Don't do it here. + +2004-11-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h: Include <errno.h>. + +2004-10-29 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): + Set ETIMEDOUT to errno when time is up. Tweak to avoid + assembler warning. + +2004-10-28 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (__pthread_create_2_1): Avoid leaking stacks + if sched_priority is not between minprio and maxprio. + +2004-10-25 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Use clock_gettime syscall if exists. + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S + (__lll_mutex_timedlock_wait): Fix a bad branch condition. + +2004-10-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h (is_smp_system): Use + not-cancelable I/O functions. + +2004-10-21 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S + (__lll_mutex_timedlock_wait): If woken but cannot get the lock, + make sure 2 is stored in the futex and we looked at the old value. + Fix a few other problems to return the correct value. + +2004-10-14 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (thread_offsetof): Redefine to + make gcc4 happy. + +2004-10-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Include pthreadP.h instead + of pthread-functions.h and pthreaddef.h. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Change __data.__nwaiters from int to unsigned int. + + * tst-clock2.c (do_test): Don't fail if _POSIX_THREAD_CPUTIME == 0 and + sysconf (_SC_THREAD_CPUTIME) returns negative value. + + * allocatestack.c (__find_thread_by_id): Move attribute_hidden + before return type. + + * sysdeps/s390/jmpbuf-unwind.h: Include bits/wordsize.h. + (JMPBUF_CFA_UNWINDS_ADJ): Subtract 96 resp. 160 bytes from CFA. + +2004-10-06 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgrcv): Check for failure in msgget. If the + test fails, remove message queue. + (tf_msgsnd): Likewise. + +2004-10-05 Jakub Jelinek <jakub@redhat.com> + + * tst-clock1.c: Change #ifdef to #if defined. + * tst-clock2.c: Likewise. + * tst-cond11.c: Likewise. + + * sysdeps/pthread/timer_create.c (timer_create): Use + defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 instead of + defined CLOCK_PROCESS_CPUTIME_ID #ifs and similarly for + THREAD_CPUTIME. + +2004-10-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h (_POSIX_CPUTIME, + _POSIX_THREAD_CPUTIME): Define to 0. + +2004-10-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Define _POSIX_CPUTIME + and _POSIX_THREAD_CPUTIME to zero. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Likewise. + * tst-barrier2.c: Fix testing for POSIX feature. + * tst-clock1.c: Likewise. + * tst-clock2.c: Likewise. + * tst-cond11.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-flock2.c: Likewise. + * tst-mutex4.c: Likewise. + * tst-mutex9.c: Likewise. + * tst-rwlock12.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-signal1.c: Likewise. + * tst-spin2.c: Likewise. + * sysdeps/pthread/posix-timer.h: Likewise. + * sysdeps/pthread/timer_create.c: Likewise. + * sysdeps/pthread/timer_routines.c: Likewise. + +2004-10-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Address futex correctly. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_timedlock_wait): If woken but cannot get the lock, + make sure 2 is stored in the futex and we looked at the old value. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Likewise. Fix a few other problems + which might very well made the code not working at all before. + [BZ #417] + +2004-09-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't + allow SIGSETXID to be sent. + * sysdeps/pthread/sigaction.c (__sigaction): Don't allow action + for SIGSETXID to be defined. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure + SIGSETXID cannot be blocked. + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __extension__ to long long types. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2004-09-25 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Add stopped_start field. + * sysdeps/pthread/createthread.c (create_thread): Set + start_stopped flag in descriptor for new thread appropriately. + * pthread_create.c (start_thread): Only take lock to be stopped on + startup if stopped_start flag says so. + +2004-09-24 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (__pthread_create_2_1): Remember whether thread + is created detached and if yes, do not try to free the stack in case + the thread creation failed. + * sysdeps/pthread/createthread.c (do_clone): Free stack here if clone + call fails. Don't depend on INTERNAL_SYSCALL_ERRNO return zero in + case there has been no error. [BZ #405] + + * pthread_create.c (start_thread): Don't wait for scheduler data + etc to be set at the beginning of the function. The cancellation + infrastructure must have been set up. And enable async + cancellation before potentially going to sleep. [BZ #401] + +2004-09-20 Ulrich Drepper <drepper@redhat.com> + + * Versions: Remove exports for pthread_set*id_np functions. + * sysdeps/pthread/pthread.h: Remove pthread_set*id_np prototypes + for now. + * Makefile: Don't build pthread_set*id code for now. + +2004-09-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/allocrtsig.c: Allocate second signal for + internal use. + * allocatestack.c (__nptl_setxid): New function. + * descr.h (struct xid_command): Define type. + * init.c (pthread_functions): Add ptr__nptl_setxid initialization. + (sighandler_setxid): New function. + (__pthread_initialize_minimal): Register sighandler_setxid for + SIGCANCEL. + * pt-allocrtsig.c: Update comment. + * pthreadP.h: Define SIGSETXID. Declare __xidcmd variable. + Declare __nptl_setxid. + * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_setxid. + * sysdeps/pthread/pthread.h: Declare pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * pthread_setgid_np.c: New file. + * pthread_setuid_np.c: New file. + * pthread_setegid_np.c: New file. + * pthread_seteuid_np.c: New file. + * pthread_setregid_np.c: New file. + * pthread_setreuid_np.c: New file. + * pthread_setresgid_np.c: New file. + * pthread_setresuid_np.c: New file. + * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * Makefile (libpthread-routines): Add pthread_setuid, pthread_seteuid, + pthread_setreuid, pthread_setresuid, pthread_setgid, pthread_setegid, + pthread_setregid, and pthread_setresgid. + +2004-09-18 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Return EAGAIN instead of + ENOMEM when out of memory. + +2004-09-10 Roland McGrath <roland@redhat.com> + + [BZ #379] + * allocatestack.c (allocate_stack): Remove [__ASSUME_CLONE_STOPPED] + code, since we don't try to use the broken CLONE_STOPPED any more. + * pthread_create.c (start_thread): Likewise. + +2004-09-15 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/vfork.S: Use libc_hidden_def. + +2004-09-01 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h + (__libc_unwind_longjmp): Delete macro and declare as function. + * sysdeps/unix/sysv/linux/ia64/Makefile (sysdep_routines): Mention + __ia64_longjmp, sigstack_longjmp, and __sigstack_longjmp for + nptl directory. + * sysdeps/unix/sysv/linux/ia64/__ia64_longjmp.S: New file. + * sysdeps/unix/sysv/linux/ia64/__sigstack_longjmp.c: New file. + * sysdeps/unix/sysv/linux/ia64/unwind_longjmp.c: New file. + +2004-09-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Make rwlock prototypes available also + for __USE_XOPEN2K. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define rwlock + types also for __USE_XOPEN2K. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + [BZ #320] + +2004-09-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h + (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Make safe for C++. + (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise. + [BZ #375] + +2004-09-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Allow + PSEUDO to be used with . prefix. + + * sysdeps/unix/sysv/linux/alpha/pthread_once.c (__pthread_once): + Use atomic_increment instead of atomic_exchange_and_add. + * sysdeps/unix/sysv/linux/sparc/pthread_once.c (__pthread_once): + Likewise. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once): + Likewise. + + * allocatestack.c (allocate_stack): Use atomic_increment_val + instead of atomic_exchange_and_add. + * sysdeps/unix/sysv/linux/sem_post.c (__new_sem_post): Likewise. + * sysdeps/unix/sysv/linux/powerpc/sem_post.c (__new_sem_post): + Likewise. + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Likewise. + + * sysdeps/pthread/pthread.h (pthread_once): Remove __THROW since + the initialization function might throw. + +2005-09-05 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P): + Move definition inside libpthread, libc, librt check. Provide + definition for rtld. + +2004-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/alpha/jmpbuf-unwind.h: Define __libc_unwind_longjmp. + * sysdeps/i386/jmpbuf-unwind.h: Likewise + * sysdeps/powerpc/jmpbuf-unwind.h: Likewise. + * sysdeps/s390/jmpbuf-unwind.h: Likewise. + * sysdeps/sh/jmpbuf-unwind.h: Likewise. + * sysdeps/sparc/sparc32/jmpbuf-unwind.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Likewise. + * sysdeps/x86_64/jmpbuf-unwind.h: Likewise. + * unwind.c: Use it. + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Rename __data.__clock to __data.__nwaiters, make it unsigned int. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: + Decrement __nwaiters. If pthread_cond_destroy has been called and + this is the last waiter, signal pthread_cond_destroy caller and + avoid using the pthread_cond_t structure after unlock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + Read clock type from the least significant bits of __nwaiters instead + of __clock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/internaltypes.h: Define COND_CLOCK_BITS. + +2004-08-31 Jakub Jelinek <jakub@redhat.com> + + [BZ #342] + * Makefile (tests): Add tst-cond20 and tst-cond21. + * tst-cond20.c: New test. + * tst-cond21.c: New test. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h + (pthread_cond_t): Rename __data.__clock to __data.__nwaiters, make + it unsigned int. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_clock): Remove. + (cond_nwaiters): New. + (clock_bits): New. + * pthread_cond_destroy.c (__pthread_cond_destroy): Return EBUSY + if there are waiters not signalled yet. + Wait until all already signalled waiters wake up. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Decrement + __nwaiters. If pthread_cond_destroy has been called and this is the + last waiter, signal pthread_cond_destroy caller and avoid using + the pthread_cond_t structure after unlock. + (__pthread_cond_wait): Increment __nwaiters in the beginning, + decrement it when leaving. If pthread_cond_destroy has been called + and this is the last waiter, signal pthread_cond_destroy caller. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. Read clock type from the least significant bits of + __nwaiters instead of __clock. + * pthread_condattr_setclock.c (pthread_condattr_setclock): Check + whether clock ID can be encoded in COND_CLOCK_BITS bits. + * pthread_condattr_getclock.c (pthread_condattr_getclock): Decode + clock type just from the last COND_CLOCK_BITS bits of value. + * pthread_cond_init.c (__pthread_cond_init): Initialize __nwaiters + instead of __clock, just from second bit of condattr's value. + +2004-08-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Include + bits/wordsize.h. Make the header match i386 header when __WORDSIZE + != 64. + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise. + +2004-08-15 Roland McGrath <roland@frob.com> + + * pthread_atfork.c: Update copyright terms including special exception + for these trivial files, which are statically linked into executables + that use dynamic linking for the significant library code. + +2004-08-09 Jakub Jelinek <jakub@redhat.com> + + * DESIGN-rwlock.txt: Add decreasing of nr_readers_queued to + pthread_rwlock_rdlock. + * sysdeps/pthread/pthread_rwlock_rdlock (__pthread_rwlock_rdlock): + Decrease __nr_readers_queued after reacquiring lock. + * sysdeps/pthread/pthread_rwlock_timedrdlock + (pthread_rwlock_timedrdlock): Likewise. + Reported by Bob Cook <bobcook47@hotmail.com>. + +2004-08-11 Jakub Jelinek <jakub@redhat.com> + + * tst-rwlock14.c (tf): Read main thread handle from *ARG + before pthread_barrier_wait. + +2004-08-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: + Remove unnecessary exception handling data. + +2004-07-23 Jakub Jelinek <jakub@redhat.com> + + [BZ #284] + * sysdeps/pthread/pthread.h (pthread_getcpuclockid): Use __clockid_t + instead of clockid_t. + +2004-07-21 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)multidir.mk): Use $(make-target-directory). + +2004-07-19 Roland McGrath <roland@redhat.com> + + * tst-cancel4.c (tf_waitid): Use WEXITED flag bit if available. + +2004-07-02 Roland McGrath <roland@redhat.com> + + * configure: Don't exit. + +2004-07-14 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Check for invalid nanosecond in + timeout value. + +2004-07-07 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build and run tst-fini1. + * tst-fini1.c: New file. + * tst-fini1mod.c: New file. + +2004-07-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define NO_CANCELLATION + if no cancellation support is needed. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: Likewise. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Define __NR_futex + only if not already defined. + +2004-07-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_unlock): Use + constraint "m" instead of "0" for futex. + + * shlib-versions: Add powerpc64-.*-linux.*. + +2004-07-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S + (pthread_rwlock_timedrdlock): Use cmpq instead of cmpl to check + for valid tv_nsec. + * tst-rwlock14.c (do_test): Test for invalid tv_nsec equal to + 1 billion and 64-bit tv_nsec which is valid when truncated to 32 + bits. + +2004-06-29 Roland McGrath <roland@redhat.com> + + * Banner: NPTL no longer has its own version number. + * Makefile (nptl-version): Variable removed. + * sysdeps/pthread/Makefile (CFLAGS-confstr.c): Set LIBPTHREAD_VERSION + using $(version), the glibc version number. + +2004-06-29 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once): + Fix branch offset for a PLT entry. + * sysdeps/unix/sysv/linux/sh/sem_post.S (__new_sem_post): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S (__new_sem_trywait): + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): + Likewise. + +2004-06-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define + unconditionally. + +2004-06-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_rwlock_timedwrlock.c + (pthread_rwlock_timedwrlock): Return EINVAL if tv_nsec is negative, + instead of tv_sec. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c + (pthread_rwlock_timedrdlock): Likewise. + +2004-06-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue): + Set __r7 to val, not mutex. + +2004-06-27 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add rules to build tst-rwlock14. + * tst-rwlock14.c: New file. + +2004-06-24 Boris Hu <boris.hu@intel.com> + + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Add timeout validation + check. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + +2004-06-19 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Fix + assembler in last patch. + +2004-06-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Also check for negativ nanoseconds. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Check for invalid nanosecond in + timeout value. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * tst-cond19.c: New file. + * Makefile: Add rules to build and run tst-cond19. + +2004-06-15 Steven Munroe <sjmunroe@us.ibm.com> + + * tst-context1.c (GUARD_PATTERN): Defined. + (tst_context_t): Define struct containing ucontext_t & guard words. + (ctx): Declare as an array of tst_context_t. + (fct): Verify uc_link & guard words are still valid. + (tf): Initialize guard words in ctx. Adjust ctx refs for new struct. + +2004-06-13 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + +2004-06-08 Jakub Jelinek <jakub@redhat.com> + + * pthread_mutexattr_getpshared.c (pthread_mutex_getpshared): Fix + comment typo. + * pthread_mutexattr_gettype.c (pthread_mutexattr_gettype): Likewise. + * pthread_mutexattr_init.c (__pthread_mutexattr_init): Likewise. + * pthread_mutexattr_settype.c (__pthread_mutexattr_settype): Likewise. + * pthread_mutexattr_setpshared.c (pthread_mutexattr_setpshared): + Likewise. Reported by Bob Cook <bobcook47@hotmail.com>. + +2004-06-11 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_compare_and_swap): + Add memory clobber to inline assembly. + (__lll_mutex_trylock): Likewise. + (__lll_mutex_cond_trylock): Likewise. + +2004-06-07 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (lll_futex_requeue): + Pass val argument as 6th system call argument in %r7. + +2004-05-21 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cond16. + * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_futex): Add. + * pthread_cond_init.c (__pthread_cond_init): Clear __data.__futex. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/i386/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/i386/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/i386/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, return 1 unconditionally + for the time being. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (FUTEX_CMP_REQUEUE): + Define. + (lll_futex_requeue): Add val argument, use FUTEX_CMP_REQUEUE + internally. Return non-zero if error, zero if success. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Add __data.__futex field, reshuffle __data.__clock. + * sysdeps/pthread/pthread_cond_signal.c (__pthread_cond_signal): + Increment __futex at the same time as __wakeup_seq or __total_seq. + Pass address of __futex instead of address of low 32-bits of + __wakeup_seq to futex syscall. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + Pass __futex value from before releasing internal lock + to FUTEX_WAIT. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. Avoid unnecessary shadowing of variables. + * sysdeps/pthread/pthread_cond_broadcast.c (__pthread_cond_broadcast): + Set __futex to 2 * __total_seq. Pass __futex value from before the + unlock and __futex address instead of address of low 32-bits of + __wakeup_seq to futex_requeue macro, adjust for new return value + meaning. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S + (__pthread_cond_signal): Increment __futex at the same time as + __wakeup_seq or __total_seq. Pass address of __futex instead of + address of low 32-bits of __wakeup_seq to futex syscall. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. Pass __futex value from before + releasing internal lock to FUTEX_WAIT. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (FUTEX_CMP_REQUEUE): Define. + (__pthread_cond_broadcast): Set __futex to 2 * __total_seq. + Use FUTEX_CMP_REQUEUE operation instead of FUTEX_REQUEUE. + Pass __futex value from before the unlock and __futex address instead + of address of low 32-bits of __wakeup_seq to futex syscall. + Fallback to FUTEX_WAKE all on any errors. + +2004-06-03 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_mutex_lock): + Add nop to align the end of critical section. + (lll_mutex_cond_lock, lll_mutex_timedlock): Likewise. + +2004-06-01 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __broadcast_seq field. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Mark + all waiters as woken with woken_seq and bump broadcast counter. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use new + __broadcast_seq. Increment __woken_seq correctly when cleanuped. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + Comment typo fixes. Avoid returning -ETIMEDOUT. + +2004-06-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Fix access to saved broadcast_seq value. + Reported by Kaz Kojima. + +2004-05-25 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/aio_misc.h: New file. + +2004-05-21 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Compare + __broadcast_seq with bc_seq after acquiring internal lock instead of + before it. + +2004-05-18 Jakub Jelinek <jakub@redhat.com> + + * Makefile (.NOTPARALLEL): Only serialize make check/xcheck, not + compilation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Avoid returning -ETIMEDOUT. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthread_cond_t): Add __data.__broadcast_seq field. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (FRAME_SIZE): Define. + (__pthread_cond_timedwait): Use it. Store/check broadcast_seq. + Comment typo fixes. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S (FRAME_SIZE): + Define. + (__pthread_cond_wait): Use it. Store/check broadcast_seq. Comment + typo fixes. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Increment broadcast_seq. Comment typo + fixes. + +2004-05-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add broadcast_seq entry. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t): + Add __broadcast_seq field. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Mark + all waiters as woken with woken_seq and bump broadcast counter. + * sysdeps/pthread/pthread_cond_broadcast.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use new + __broadcast_seq field. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * pthread_cond_init.c: Initialize __broadcast_seq field. + * Makefile (tests): Add tst-cond17 and tst-cond18. + Add .NOTPARALLEL goal. + * tst-cond16.c: New file. From Jakub. + * tst-cond17.c: New file. From Jakub. + * tst-cond18.c: New file. From Jakub. + +2004-05-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Correct some + unwind info. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: + Parametrize frame size. Correct some unwind info. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + +2004-05-04 Jakub Jelinek <jakub@redhat.com> + + * tst-stack3.c: Note testing functionality beyond POSIX. + +2004-05-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (USE___THREAD): + Change conditional from ifdef to if. + +2004-04-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SYSDEP_CANCEL_ERRNO, + SYSDEP_CANCEL_ERROR): Define. + (PSEUDO): Use it. + +2004-05-01 Jakub Jelinek <jakub@redhat.com> + + * Versions (libpthread): Remove __pthread_cleanup_upto@@GLIBC_PRIVATE. + +2004-04-20 Jakub Jelinek <jakub@redhat.com> + + * sem_unlink.c (sem_unlink): Change EPERM into EACCES. + +2004-04-19 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Add frame info. + Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Remove unneeded frame + info. Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + +2004-04-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c: Make sure helper + thread has all signals blocked. + +2004-04-18 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h + (SEM_VALUE_MAX): Add missing brace. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/Makefile (tests): Add tst-mqueue8x + in rt subdir. + (CFLAGS-tst-mqueue8x.c): Add -fexceptions. + * sysdeps/pthread/tst-mqueue8x.c: New test. + * tst-cancel4.c: Update comment about message queues. + + * sysdeps/pthread/timer_gettime.c (timer_gettime): For expired timer + return it_value { 0, 0 }. + * sysdeps/pthread/timer_create.c (timer_create): Handle SIGEV_NONE + like SIGEV_SIGNAL. + * sysdeps/pthread/timer_routines.c (thread_expire_timer): Remove + assertion for SIGEV_NONE. + (thread_attr_compare): Compare all attributes, not just a partial + subset. + +2004-04-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/mq_notify.c: Include stdlib.h. + +2004-04-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h (SEM_VALUE_MAX): + Just use a plain number. + * sysdeps/unix/sysv/linux/i386/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: Likewise. + +2004-04-16 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Remove unneeded + frame info. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + +2004-04-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/timer_routines.c: Include errno.h. + (timer_helper_thread): Use inline rt_sigtimedwait syscall instead + of calling sigwaitinfo. + +2004-04-16 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Set reported_guardsize + unconditionally. + * pthread_getattr_np.c (pthread_getattr_np): Use + reported_guardsize instead of guardsize. + * descr.h (struct pthread): Add reported_guardsize field. + +2004-04-13 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/mq_notify.c: Shut up GCC warning. + +2004-04-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/mq-notify.c: New file. + +2004-04-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING): + Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + +2004-04-04 Ulrich Drepper <drepper@redhat.com> + + * tst-context1.c (fct): Check whether correct stack is used. + +2004-04-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Never use + matching constraints for asm mem parameters. + + * tst-clock2.c (tf): Don't define unless needed. + +2004-03-30 H.J. Lu <hongjiu.lu@intel.com> + + * Makefile (link-libc-static): Use $(static-gnulib) instead of + $(gnulib). + +2004-03-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_deallocate_tsd. + * init.c (pthread_functions): Add ptr__nptl_deallocate_tsd. + * pthreadP.h: Declare __nptl_deallocate_tsd. + * pthread_create.c (deallocate_tsd): Remove to __nptl_deallocate_tsd. + Adjust caller. + + * Makefile (tests): Add tst-tsd5. + * tst-tsd5.c: New file. + +2004-03-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (__pthread_attr_setaffinity_old): Prepend GLIBC_ to version names + is SHLIB_COMPAT check. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c + (__pthread_attr_getaffinity_old): Likewise. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_old): Likewise. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_old): Likewise. + +2004-03-26 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (_make_stacks_executable): Call + _dl_make_stack_executable first. + +2004-03-24 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/pthread_spin_lock.c (pthread_spin_lock): Use "m" + constraint instead of "0". + +2004-03-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_cond_trylock): Define as wrapper around __lll_cond_trylock. + + * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Reorganize + code to avoid warning. + +2004-03-24 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (__pthread_attr_setaffinity_old): Remove const. + +2004-03-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/smp.h: New file. + * sysdeps/unix/sysv/linux/sh/smp.h: New file. + * init.c: Define __is_smp. + (__pthread_initialize_minimal_internal): Call is_smp_system to + initialize __is_smp. + * pthreadP.h: Declare __is_smp. + Define MAX_ADAPTIVE_COUNT is necessary. + * pthread_mutex_init.c: Add comment regarding __spins field. + * pthread_mutex_lock.c: Implement adaptive mutex type. + * pthread_mutex_timedlock.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_mutex_t): + Add __spins field. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Define + lll_mutex_cond_trylock. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + Define BUSY_WAIT_NOP. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * tst-mutex5.c: Add support for testing adaptive mutexes. + * tst-mutex7.c: Likewise. + * tst-mutex5a.c: New file. + * tst-mutex7a.c: New file. + * Makefile (tests): Add tst-mutex5a and tst-mutex7a. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_timedlock_wait): Preserve r8 and r9 since the + vgettimeofday call might destroy the content. + + * sysdeps/ia64/pthread_spin_lock.c (pthread_spin_lock): Use hint + @pause in the loop. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock): + No need to restrict type of ret. Make it int. Add comment. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_mutex_trylock): + Remove unnecessary setne instruction. + +2004-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_new): Use INT_MAX instead of UINT_MAX. + * pthread_getattr_np.c (pthread_getattr_np): Double size every cycle. + If realloc fails, break out of the loop. + +2004-03-20 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_old): Fix interface. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (__pthread_getaffinity_old): Likewise. + + * sysdeps/unix/sysv/linux/pthread_setaffinity.c + (__pthread_setaffinity_new): Remove duplicate declaration. + +2004-03-20 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (CENABLE): Save + the return value to a safe register. + (CDISABLE): Set the function argument correctly. + +2004-03-17 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h (XCHG): Define. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S (__lll_mutex_lock_wait): + Rewrite so that only one locked memory operation per round is needed. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S + (pthread_barrier_wait): After wakeup, release lock only when the + last thread stopped using the barrier object. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. Add correct cleanup support and unwind info. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared condvars. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Update comment. + * sysdeps/unix/sysv/linux/sh/pthread_once.S (__pthread_once): + Add correct cleanup support and unwind info. + * sysdeps/unix/sysv/linux/sh/sem_wait.S (__new_sem_wait): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Add unwind + information for syscall wrappers. + +2004-03-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add + cpusetsize field, remove next. + * sysdeps/pthread/pthread.h (pthread_getaffinity_np): Add new second + parameter for size of the CPU set. + (pthread_setaffinity_np): Likewise. + (pthread_attr_getaffinity_np): Likewise. + (pthread_attr_setaffinity_np): Likewise. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: Implement + interface change, keep compatibility code. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c: Likewise. + * pthreadP.h: Remove hidden_proto for pthread_getaffinity_np. Declare + __pthread_getaffinity_np. + * Versions: Add version for changed interfaces. + * tst-attr3.c: Adjust test for interface change. + * pthread_getattr_np.c: Query the kernel about the affinity mask with + increasing buffer sizes. + * pthread_attr_destroy.c: Remove unused list handling. + * pthread_attr_init.c: Likewise. + +2004-03-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Pass missing + first argument to clock_getres so we ever enable kernel timers. + +2004-03-15 Ulrich Weigand <uweigand@de.ibm.com> + + * init.c (nptl_version): Add __attribute_used__ to nptl_version. + +2004-03-12 Richard Henderson <rth@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: Propagate + oldvalue from CENABLE to CDISABLE. + +2004-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define HOST_NAME_MAX. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: Likewise. + +2004-03-11 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tcb-offsets.sym (PID_OFFSET): New. + * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: Save/restore PID. + * sysdeps/unix/sysv/linux/alpha/vfork.S: New file. + +2004-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Use jgnl + instead of jnl instruction to jump to SYSCALL_ERROR_LABEL. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S (__vfork): Likewise. + +2004-03-11 Jakub Jelinek <jakub@redhat.com> + + * forward.c (__pthread_cond_broadcast_2_0, + __pthread_cond_destroy_2_0, __pthread_cond_init_2_0, + __pthread_cond_signal_2_0, __pthread_cond_wait_2_0, + __pthread_cond_timedwait_2_0): Use return 0 as defaction instead of 0. + +2004-03-11 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Add PID. + * sysdeps/unix/sysv/linux/sh/pt-vfork.S: Properly handle PID cache. + * sysdeps/unix/sysv/linux/sh/vfork.S: New file. + +2004-03-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: No need to + include <sysdep-cancel.h>, vfork is no cancellation point. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: Likewise. + +2004-03-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S (__vfork): Add + libc_hidden_def. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S (__vfork): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Include tcb-offsets.h. + * sysdeps/unix/sysv/linux/ia64/vfork.S (__vfork): Use DO_CALL instead + of DO_CALL_VIA_BREAK. Work around a gas problem. + + * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: Remove. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S: New file. + * sysdeps/powerpc/tcb-offsets.sym: Add PID. + + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S (__vfork): Don't use + a local register for saving old PID. Negate PID in parent upon exit. + + * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: Include + tcb-offsets.h. + (__vfork): Negate PID if non-zero and set to INT_MIN if zero + before syscall, set to the old value in the parent afterwards. + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: Include + tcb-offsets.h. + (__vfork): Negate PID if non-zero and set to INT_MIN if zero + before syscall, set to the old value in the parent afterwards. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: New file. + * sysdeps/s390/tcb-offsets.sym: Add PID. + + * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: Remove. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S: New file. + * sysdeps/sparc/tcb-offsets.sym: Add PID. + +2004-03-10 Andreas Schwab <schwab@suse.de> + + * sysdeps/ia64/tcb-offsets.sym: Add PID. + * sysdeps/unix/sysv/linux/ia64/vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Properly handle PID cache. + +2004-03-09 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel20.c (do_one_test): Clear in_sh_body first. + * tst-cancel21.c (do_one_test): Likewise. + Reported by Gordon Jin <gordon.jin@intel.com>. + +2004-02-09 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/vfork.S (SAVE_PID): Negate PID + if non-zero and set to INT_MIN if zero. + * sysdeps/unix/sysv/linux/x86_64/vfork.S (SAVE_PID): Likewise. + * sysdeps/unix/sysv/linux/i386/pt-vfork.S: Include tcb-offsets.h. + (SAVE_PID, RESTORE_PID): Define. + (__vfork): Use it. + * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: Include tcb-offsets.h. + Use relative path to avoid including NPTL i386/vfork.S. + (SAVE_PID, RESTORE_PID): Define. + * sysdeps/unix/sysv/linux/raise.c: Include limits.h. + (raise): Handle THREAD_SELF->pid INT_MIN the same as 0. + * Makefile (tests): Add tst-vfork1, tst-vfork2, tst-vfork1x and + tst-vfork2x. + (tests-reverse): Add tst-vfork1x and tst-vfork2x. + * tst-vfork1.c: New test. + * tst-vfork2.c: New test. + * tst-vfork1x.c: New test. + * tst-vfork2x.c: New test. + +2004-03-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tcb-offsets.sym: Add PID. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * sysdeps/unix/sysv/linux/i386/vfork.S: New file. + * sysdeps/unix/sysv/linux/x86_64/vfork.S: New file. + +2004-03-08 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/Versions: Remove leading tabs. + +2004-03-08 H.J. Lu <hongjiu.lu@intel.com> + + * sysdeps/s390/tls.h (INIT_SYSINFO): _dl_sysinfo is now in + _rtld_global_ro. + +2004-03-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/ia64/tls.h (INIT_SYSINFO): _dl_sysinfo is now in + _rtld_global_ro. + + * tst-once4.c: Remove unnecessary macro definition. + + * tst-mutex7.c (do_test): Limit thread stack size. + * tst-once2.c (do_test): Likewise. + * tst-tls3.c (do_test): Likewise. + * tst-tls1.c (do_test): Likewise. + * tst-signal3.c (do_test): Likewise. + * tst-kill6.c (do_test): Likewise. + * tst-key4.c (do_test): Likewise. + * tst-join4.c (do_test): Likewise. + * tst-fork1.c (do_test): Likewise. + * tst-context1.c (do_test): Likewise. + * tst-cond2.c (do_test): Likewise. + * tst-cond10.c (do_test): Likewise. + * tst-clock2.c (do_test): Likewise. + * tst-cancel10.c (do_test): Likewise. + * tst-basic2.c (do_test): Likewise. + * tst-barrier4.c (do_test): Likewise. + +2004-03-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: Use GLRO instead of GL where appropriate. + +2004-03-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Optimize wakeup test. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. + +2004-02-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Optimize a bit more. Just one copy of + the atomic instruction needed. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_lock_wait): Likewise. + +2004-02-28 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond14 and tst-cond15. + * tst-cond14.c: New file. + * tst-cond15.c: New file. + +2004-02-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Remove use of + CLONE_STOPPED. We cannot use SIGCONT which means CLONE_STOPPED + needs to be implemented differently to be useful. + +2004-02-26 Ulrich Drepper <drepper@redhat.com> + + * pthread_attr_setschedparam.c: Don't test priority against limits + here. Set ATTR_FLAG_SCHED_SET flag. + * pthread_attr_setschedpolicy.c: Set ATTR_FLAG_POLICY_SET flag. + * pthread_create.c (__pthread_create_2_1): Copy scheduling attributes + from parent thread to child. If attribute is used and scheduling + parameters are not inherited, copy parameters from attribute or + compute them. Check priority value. + * pthread_getschedparam.c: If the parameters aren't known yet get + them from the kernel. + * pthread_setschedparam.c: Set ATTR_FLAG_SCHED_SET and + ATTR_FLAG_POLICY_SET flag for thread. + * sysdeps/unix/sysv/linux/internaltypes.h: Define ATTR_FLAG_SCHED_SET + and ATTR_FLAG_POLICY_SET. + + * sysdeps/pthread/createthread.c: Use tgkill if possible. + + * pthread_attr_getstackaddr.c (__pthread_attr_getstackaddr): Don't + fail if stack address hasn't been set. Just return 0. + +2004-02-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests-nolibpthread): Add tst-unload. Don't link with + libpthread for the files in this list. + (CFLAGS-tst-unload): Removed. + * tst-unload.c (do_test): Don't use complete path for + LIBPHREAD_SO. + + * Makefile: Define sonames for tst-tls5mod, tst-_res1mod1, and + tst-_res1mod2. + +2004-02-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Rewrite so that only one locked memory + operation per round is needed. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S + (__lll_mutex_lock_wait): Likewise. + +2004-02-20 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel9.c (cleanup): Don't print to stderr. + +2004-02-20 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/jmpbuf-unwind.h (_JMPBUF_UNWINDS_ADJ): Fix variable name. + +2004-02-20 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h + (__syscall_error_handler2): Call CDISABLE. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h + (__syscall_error_handler2): Call CDISABLE. + + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Release lock before the loop, don't reacquire it. + + * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h (DL_ARGV_NOT_RELRO): Define. + +2004-02-19 Andreas Schwab <schwab@suse.de> + + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Fix last change. + +2004-02-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S + (pthread_barrier_wait): After wakeup, release lock only when the + last thread stopped using the barrier object. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S + (pthread_barrier_wait): Likewise. + * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): + Likewise. + * Makefile (tests): Add tst-barrier4. + * tst-barrier4.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Perform timeout test while holding + internal lock to prevent wakeup race. + Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + +2004-02-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S + (__pthread_rwlock_unlock): Access WRITER as 32-bit value. + * Makefile (tests): Add tst-rwlock13. + * tst-rwlock13.c: New test. + +2004-02-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__condvar_tw_cleanup): Little optimization. + Patch by Dinakar Guniguntala <dgunigun@in.ibm.com>. + +2004-02-16 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: Replace libc with + libpthread as "lib" parameter to SHLIB_COMPAT. + (__novmx_siglongjmp): Fix typo in function name. + (__novmx_longjmp): Fix typo in function name. + +2004-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Add a + __builtin_expect. + + * sysdeps/generic/pt-longjmp.c: Moved to... + * sysdeps/pthread/pt-longjmp.c: ...here. New file. + +2004-01-29 Steven Munroe <sjmunroe@us.ibm.com> + + * Makefile (libpthread-routines): Add pt-cleanup. + * pt-longjmp.c: Removed. + * pt-cleanup.c: Copied __pthread_cleanup_upto to here. New file. + * sysdeps/generic/pt-longjmp.c: Copied longjmp to here. New file. + * sysdeps/unix/sysv/linux/powerpc/Versions: New file. + Version longjmp, siglongjmp for GLIBC_2.3.4. + * sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c: New File. + +2004-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Optimize. Drop internal lock earlier. + Reuse code. Add __builtin_expects. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Get internal lock in case timeout has + passed before the futex syscall. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + +2004-01-20 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c: Pretty printing. + + * sysdeps/pthread/createthread.c (create_thread): Don't add + CLONE_DETACHED bit if it is not necessary. + +2004-01-16 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c: Include ldsodefs.h. + +2004-01-16 Richard Henderson <rth@redhat.com> + + * allocatestack.c: Don't declare __libc_stack_end. + * init.c (__pthread_initialize_minimal_internal): Likewise. + * pthread_getattr_np.c (pthread_getattr_np): Likewise. + +2004-01-15 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/tls.h (tcbhead_t): Add private. + (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN, TLS_TCB_SIZE, + TLS_PRE_TCB_SIZE, TLS_TCB_ALIGN, INSTALL_DTV, INSTALL_NEW_DTV, + GET_DTV, THREAD_DTV, THREAD_SELF, DB_THREAD_SELF): Match ia64. + (TLS_TCB_OFFSET, THREAD_ID, NO_TLS_OFFSET): Remove. + (THREAD_GETMEM, THREAD_GETMEM_NC): Simplify. + (THREAD_SETMEM, THREAD_SETMEM_NC): Likewise. + * sysdeps/unix/sysv/linux/alpha/createthread.c (TLS_VALUE): Match ia64. + +2004-01-14 Ulrich Drepper <drepper@redhat.com> + + * init.c (pthread_functions): Make array const. + +2004-01-13 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (__make_stacks_executable): Change interface. + Check parameters. Pass parameter on to libc counterpart. + * pthreadP.h: Change declaration. + +2004-01-13 Richard Henderson <rth@redhat.com> + + * pthread_attr_setstack.c (__old_pthread_attr_setstack): Use + prototype form. + * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize): + Likewise. + + * sysdeps/alpha/Makefile: New file. + * sysdeps/alpha/tcb-offsets.sym: New file. + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h (SINGLE_THREAD_P): + Use MULTIPLE_THREADS_OFFSET to implement !libpthread !libc version. + + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Rewrite based + on powerpc version. + +2004-01-08 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-backtrace1. + * tst-backtrace1.c: New test. + +2003-12-11 Ulrich Weigand <uweigand@de.ibm.com> + + * sysdeps/alpha/tls.h (DB_THREAD_SELF): Pass bit size of thread + register as second parameter to the REGISTER macro. + * sysdeps/ia64/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/powerpc/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/sh/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/sparc/tls.h (DB_THREAD_SELF): Likewise. + * sysdeps/s390/tls.h (DB_THREAD_SELF): Pass __WORDSIZE as bit size + of thread register as second parameter to REGISTER macro in 64 case. + +2004-01-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Removed. + (CFLAGS-getpid.o): Defined. + (CFLAGS-getpid.os): Defined. + +2003-12-31 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c (pthread_getattr_np): Make sure stack info + returned for main thread does not overlap with any other VMA. + Patch by Jakub Jelinek. + +2003-12-29 Jakub Jelinek <jakub@redhat.com> + + * tst-raise1.c: Include stdio.h. + +2003-12-23 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/raise.c (raise): Protect pid = selftid + setting with __ASSUME_TGKILL || defined __NR_tgkill. + If pid is 0, set it to selftid. + * sysdeps/unix/sysv/linux/getpid.c (really_getpid): Make inline. + Don't set self->pid but self->tid. If self->pid == 0 and self->tid + != 0, return self->tid without doing a syscall. + * descr.h (struct pthread): Move pid field after tid. + + * Makefile (tests): Add tst-raise1. + * tst-raise1.c: New file. + +2003-12-23 Roland McGrath <roland@redhat.com> + + * tst-oddstacklimit.c: New file. + * Makefile (tests): Add it. + (tst-oddstacklimit-ENV): New variable. + + * init.c (__pthread_initialize_minimal_internal): Round stack rlimit + value up to page size for __default_stacksize. + +2003-12-21 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-eintr5. + * tst-eintr5.c: New file. + + * eintr.c (eintr_source): Prevent sending signal to self. + + * tst-eintr2.c (tf1): Improve error message. + +2003-12-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Define. + * sysdeps/unix/sysv/linux/getpid.c: New file. + * pthread_cancel.c: Add comment explaining use of PID field. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * pthread_getattr_np.c: Use abs() when comparing PID and TID fields. + * sysdeps/unix/sysv/linux/fork.c: Negate PID field of parent + temporarily to signal the field must not be relied on and updated + by getpid(). + * sysdeps/unix/sysv/linux/pt-raise.c: Handle case where PID is + temporarily negative. + * sysdeps/unix/sysv/linux/raise.c: Likewise. + +2003-12-19 Ulrich Drepper <drepper@redhat.com> + + * eintr.c (setup_eintr): Add new parameter. Pass to thread function. + (eintr_source): If ARG != NULL, use pthread_kill. + * tst-eintr1.c: Adjust for this change. + * tst-eintr2.c: Likewise. + * Makefile (tests): Add tst-eintr3 and tst-eintr4. + * tst-eintr3.c: New file. + * tst-eintr4.c: New file. + +2003-12-19 Jakub Jelinek <jakub@redhat.com> + + * libc-cancellation.c (__libc_enable_asynccancel): Don't cancel + if CANCELSTATE_BITMASK is set. + * sysdeps/pthread/librt-cancellation.c (__librt_enable_asynccancel): + Likewise. + + * Makefile (tests): Add tst-cancel22 and tst-cancel23. + (tests-reverse): Add tst-cancel23. + * tst-cancel22.c: New test. + * tst-cancel23.c: New test. + +2003-12-18 Ulrich Drepper <drepper@redhat.com> + + * tst-eintr1.c: Better error messages. + + * Makefile (tests): Add tst-eintr2. + * tst-eintr2.c: New file. + +2003-12-18 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel21 and tst-cancelx21. + (CFLAGS-tst-cancelx21.c): Set. + * tst-cancel21.c: New test. + * tst-cancelx21.c: New test. + + * unwind.c (FRAME_LEFT): Add adj argument. Subtract it from each + comparison operand. + (unwind_stop): Use _JMPBUF_CFA_UNWINDS_ADJ macro instead of + _JMPBUF_CFA_UNWINDS. Adjust FRAME_LEFT invocations. + * pt-longjmp.c: Include jmpbuf-unwind.h. + (__pthread_cleanup_upto): Use _JMPBUF_UNWINDS_ADJ macro instead of + _JMPBUF_UNWINDS. Adjust compared pointers. + * init.c (__pthread_initialize_minimal_internal): Initialize + pd->stackblock_size. + * sysdeps/pthread/jmpbuf-unwind.h: Removed. + * sysdeps/alpha/jmpbuf-unwind.h: New file. + * sysdeps/i386/jmpbuf-unwind.h: New file. + * sysdeps/powerpc/jmpbuf-unwind.h: New file. + * sysdeps/s390/jmpbuf-unwind.h: New file. + * sysdeps/sh/jmpbuf-unwind.h: New file. + * sysdeps/sparc/sparc32/jmpbuf-unwind.h: New file. + * sysdeps/x86_64/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: Include stdint.h. + (_JMPBUF_CFA_UNWINDS): Remove. + (_JMPBUF_CFA_UNWINDS_ADJ, _JMPBUF_UNWINDS_ADJ): Define. + +2003-12-12 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel20 and tst-cancelx20. + (CFLAGS-tst-cancelx20.c): Set. + * tst-cancel20.c: New test. + * tst-cancelx20.c: New test. + +2003-12-17 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Don't treat + architectures with separate register stack special here when + computing default stack size. + +2003-12-17 Roland McGrath <roland@redhat.com> + + * Makefile (tst-cancelx7-ARGS): New variable. + Reportd by Greg Schafer <gschafer@zip.com.au>. + +2003-12-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-stack3. Depend on $(objpfx)tst-stack3-mem. + (generated): Add tst-stack3.mtrace and tst-stack3-mem. + (tst-stack3-ENV): Set. + ($(objpfx)tst-stack3-mem): New. + * tst-stack3.c: New test. + +2003-12-10 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c (_init_EPILOG_BEGINS): + Add unwind directives. Drop unused .regstk directive. + (_fini_EPILOG_BEGINS): Add unwind directives. + +2003-12-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait): + Assume parameter is a pointer. + (lll_futex_wake): Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_futex_wait): + Likewise. + (lll_futex_wake): Likewise. + Reported by Boris Hu. + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Pass pointer to refcntr to lll_futex_wait. + + * sysdeps/unix/sysv/linux/sem_wait.c (__new_sem_wait): Simplify a bit. + +2003-12-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__rtld_lock_initialize): Define. + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Call + __rtld_lock_initialize for ld.so lock. + Patch in part by Adam Li <adam.li@intel.com>. + +2003-12-02 David Mosberger <davidm@hpl.hp.com> + + * Makefile (link-libc-static): Remove -lgcc_eh---it's already mentioned + in $(gnulib). Also, remove stale comment. + +2003-11-12 David Mosberger <davidm@hpl.hp.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Take + advantage of new syscall stub and optimize accordingly. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__NR_futex): Rename + from SYS_futex, to match expectations of + sysdep.h:DO_INLINE_SYSCALL. + (lll_futex_clobbers): Remove. + (lll_futex_timed_wait): Rewrite in terms of DO_INLINE_SYSCALL. + (lll_futex_wake): Likewise. + (lll_futex_requeue): Likewise. + (__lll_mutex_trylock): Rewrite to a macro, so we can include this + file before DO_INLINE_SYSCALL is defined (proposed by Jakub + Jelinek). + (__lll_mutex_lock): Likewise. + (__lll_mutex_cond_lock): Likewise. + (__lll_mutex_timed_lock): Likewise. + (__lll_mutex_unlock): Likewise. + (__lll_mutex_unlock_force): Likewise. + + * sysdeps/ia64/tls.h: Move declaration of __thread_self up so it + comes before the include of <sysdep.h>. + (THREAD_SELF_SYSINFO): New macro. + (THREAD_SYSINFO): Likewise. + (INIT_SYSINFO): New macro. + (TLS_INIT_TP): Call INIT_SYSINFO. + + * sysdeps/ia64/tcb-offsets.sym: Add SYSINFO_OFFSET. + + * sysdeps/pthread/createthread.c (create_thread): Use + THREAD_SELF_SYSINFO and THREAD_SYSINFO instead of open code. + * allocatestack.c (allocate_stack): Use THREAD_SYSINFO and + THREAD_SELF_SYSINFO instead of open code. + * sysdeps/i386/tls.h (THREAD_SELF_SYSINFO): New macro. + (THREAD_SYSINFO): Likewise. + + * sysdeps/unix/sysv/linux/ia64/dl-sysdep.h: New file. + + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: Work around gas problem. + +2003-12-06 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: Use .init_array + instead of .init. Patch by David Mosberger. + +2003-11-30 Thorsten Kukuk <kukuk@suse.de> + + * sysdeps/pthread/configure.in: Remove broken declaration in C + cleanup handling check. + +2003-11-30 Andreas Jaeger <aj@suse.de> + + * Makefile (CFLAGS-pt-initfini.s): Add $(fno_unit_at_a_time). + * sysdeps/unix/sysv/linux/x86_64/Makefile (CFLAGS-pt-initfini.s): + Likewise. + +2003-11-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/internaltypes.h (ATTR_FLAG_OLDATTR): Define. + * pthread_attr_destroy.c: Include shlib-compat.h. + (__pthread_attr_destroy): Return immediately if ATTR_FLAG_OLDATTR + is set in iattr->flags. + * pthread_attr_init.c (__pthread_attr_init_2_0): Set ATTR_FLAG_OLDATTR. + +2003-11-21 Jakub Jelinek <jakub@redhat.com> + + * Makefile (distribute): Add tst-cleanup4aux.c. + + * tst-cond12.c (prepare): Add prototype. Move after test-skeleton.c + include. + +2003-11-21 Ulrich Drepper <drepper@redhat.com> + + * tst-cond12.c (do_test): If USE_COND_SIGNAL is defined, use + pthread_cond_signal. + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Don't + store mutex address if the current value is ~0l. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/pthread/pthread_cond_broadcast.c + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * pthread_cond_init.c (__pthread_cond_init): Initialize __mutex + element with ~0l for pshared condvars, with NULL otherwise. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Don't store mutex address if the current + value is ~0l. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't use requeue for pshared + condvars. + + * Makefile: Add rules to build and run tst-cond12 and tst-cond13. + * tst-cond12.c: New file. + * tst-cond13.c: New file. + +2003-11-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Make missing forced unwind support + fatal. + +2003-11-11 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Don't declare __pthread_unwind as weak inside libpthread. + +2003-11-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add magic to clean up correctly. + +2003-11-05 Jakub Jelinek <jakub@redhat.com> + + * unwind.c (FRAME_LEFT): Define. + (unwind_stop): Handle old style cleanups here. + (__pthread_unwind): Handle old style cleanups only if + !HAVE_FORCED_UNWIND. + * Makefile (tests): Add tst-cleanup4 and tst-cleanupx4. + (CFLAGS-tst-cleanupx4.c): Add -fexceptions. + ($(objpfx)tst-cleanup4): Depend on $(objpfx)tst-cleanup4aux.o. + ($(objpfx)tst-cleanupx4): Likewise. + * tst-cleanup4.c: New test. + * tst-cleanup4aux.c: New. + * tst-cleanupx4.c: New test. + +2003-11-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h: Use lll_*lock instead of + lll_mutex_*lock macros to skip atomic operations on some archs. + +2003-11-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/tst-timer.c (main): Initialize + sigev2.sigev_value as well. + +2003-10-15 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/configure.in: Barf if visibility attribute support + is missing. + * sysdeps/pthread/configure: Regenerated. + +2003-10-09 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Completely revamp the + locking macros. No distinction between normal and mutex locking + anymore. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Rewrite mutex locking. + Merge bits from lowlevelmutex.S we still need. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Remove. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/sh/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Adjust for + new mutex implementation. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h (PSEUDO): Also defined + symbol for entry point to avoid cancellation. + +2003-10-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Backout 2003-10-02 + changes. + (SAVE_OLDTYPE_0): Fix a typo. + +2003-10-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): + Check __sigsetjmp return value. Reported by Daniel Jacobowitz. + +2003-10-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (DOCARGS_1): Use + correct offset. + +2003-10-02 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-cancel19. + * tst-cancel19.c: New test. + +2003-10-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Fix saving and + restoring of the old cancellation type. + +2003-09-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/malloc-machine.h: Remove misleading comment. + +2003-09-27 Wolfram Gloger <wg@malloc.de> + + * sysdeps/pthread/malloc-machine.h: New file + +2003-09-24 Roland McGrath <roland@redhat.com> + + * allocatestack.c (__make_stacks_executable): Don't ignore return + value from _dl_make_stack_executable. + +2003-09-24 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (__make_stacks_executable): Also change + permission of the currently unused stacks. + + * allocatestack.c (change_stack_perm): Split out from + __make_stacks_executable. + (allocate_stack): If the required permission changed between the time + we started preparing the stack and queueing it, change the permission. + (__make_stacks_executable): Call change_stack_perm. + + * Makefile: Build tst-execstack-mod locally. + * tst-execstack-mod.c: New file. + +2003-09-23 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Only add tst-execstack if have-z-execstack is yes. + +2003-09-23 Roland McGrath <roland@redhat.com> + + * tst-execstack.c: New file. + * Makefile (tests): Add it. + ($(objpfx)tst-execstack, $(objpfx)tst-execstack.out): New targets. + (LDFLAGS-tst-execstack): New variable. + + * allocatestack.c (allocate_stack): Use GL(dl_stack_flags) to decide + whether to use PROT_EXEC for stack mmap. + (__make_stacks_executable): New function. + * pthreadP.h: Declare it. + * init.c (__pthread_initialize_minimal_internal): Set + GL(dl_make_stack_executable_hook) to that. + +2003-09-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Adjust for latest + recommendation from AMD re avoidance of lock prefix. + +2003-09-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): Use + lll_futex_timed_wait instead of lll_futex_wait. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Removed. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Removed. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Include atomic.h. + Completely revamp the locking macros. No distinction between + normal and mutex locking anymore. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_lock_wait, + __lll_lock_timedwait): Fix prototypes. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_lock_wait, + __lll_lock_timedwait): Likewise. + (lll_mutex_lock, lll_mutex_cond_lock): Use _val instead of _bool + macros, add __builtin_expect. + (lll_mutex_timedlock): Likewise. Fix return value. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: Removed. + +2003-09-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_mutex_lock_wait): Minor optimization to avoid one atomic + operation if possible. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Don't play tricks + like jumping over the lock prefix. + +2003-09-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Completely revamp the + locking macros. No distinction between normal and mutex locking + anymore. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Rewrite mutex + locking. Merge bits from lowlevelmutex.S we still need. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/lowlevellock.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Removed. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Removed. + * Makefile (routines): Remove libc-lowlevelmutex. + (libpthread-rountines): Remove lowlevelmutex. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Adjust + for new mutex implementation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: Likewise + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + Don't use requeue. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/pthread/pthread_cond_signal.c: Don't use requeue. + +2003-09-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't match memory + in parameters of asm with output parameters. + + * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Change + type of DECR parameter to int. + * pthreadP.h: Adjust prototype of __pthread_mutex_unlock_usercnt. + +2003-09-18 Jakub Jelinek <jakub@redhat.com> + + * tst-attr3.c (tf, do_test): Print stack start/end/size and + guardsize for each thread. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_getattr_np): Clarify usage. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c + (pthread_attr_setaffinity_np): Handle cpuset == NULL. + + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c + (pthread_attr_getaffinity_np): Don't segfault if iattr->cpuset is + NULL. + * pthread_getattr_np.c: Set cpuset using pthread_getaffinity_np. + * pthreadP.h (pthread_getaffinity_np): Add hidden_proto. + * sysdeps/unix/sysv/linux/pthread_getaffinity.c + (pthread_getaffinity_np): Add hidden_def. + + * Makefile (tests): Add tst-attr3. + * tst-attr3.c: New test. + + * sysdeps/i386/Makefile (CFLAGS-tst-align.c): Remove. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/Makefile (CFLAGS-pthread_create.c, + CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4. + +2003-09-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-tst-align.c): Add $(stack-align-test-flags). + * tst-align.c: Include tst-stack-align.h. + (tf, do_test): Use TEST_STACK_ALIGN macro. + +2003-09-17 Ulrich Drepper <drepper@redhat.com> + + * pthread_attr_init.c (__pthread_attr_init_2_0): Remove unused + variable. + +2003-09-16 Ulrich Drepper <drepper@redhat.com> + + * pthread_getattr_np.c (pthread_getattr_np): Correctly fill in the + stack-related values for the initial thread. + +2003-09-15 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_once.c): Add $(uses-callbacks). + +2003-09-11 Ulrich Drepper <drepper@redhat.com> + + * pthread_mutex_lock.c: Minor code rearrangements. + +2003-09-05 Roland McGrath <roland@redhat.com> + + * pthread_create.c (__pthread_pthread_sizeof_descr): Removed. + Instead, include ../nptl_db/db_info.c to do its magic. + * pthread_key_create.c (__pthread_pthread_keys_max): Removed. + (__pthread_pthread_key_2ndlevel_size): Likewise. + * sysdeps/alpha/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/i386/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/ia64/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/powerpc/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/s390/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/sh/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/sparc/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/x86_64/tls.h (DB_THREAD_SELF): New macro. + * sysdeps/alpha/td_ta_map_lwp2thr.c: File removed. + * sysdeps/generic/td_ta_map_lwp2thr.c: File removed. + * sysdeps/i386/td_ta_map_lwp2thr.c: File removed. + * sysdeps/ia64/td_ta_map_lwp2thr.c: File removed. + * sysdeps/powerpc/td_ta_map_lwp2thr.c: File removed. + * sysdeps/s390/td_ta_map_lwp2thr.c: File removed. + * sysdeps/sh/td_ta_map_lwp2thr.c: File removed. + * sysdeps/sparc/td_ta_map_lwp2thr.c: File removed. + * sysdeps/x86_64/td_ta_map_lwp2thr.c: File removed. + +2003-09-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type + of pthread_t to be compatible with LT. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise. + +2003-09-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/not-cancel.h (fcntl_not_cancel): Define. + +2003-09-04 Jakub Jelinek <jakub@redhat.com> + + * unwind-forcedunwind.c: Move to... + * sysdeps/pthread/unwind-forcedunwind.c: ...here. + (pthread_cancel_init): Use ARCH_CANCEL_INIT if defined. + * sysdeps/pthread/jmpbuf-unwind.h: New file. + * sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c: New file. + * sysdeps/unix/sysv/linux/ia64/jmpbuf-unwind.h: New file. + * unwind.c: Include jmpbuf-unwind.h. + (unwind_stop): Use _JMPBUF_CFA_UNWINDS macro. + +2003-09-02 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/ia64/Versions (libpthread): Export + pthread_attr_setstack and pthread_attr_setstacksize @@GLIBC_2.3.3. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/alpha/Versions: New file. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h: New file. + * sysdeps/unix/sysv/linux/sparc/Versions: New file. + * pthread_attr_setstack.c (__old_pthread_attr_setstack): New function. + (pthread_attr_setstack): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.2. + * pthread_attr_setstacksize.c (__old_pthread_attr_setstacksize): New + function. + (pthread_attr_setstacksize): If PTHREAD_STACK_MIN != 16384, export + as @@GLIBC_2.3.2 and also export compatibility @GLIBC_2.1. + * Makefile (tests): Add tst-stack2. + * tst-stack2.c: New test. + * tst-stack1.c: Include limits.h and sys/param.h. + (do_test): Set size to MAX (4 * getpagesize (), PTHREAD_STACK_MIN). + + * pthread_condattr_setpshared.c: Include errno.h. + (pthread_condattr_setpshared): Return EINVAL if pshared + is neither PTHREAD_PROCESS_PRIVATE nor PTHREAD_PROCESS_SHARED. + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): Also + defined symbol for entry point to avoid cancellation. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/i386/not-cancel.h (__open_nocancel, + __close_nocancel, __read_nocancel, __write_nocancel, + __waitpid_nocancel): Add attribute_hidden. If not in libc.so, + libpthread.so or librt.so, define to corresponding function + without _nocancel suffix. + * sysdeps/unix/sysv/linux/s390/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/powerpc/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/not-cancel.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: Fix a typo. + +2003-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/not-cancel.h: New file. + * sysdeps/unix/sysv/linux/x86_64/not-cancel.h: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Make sure the code + in subsections has a symbol associated with it. + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (PSEUDO): Also + defined symbol for entry point to avoid cancellation. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (PSEUDO): Likewise. + +2003-09-01 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests): Add tst-tls5. + (module-names): Add tst-tls5mod{,a,b,c,d,e,f}. + ($(objpfx)tst-tls5mod{,a,b,c,d,e,f}.so-no-z-defs): Set to yes. + ($(objpfx)tst-tls5): New. + ($(objpfx)tst-tls6.out): Likewise. + (tests): Depend on $(objpfx)tst-tls6.out. + * tst-tls3.c: Include stdint.h and pthreaddef.h. + (do_test): Check pthread_self () return value alignment. + * tst-tls3mod.c: Include stdint.h and pthreaddef.h. + (tf): Check pthread_self () return value alignment. + * tst-tls5.c: New test. + * tst-tls5.h: New. + * tst-tls5mod.c: New. + * tst-tls5moda.c: New. + * tst-tls5modb.c: New. + * tst-tls5modc.c: New. + * tst-tls5modd.c: New. + * tst-tls5mode.c: New. + * tst-tls5modf.c: New. + * tst-tls6.sh: New test. + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): Add + ptr___pthread_cond_timedwait and ptr___pthread_cond_timedwait_2_0. + * init.c (pthread_functions): Initialize them. + * forward.c (pthread_cond_timedwait@GLIBC_2.0, + pthread_cond_timedwait@@GLIBC_2.3.2): New forwards. + * Versions (libc): Export pthread_cond_timedwait@GLIBC_2.0, + pthread_cond_timedwait@@GLIBC_2.3.2. + +2003-09-01 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/alpha/timer_create.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/alpha/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/alpha/Versions: New file. + + * sysdeps/unix/sysv/linux/alpha/aio_cancel.c: New file. + + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: Define + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: Likewise. + +2003-08-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock): Avoid + nested function, use static inline function from libio.h. + Code by Richard Henderson. + + * sysdeps/pthread/bits/libc-lock.h: Mark pthread_setcancelstate as + weak. + +2003-08-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/Versions: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/sparc/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/sparc/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sparc/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/sparc/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sparc/fork.c: New file. + * sysdeps/unix/sysv/linux/sparc/aio_cancel.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c: New file. + * sysdeps/sparc/sparc32/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc32/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc32/pthreaddef.h: New file. + * sysdeps/sparc/sparc64/pthread_spin_lock.c: New file. + * sysdeps/sparc/sparc64/pthread_spin_trylock.c: New file. + * sysdeps/sparc/sparc64/pthread_spin_unlock.c: New file. + * sysdeps/sparc/sparc64/pthreaddef.h: New file. + * sysdeps/sparc/tls.h: New file. + * sysdeps/sparc/tcb-offsets.sym: New file. + * sysdeps/sparc/Makefile: New file. + * sysdeps/sparc/td_ta_map_lwp2thr.c: New file. + * init.c [__sparc__] (__NR_set_tid_address): Define. + +2003-08-29 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_acquire_lock, + _IO_release_lock): Define. + +2003-08-29 Jakub Jelinek <jakuB@redhat.com> + + * tst-cancel4.c (tf_sigwait, tf_sigwaitinfo, tf_sigtimedwait): Add + sigemptyset before sigaddset. Reported by jreiser@BitWagon.com. + +2003-08-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_exit): Remove __THROW. + (__pthread_cleanup_class): Add missing return types of member + functions. + +2003-08-26 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_unlock_force): Add memory barrier between store and futex + syscall. + +2003-08-25 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (do_test): Also unlink tempfname and remove + tempmsg in first loop. + +2003-08-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + +2003-08-07 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h [_LIBC && SHARED] + (__rtld_lock_default_lock_recursive, + __rtld_lock_default_unlock_recursive): Define. + [_LIBC && SHARED] (__rtld_lock_lock_recursive, + __rtld_lock_unlock_recursive): Define using + GL(_dl_rtld_*lock_recursive). + * init.c (__pthread_initialize_minimal_internal): Initialize + _dl_rtld_lock_recursive and _dl_rtld_unlock_recursive. + Lock GL(_dl_load_lock) the same number of times as + GL(_dl_load_lock) using non-mt implementation was nested. + + * pthreadP.h (__pthread_cleanup_upto): Add hidden_proto. + * pt-longjmp.c (__pthread_cleanup_upto): Add hidden_def. + +2003-08-06 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel17.c (do_test): Make len2 maximum of page size and + PIPE_BUF. + +2003-08-07 Jakub Jelinek <jakub@redhat.com> + + * pthread_create.c (__pthread_create_2_0): Clear new_attr.cpuset. + +2003-08-03 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/createthread.c (do_clone): Move error handling + to first syscall error check. Move syscall error check for tkill + into __ASSUME_CLONE_STOPPED #ifdef. + +2003-08-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (do_clone): If __ASSUME_CLONE_STOPPED + is not defined, do explicit synchronization. + (create_thread): Do not lock pd->lock here. If __ASSUME_CLONE_STOPPED + is not defined also unlock pd->lock for non-debugging case in case + it is necessary. + * pthread_create.c (start_thread): Always get and release pd->lock + if __ASSUME_CLONE_STOPPED is not defined. + (start_thread_debug): Removed. Adjust users. + * allocatestack.c (allocate_stack): Always initialize lock if + __ASSUME_CLONE_STOPPED is not defined. + * Makefile (tests): Add tst-sched1. + * tst-sched1.c: New file. + + * sysdeps/pthread/createthread.c (do_clone): Only use + sched_setschduler and pass correct parameters. + +2003-07-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_attr_setstackaddr, + pthread_attr_setstacksize): Change PTHREAD_STACK_SIZE to + PTHREAD_STACK_MIN in comments. + +2003-07-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Shut up warnings if INTERNAL_SYSCALL_ERROR_P does not use its first + argument. + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Likewise. + * pthread_condattr_setclock.c (pthread_condattr_setclock): Likewise. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Include pthreaddef.h. + (__pthread_cleanup_upto): Fix prototype. + (_longjmp_unwind): Adjust caller. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_timedlock): + Change second argument to const struct pointer. + * tst-sem8.c (main): Remove unused s2 and s3 variables. + * tst-sem9.c (main): Likewise. + * unwind.c: Include string.h for strlen prototype. + +2003-07-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Don't use cmov unless HAVE_CMOV is defined. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: + Define HAVE_CMOV. + Patch by Nicholas Miell <nmiell@attbi.com>. + +2003-07-30 Jakub Jelinek <jakub@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Initialize + GL(dl_init_static_tls). + * pthreadP.h (__pthread_init_static_tls): New prototype. + * allocatestack.c (init_one_static_tls, __pthread_init_static_tls): + New functions. + * Makefile (tests): Add tst-tls4. + (modules-names): Add tst-tls4moda and tst-tls4modb. + ($(objpfx)tst-tls4): Link against libdl and libpthread. + ($(objpfx)tst-tls4.out): Depend on tst-tls4moda.so and + tst-tls4modb.so. + * tst-tls4.c: New file. + * tst-tls4moda.c: New file. + * tst-tls4modb.c: New file. + +2003-06-19 Daniel Jacobowitz <drow@mvista.com> + + * sysdeps/pthread/timer_create.c (timer_create): Call timer_delref + before __timer_dealloc. + * sysdeps/pthread/timer_routines.c (__timer_thread_find_matching): + Don't call list_unlink. + +2003-07-29 Roland McGrath <roland@redhat.com> + + * Makefile [$(build-shared) = yes] (tests): Depend on $(test-modules). + +2003-07-25 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel17.c (do_test): Check if aio_cancel failed. + Don't reuse struct aiocb A if it failed. + Write fpathconf (fds[1], _PC_PIPE_BUF) + 2 bytes using aio_write, + not just one byte, as that does not block. + +2003-07-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/unwind-resume.c: New file. + * sysdeps/pthread/Makefile (routines, shared-only-routines): Add + unwind-resume in csu subdir. + (CFLAGS-unwind-resume.c, CFLAGS-rt-unwind-resume.c): Compile with + exceptions. + (librt-sysdep_routines, librt-shared-only-routines): Add + rt-unwind-resume. + * sysdeps/pthread/rt-unwind-resume.c: New file. + * unwind-forcedunwind.c: New file. + * Makefile (libpthread-routines): Add unwind-forcedunwind. + (libpthread-shared-only-routines): Likewise. + (CFLAGS-unwind-forcedunwind.c): Compile with exceptions. + * pthreadP.h (pthread_cancel_init): New prototype. + * pthread_cancel.c (pthread_cancel): Call pthread_cancel_init. + + * sysdeps/pthread/createthread.c (do_thread, create_thread): Make + attr argument const struct pthread_attr *. + + * res.c (__res_state): Return __resp. + * descr.h: Include resolv.h. + (struct pthread): Add res field. + * pthread_create.c: Include resolv.h. + (start_thread): Initialize __resp. + * Makefile (tests): Add tst-_res1. + (module-names): Add tst-_res1mod1, tst-_res1mod2. + ($(objpfx)tst-_res1mod2.so): Depend on $(objpfx)tst-_res1mod1.so. + ($(objpfx)tst-_res1): Depend on $(objpfx)tst-_res1mod2.so and + libpthread. + * tst-_res1.c: New file. + * tst-_res1mod1.c: New file. + * tst-_res1mod2.c: New file. + +2003-07-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c: Don't define CLONE_STOPPED. + + * Makefile: Define various *-no-z-defs variables for test DSOs + which has undefined symbols. + +2003-07-21 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c (__pthread_once): + Retry if the stwcx fails to store once_control. + +2003-07-20 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pthread_attr_getaffinity and + pthread_attr_setaffinity. + * Versions [libpthread] (GLIBC_2.3.3): Likewise. + * sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c: New file. + * sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c: New file. + * pthread_attr_destroy.c: Free cpuset element if allocated. + * pthread_create.c: Pass iattr as additional parameter to + create_thread. + * sysdeps/pthread/createthread.c: If attribute is provided and + a new thread is created with affinity set or scheduling parameters, + start thread with CLONE_STOPPED. + * sysdeps/pthread/pthread.h: Declare pthread_attr_getaffinity and + pthread_attr_setaffinity. + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_attr): Add + cpuset element. + +2003-07-15 Ulrich Drepper <drepper@redhat.com> + + * tst-tcancel-wrappers.sh: lseek and llseek are not cancelation points. + +2003-07-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Require CFI directives also for + ppc and s390. + +2003-07-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (PSEUDO): + Add cfi directives. + +2003-07-12 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Add RESULT, TID, CANCELHANDLING and + CLEANUP_JMP_BUF. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Use more + registers as variables. Call __pthread_mutex_unlock_usercnt. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Store TID + not self pointer in __writer. Compare with TID to determine + deadlocks. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Add cancellation support. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Define all the nice + macros also when compiling librt. + +2003-07-11 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_once.c): Add -fexceptions + -fasynchronous-unwind-tables. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h + (PSEUDO): Add cfi directives. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (PSEUDO): + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (PSEUDO): + Likewise. + +2003-07-08 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (__pthread_unwind_next, __pthread_register_cancel, + __pthread_unregister_cancel): Add prototypes and hidden_proto. + * unwind.c (__pthread_unwind_next): Add hidden_def. + * cleanup.c (__pthread_register_cancel, __pthread_unregister_cancel): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait): + Use HIDDEN_JUMPTARGET to jump to __pthread_unwind. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S (sem_wait): Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): Use + HIDDEN_JUMPTARGET to call __pthread_register_cancel, + __pthread_unregister_cancel and __pthread_unwind_next. + +2003-07-04 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (PSEUDO): Use + different symbol for the cancellation syscall wrapper and + non-cancellation syscall wrapper. + (PSEUDO_END): Define. + +2003-07-05 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: Avoid .ent/.end. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h (lll_futex_wait, + lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success + return actual return value from the syscall, not 0. + +2003-07-07 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Add pid field. + * allocatestack.c (allocate_stack): Initialize pid field in descriptor. + (__reclaim_stacks): Likewise. + * init.c (sigcancel_handler): If __ASSUME_CORRECT_SI_PID is defined + also check for PID of the signal source. + (__pthread_initialize_minimal_internal): Also initialize pid field + of initial thread's descriptor. + * pthread_cancel.c: Use tgkill instead of tkill if possible. + * sysdeps/unix/sysv/linux/fork.c: Likewise. + * sysdeps/unix/sysv/linux/pt-raise.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * sysdeps/unix/sysv/linux/raise.c: Likewise. + +2003-07-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_push): Renamed. + Fix use of parameter. + (__libc_cleanup_pop): Likewise. + +2003-07-04 Ulrich Drepper <drepper@redhat.com> + + * init.c (sigcancel_handler): Change parameters to match handler + for SA_SIGACTION. Check signal number and code to recognize + invalid invocations. + +2003-07-03 Roland McGrath <roland@redhat.com> + + * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): + Apply sizeof (struct pthread) bias to r13 value. + +2003-07-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Require CFI directives. + + * sysdeps/pthread/librt-cancellation.c (__pthread_unwind): Remove + definition. + * pthreadP.h (__pthread_unwind): Add hidden_proto if used in + libpthread compilation. + * unwind.c (__pthread_unwind): Add hidden_def. + * Versions (libpthread) [GLIBC_PRIVATE]: Add __pthread_unwind. + +2003-07-01 Ulrich Drepper <drepper@redhat.com> + + * libc-cancellation.c (__libc_cleanup_routine): Define. + * sysdeps/pthread/bits/libc-lock.h (__pthread_cleanup_push): Define. + (__pthread_cleanup_pop): Define. + +2003-07-01 Richard Henderson <rth@redhat.com> + + * sysdeps/alpha/elf/pt-initfini.c: New file. + * sysdeps/alpha/pthread_spin_lock.S: New file. + * sysdeps/alpha/pthread_spin_trylock.S: New file. + * sysdeps/alpha/pthreaddef.h: New file. + * sysdeps/alpha/td_ta_map_lwp2thr.c: New file. + * sysdeps/alpha/tls.h: New file. + * sysdeps/unix/sysv/linux/alpha/Makefile: New file. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/alpha/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/alpha/createthread.c: New file. + * sysdeps/unix/sysv/linux/alpha/fork.c: New file. + * sysdeps/unix/sysv/linux/alpha/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/alpha/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/alpha/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/alpha/sem_post.c: New file. + * sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h: New file. + +2003-07-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Add correct + cleanup support and unwind info. + +2003-06-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (__pthread_once): + Use correct cleanup handler registration. Add unwind info. + * sysdeps/unix/sysv/linux/unwindbuf.sym: New file. + * sysdeps/unix/sysv/linux/Makefile: Add rule to build unwindbuf.h. + * tst-once3.c: Add cleanup handler and check it is called. + * tst-once4.c: Likewise. + * tst-oncex3.c: New file. + * tst-oncex4.c: New file. + * Makefile: Add rules to build and run tst-oncex3 and tst-oncex4. + +2003-06-29 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/configure.in: Check for C cleanup handling in gcc. + +2003-06-27 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgrcv): Use IPC_PRIVATE in msgget call. + (tf_msgsnd): Likewise. + + * tst-cancel4.c (tf_msgrcv): Strengthen test against valid + premature returns a bit more. + +2003-06-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/librt-cancellation.c: Move __pthread_unwind + definition to the front. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rename + the cleanup functions to make the names unique. Fix dwarf opcode + un unwind table. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Rename cleanup + functions to make the names unique. Fix CFA offset for two blocks. + +2003-06-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (class __pthread_cleanup_class): Add + missing closing braces. + Patch by Christophe Saout <christophe@saout.de>. + +2003-06-24 Roland McGrath <roland@redhat.com> + + * pthread_mutex_trylock.c (__pthread_mutex_trylock): Typo fix. + +2003-06-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h: New file. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h: New file. + + * pthreadP.h: Declare __find_thread_by_id. + * allocatestack.c [HP_TIMING_AVAIL]: Define __find_thread_by_id. + * pthread_clock_gettime.c: Allow using other thread's clock. + * pthread_clock_settime.c: Likewise. + * sysdeps/pthread/pthread_getcpuclockid.c: Likewise. + * Makefile: Add rules to build and run tst-clock2. + * tst-clock2.c: New file. + +2003-06-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Rewrite + to use exception-based cleanup handler. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + + * tst-cond8.c (ch): Announce that we are done. + + * pthreadP.h (__pthread_mutex_cond_lock): Mark with internal_function. + + * tst-cancel17.c (tf): Retry aio_suspend in case of EINTR. + Also test aio_suspend with timeout value. + +2003-06-22 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Mark __pthread_mutex_unlock_usercnt also hidden. + * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Add + attribute_hidden. + + * pthreadP.h (__pthread_mutex_init_internal): Mark hidden. + (__pthread_mutex_lock_internal): Likewise. + (__pthread_mutex_unlock_internal): Likewise. + (__pthread_mutex_unlock_usercnt): Declare. + * pthread_mutex_destroy.c: Always fail if used in any way. + * pthread_mutex_init.c: Update comment. + * pthread_mutex_lock.c: If NO_INCR is not defined adjust __nusers. + * pthread_mutex_timedlock.c: Adjust __nusers. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Old code is in __pthread_mutex_unlock_usercnt + and public interfaces are wrapper with pass additional parameter. + __pthread_mutex_unlock_usercnt does not adjust __nusers if second + parameter zero. + * tst-mutex8.c: New file. + * Makefile (tests): Add tst-mutex8. + * sysdeps/pthread/pthread_cond_timedwait.c: Call + __pthread_mutex_unlock_usercnt. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Define NO_INCR. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Add __nusers. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * pthread_mutex_lock.c: Don't store THREAD_ID in __owner, use TID. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Compare with TID not THREAD_ID. + * tst-mutex9.c: New file. + * Makefile (tests): Add tst-mutex9. + * sysdeps/i386/tls.h: Remove THREAD_ID definition. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Change type of __owner. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2003-06-19 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Move to... + * sysdeps/unix/sysv/linux/sem_post.c: ...here. + + * sysdeps/unix/sysv/linux/sem_post.c: Move to... + * sysdeps/unix/sysv/linux/powerpc/sem_post.c: ... here. Pass nr + 1 + instead of nr to lll_futex_wake. Only set errno and return -1 + if err < 0. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (lll_futex_wait, + lll_futex_timed_wait, lll_futex_wake, lll_futex_requeue): On success + return actual return value from the syscall, not 0. + +2003-06-18 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c (tf_msgsnd): Don't always use 100 as the type, + find a random value. + (tf_msgrcv): Likewise. Also don't report msgrcv returns if + errno==EIDRM. + + * sysdeps/unix/sysv/linux/timer_settime.c: Add prototype for + compat_timer_settime. + * sysdeps/unix/sysv/linux/timer_gettime.c: Add prototype for + compat_timer_gettime. + * sysdeps/unix/sysv/linux/timer_getoverr.c: Add prototype for + compat_timer_getoverrun. + * sysdeps/unix/sysv/linux/timer_delete.c: Add prototype for + compat_timer_delete. + + * pthread_mutex_destroy.c (__pthread_mutex_destroy): For + error-checking mutex detect busy mutexes. + +2003-06-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_mutex_lock): + Add ax to clobber list. + (lll_mutex_cond_lock): Likewise. + (lll_mutex_unlock): Likewise. + (lll_lock): Likewise. + (lll_unlock): Likewise. + + * Makefile: Add rules to build and run tst-cancel18 and tst-cancelx18. + * tst-cancel18.c: New file. + * tst-cancelx18.c: New file. + + * tst-cancel4.c: Test connect, creat, msgrcv, msgsnd, sendmsg, sendto, + and tcdrain. + + * Makefile: Add rules to build and run tst-cancel17 and tst-cancel17x. + * tst-cancel17.c: New file. + * tst-cancelx17.c: New file. + + * sysdeps/unix/sysv/linux/sigtimedwait.c: New file. + * sysdeps/unix/sysv/linux/sigwait.c: New file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file. + + * tst-cancel4.c: Test open, close, pread, pwrite, fsync, and msync. + +2003-06-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Set + header.multiple_threads unconditionally. + * allocatestack.c (allocate_stack): Likewise. + * descr.h (struct pthread): Add header.multiple_threads + unconditionally. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (CENABLE, CDISABLE): + Define for librt. #error if neither libpthread, libc nor librt. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (CENABLE, CDISABLE): + Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h (CENABLE, + CDISABLE): Likewise. Access header.multiple_threads outside of + libc and libpthread. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h (CENABLE, CDISABLE): + Likewise. + * sysdeps/x86_64/tls.h (tcbhead_t): Add multiple_threads. + * sysdeps/x86_64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Define. + +2003-06-17 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel4.c: Add tests for the socket and signal functions, pause. + Also test early cancellation before the thread reaches the cancellation + point. + + * Makefile: Compile forward.c with exceptions. + + * sysdeps/unix/sysv/linux/sleep.c: New file. + +2003-06-16 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Add CFLAGS definition to compile function wrappers + duplicated from libc with exceptions. + * tst-cancel4.c: Also check cancellation handlers. + + * Makefile: Add rules to build and run tst-cancel16 and + tst-cancelx16. Add missing CFLAGS definitions. + * tst-cancel16.c: New file. + * tst-cancelx16.c: New file. + +2003-06-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Use CFI opcodes. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Likewise. + + * pthreadP.h (LIBC_CANCEL_ASYNC): Also define for librt. + (LIBC_CANCEL_RESET): Likewise. + Declare __librt_enable_asynccancel and __librt_disable_asynccancel. + * sysdeps/pthread/Makefile (librt-sysdep_routines): Add + librt-cancellation. + (CFLAGS-libcrt-cancellation.c): Define. + * sysdeps/pthread/librt-cancellation.c: New file. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define all the nice + macros also when compiling librt. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + + * sysdeps/unix/sysv/linux/timer_create.c: Add prototype for + compat_timer_create. + +2003-06-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/posix-timer.h (timespec_compare): Always inline. + + * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for + __register_atfork. + * sysdeps/unix/sysv/linux/register-atfork.c (__register_atfork): + Add libc_hidden_def. + +2003-06-13 Roland McGrath <roland@redhat.com> + + * sysdeps/x86_64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Pass FS + constant from <sys/reg.h> to ps_get_thread_area, not register contents. + +2003-06-11 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (queue_stack): Always inline. + * ptreadhP.h (__do_cancel): Likewise. + +2003-06-10 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): Fix + a typo. + +2003-06-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Remove incorrect second addition for + cond_lock!=0. + +2003-06-09 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Use correct futex pointer in + __lll_mutex_lock_wait call. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Some more tweaks to handle cond_lock!=0. + +2003-06-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/s390/sem_wait.c (__new_sem_wait): Make + cancelable. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): + Likewise. + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Remove + hand-written CFI generation code. Since ENTRY/END also initiated + CFI frames this caused two CFI sets to be generated. + +2003-06-07 Ulrich Drepper <drepper@redhat.com> + + * cleanup_routine.c: New file. + * Versions (libpthread) [GLIBC_2.3.3]: Add __pthread_cleanup_routine. + * sysdeps/pthread/pthread.h: Add support for fully exception-based + cleanup handling. + * Makefile (libpthread-routines): Add cleanup_routine. + Add more CFLAGS variables to compile with exceptions. Add comments + why which file needs unwind tables. + (tests) [have-forced-unwind==yes]: Add tst-cancelx* and tst-cleanupx* + tests. + * tst-cancelx1.c: New file. + * tst-cancelx2.c: New file. + * tst-cancelx3.c: New file. + * tst-cancelx4.c: New file. + * tst-cancelx5.c: New file. + * tst-cancelx6.c: New file. + * tst-cancelx7.c: New file. + * tst-cancelx8.c: New file. + * tst-cancelx9.c: New file. + * tst-cancelx10.c: New file. + * tst-cancelx11.c: New file. + * tst-cancelx12.c: New file. + * tst-cancelx13.c: New file. + * tst-cancelx14.c: New file. + * tst-cancelx15.c: New file. + * tst-cleanupx0.c: New file. + * tst-cleanupx0.expect: New file. + * tst-cleanupx1.c: New file. + * tst-cleanupx2.c: New file. + * tst-cleanupx3.c: New file. + + * tst-cleanup0.c: Make standard compliant. + * tst-cleanup1.c: Likewise. + + * sysdeps/unix/sysv/linux/sem_timedwait.c: Add cancellation support. + * sysdeps/unix/sysv/linux/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/i386/tcb-offsets.sym: Add RESULT, CANCELHANDLING, and + CLEANUP_JMP_BUF. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * tst-cancel12.c: New file. + * tst-cancel13.c: New file. + * tst-cancel14.c: New file. + * tst-cancel15.c: New file. + * Makefile (tests): Add tst-cancel12, tst-cancel13, tst-cancel14, + and tst-cancel15. + + * tst-cancel1.c: Add some comments. + + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Compute relative + timeout correctly. + +2003-06-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-pthread_cancel.c): Define. + +2003-06-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_rwlock_t): + Change type of __writer element to int. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/i386/tcb-offsets.sym: Replace SELF entry with TID entry. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + * pthread_rwlock_trywrlock.c: Store TID not self pointer in __writer. + Compare with TID to determine deadlocks. + * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + * Makefile (tests): Add tst-rwlock12. + * tst-rwlock12.c: New file. + +2003-06-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait, + __lll_timedlock_wait, lll_unlock_wake_cb, __lll_timedwait_tid): + Remove bogus hidden_proto. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_lock, + lll_unlock_wake_cb, ___lll_timedwait_tid): Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (___lll_mutex_lock, + ___lll_mutex_timedlock): Likewise. + +2003-06-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Add some code to eventually handle + cond_lock!=0. + +2003-06-01 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-exec4. + (tst-exec4-ARGS): Define. + * tst-exec4.c: New file. + +2003-05-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): + Also fail if tv_nsec < 0. + (__lll_timedwait_tid): Likewise. + * sysdeps/unix/sysv/linux/sem_timedwait.c (sem_timedwait): Likewise. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c (___lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c (__lll_mutex_timedlock): + Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c (sem_timedwait): + Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_timedwait_tid): + Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (lll_timedwait_tid): + Likewise. + + * Makefile (tests): Add tst-sem8 and tst-sem9. + * tst-sem8.c: New file. + * tst-sem9.c: New file. + * sem_open.c: Fix creation of in_use record if the file exists but + no internal record. + + * posix-timer.h: Remove old, unused timer_id2ptr and timer_ptr2id + definitions. + + * sysdeps/pthread/timer_create.c (timer_create): In case + evp==NULL, assign timer ID to sival_ptr. + + * descr.h (struct pthread_unwind_buf): Change type of prev element to + struct pthread_unwind_buf *. + (struct pthread): Likewise for cleanup_jmp_buf element. + + * cleanup.c (__pthread_register_cancel): Add cast to avoid warning. + * cleanup_defer.c (__pthread_register_cancel_defer): Likewise. + * unwind.c (__pthread_unwind_next): Likewise. + +2003-05-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (lll_futex_timed_wait): Use int for futex value parameter. + (lll_futex_wake): Likewise. + (lll_futex_requeue): Likewise. + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait): + Replace one memory operation with one register operation. + + * tst-join4.c (do_test): Fix error message. + + * tst-rwlock6.c (do_test): Use correct format specifier. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_lock_wait): Replace one memory operation with one + register operation. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S + (__lll_mutex_lock_wait): Likewise. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_cond_lock): Add one to value parameter of + __lll_lock_wait to reflect reality in the futex syscall. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_cond_lock): Likewise. + +2003-05-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_mutex_cond_lock): + New function. + (lll_mutex_cond_lock): Define. + +2003-05-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-signal6. + * tst-signal6.c: New file. + + * sysdeps/unix/sysv/linux/s390/lowlevellock.h + (__lll_mutex_unlock_force): New function + (lll_mutex_unlock_force): Use __lll_mutex_unlock_force. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_unlock_force): New function. + (lll_mutex_unlock_force): Use __lll_mutex_unlock_force. + + * tst-rwlock7.c (do_test): Use correct format specifier. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_requeue): + Find break parameter in correct asm argument. + +2003-05-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_clobbers): + Remove out4. + (lll_futex_requeue): Fix __o3 constraint, return negative errno if + error occured. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h (FUTEX_REQUEUE, + lll_futex_requeue, lll_mutex_unlock_force): Define. + +2003-05-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Add __mutex. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (FUTEX_REQUEUE, + lll_futex_requeue, lll_mutex_unlock_force): Define. + +2003-05-28 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tcb-offsets.sym: Define MUTEX_FUTEX. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex field. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h (SYSCALL_WITH_INST_PAD): + Define. + (lll_futex_wait, lll_futex_wake): Define. + * sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: Try using + FUTEX_REQUEUE instead of FUTEX_WAIT. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Remember + mutex which was used in condvar structure. Call + __pthread_mutex_cond_lock instead of __pthread_mutex_lock_internal. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Don't + include tcb-offsets.h. Read wakeup value in locked region. + Use the value of gbr register as THREAD_ID. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Remove futex related + macros. + +2003-05-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_broadcast.c + (__pthread_cond_broadcast): Fix typo: MAX_INT -> INT_MAX. + +2003-05-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Fix + typo in register name. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Use parameters + correctly. Actually use requeue. Little optimization. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Store + mutex address early. Handle cancellation state as 32-bit value. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + Remove unnecessary label. + +2003-05-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_broadcast.c: Try using FUTEX_REQUEUE + instead of FUTEX_WAIT. + * sysdeps/pthread/pthread_cond_signal.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c: Remember mutex which was + used in condvar structure. Call __pthread_mutex_cond_lock instead + of __pthread_mutex_lock_internal. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + (__condvar_cleanup): Always call __pthread_mutex_cond_lock. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/Makefile (libpthread-sysdep_routines): + Add pthread_mutex_cond_lock. + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add dep_mutex. + * sysdeps/unix/sysv/linux/pthread_cond_mutex_lock.c: New file. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define + lll_mutex_cond_lock. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __mutex field. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * sysdeps/i386/tcb-offsets.sym: Define MUTEX_FUTEX. + * sysdeps/x86_64/tcb-offsets.sym: Likewise. + + * pthreadP.h: Declare __pthread_mutex_cond_lock. + * pthread_mutex_lock.c: Define LLL_MUTEX_LOCK if not already defined. + Use it instead of lll_mutex_lock. If __pthread_mutex_lock is a + macro don't define aliases. + + * cancellation.c: Remove __pthread_enable_asynccancel_2. + * pthreadP.h: Remove declaration of __pthread_enable_asynccancel_2. + * sysdeps/pthread/pthread_cond_timedwait.c: Use + __pthread_enable_asynccancel instead of __pthread_enable_asynccancel_2. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + +2003-05-17 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c: Fix one endless loop. Implement correct semantics + wrt opening the same semaphore more then once. + * sem_close.c: Adjust for sem_open change. + * semaphoreP.h: Include <semaphore.h>. Define struct inuse_sem. + Declare __sem_mappings, __sem_mappings_lock, __sem_search. + * Makefile (tests): Add tst-sem7. + * tst-sem7.c: New file. + +2003-05-16 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/register-atfork.c (libc_freeres_fn): Fix + uninitialized variable braino. + +2003-05-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_gettime.c (timer_gettime): Correct + test for syscall availability. + + * sysdeps/unix/sysv/linux/timer_settime.c (timer_settime): Set + __no_posix_timers to -1 if the syscalls don't exist. + + * pthread_join.c (pthread_join): Set tid field of the joined + thread to -1. This isn't necessary but helps to recognize some + error conditions with almost no cost. + + * allocatestack.c (FREE_P): Also negative values indicate an + unused stack. + + * unwind.c: Include <unistd.h>. + +2003-05-14 Ulrich Drepper <drepper@redhat.com> + + * Makefile ($(objpfx)$(multidir)): Add rule to create the directory. + +2003-05-14 Jakub Jelinek <jakub@redhat.com> + + * Makefile (crti-objs, crtn-objs): New variables. + (omit-deps, extra-objs): Add crtn. + ($(objpfx)libpthread.so): Depend on both crti and crtn + and links to them in multidir. + ($(objpfx)crtn.S, $(objpfx)crtn.o): New rules. + +2003-05-12 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h + (lll_mutex_unlock): Use atomic_exchange_rel. + +2003-05-11 Ulrich Drepper <drepper@redhat.com> + + * cond-perf.c (cons): Add missing locking around setting of alldone. + +2003-05-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Remove futex + related macros. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + +2003-05-09 Ulrich Drepper <drepper@redhat.com> + + * tst-sem6.c: New file. + * Makefile (tests): Add tst-sem6. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (___lll_mutex_unlock): + Use atomic_exchange_rel instead of atomic_exchange. + * sysdeps/unix/sysv/linux/lowlevellock.c (lll_unlock_wake_cb): + Likewise. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Improve quality of + code for lll_futex_wait and lll_futex_wake in static apps. Use + vsyscall is possible. + + * sysdeps/unix/sysv/linux/pthread_getaffinity.c: New file. + * sysdeps/unix/sysv/linux/pthread_setaffinity.c: New file. + * sysdeps/pthread/pthread.h: Declare pthread_getaffinity_np and + pthread_setaffinity_np. + * Versions [libpthread] (GLIBC_2.3.3): Add pthread_getaffinity_np + and pthread_setaffinity_np. + * Makefile (libpthread-routines): Add pthread_getaffinity and + pthread_setaffinity. + + * allocatestack.c (allocate_stack): If ARCH_RETRY_MMAP is defined, + use it in case mmap to allocate the stack fails. + * sysdeps/unix/sysv/linux/x86_64/Makefile: Don't define + ARCH_MAP_FLAGS here. + * sysdeps/x86_64/pthreaddef.h: Define ARCH_MAP_FLAGS and + ARCH_RETRY_MMAP. + +2003-05-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c: Complete rewrite of the atfork + handler implementation. It is now lockless in fork(). + * sysdeps/unix/sysv/linux/register-atfork.c: Likewise. + * sysdeps/unix/sysv/linux/unregister-atfork.c: Likewise. + * sysdeps/unix/sysv/linux/fork.h: Don't include <link.h>. Don't + declare the __fork_*_lists. + (struct fork_handler): Include pointers to all three functions. + Add next, refcntr and need_signal elements. + (__fork_handlers): New declaration. + (__register_atfork_malloc): Remove declaration. + (HAVE_register_atfork_malloc): Remove definition. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove + __pthread_child_handler variable. + (__libc_pthread_init): Use __register_atfork instead of explicitly + adding to the list. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define lll_futex_wait + and lll_futex_wake. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + + * unwind.c (unwind_cleanup): Print error message and then abort. This + function must never be reached. + + * cond-perf.c: New file. + +2003-05-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Include \n in error message. + +2003-05-04 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)../libc.so): New target. + +2003-05-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_condattr_t): Size is only an int, don't use long for + alignment. + (pthread_mutexattr_t): Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + +2003-05-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h: Define THREAD_ID. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * pthread_mutex_lock.c: Use THREAD_ID instead of THREAD_SELF to + record ownership. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Likewise. + * pthread_mutex_unlock.c: Likewise. + * pthread_rwlock_trywrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlocklock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + + * sysdeps/pthread/createthread.c (create_thread): Use CLONE_SYSVSEM + flag. + +2003-04-29 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (__SIZEOF_PTHREAD_COND_T): Define to 48. + (pthread_rwlock_t): Add 16 bytes of pad instead of 8 before __flags. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Make __align long long instead of long. + (pthread_rwlock_t): Formatting. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h + (pthread_rwlock_t): Formatting. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Make __align long long instead of long. + (pthread_rwlock_t): Move __flags field to the same position as in + linuxthreads. + +2003-04-30 Ulrich Drepper <drepper@redhat.com> + + * tst-rwlock6.c (do_test): Use correct printf format specifiers. + * tst-rwlock7.c (do_test): Likewise. + +2003-04-26 Roland McGrath <roland@redhat.com> + + * Makefile ($(test-modules)): Depend on $(common-objpfx)shlib.lds. + +2003-04-22 Jakub Jelinek <jakub@redhat.com> + + * allocatestack.c (TLS_TPADJ): Add TLS_PRE_TCB_SIZE instead of + sizeof (struct pthread). + (allocate_stack): Subtract TLS_PRE_TCB_SIZE bytes instead of + 1 struct pthread. + * sysdeps/powerpc/tls.h (TLS_INIT_TCB_SIZE, TLS_TCB_SIZE): Define + to 0. + (TLS_INIT_TCB_ALIGN, TLS_TCB_ALIGN): Define to alignment of + struct pthread. + (TLS_PRE_TCB_SIZE): Increase to cover tcbhead_t preceeded by pad + to 32-bit bytes. + (INSTALL_DTV, GET_DTV, THREAD_DTV): tcbhead_t is immediately before + tcbp. + (TLS_INIT_TP, THREAD_SELF, INIT_THREAD_SELF): Don't add TLS_TCB_SIZE + unneccessarily. + (NO_TLS_OFFSET): Define. + * sysdeps/unix/sysv/linux/powerpc/createthread.c (TLS_VALUE): Don't + add TLS_TCB_SIZE unnecessarily. + +2003-04-22 Roland McGrath <roland@redhat.com> + + * Makeconfig (shared-thread-library): Reverse link order to work + around linker bug. + +2003-04-22 Ulrich Drepper <drepper@redhat.com> + + * semaphore.h: Fix typo in comment. + +2003-04-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/sigfillset.c: New file. + + * init.c (__pthread_initialize_minimal): Don't block SIGTIMER. + * pthreadP.h: Make SIGTIMER and SIGCANCEL the same. + * sysdeps/pthread/pthread_sigmask.c: Remove handling of SIGTIMER. + * sysdeps/pthread/sigaction.c: Likewise. + * sysdeps/pthread/sigprocmask.c: New file. + * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): Define as + __SIGRTMIN+1. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Block SIGTIMER. Also handle SI_TKILL events and terminate thread + in this case. + +2003-04-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (DL_SYSINFO_IMPLEMENTATION): Add .eh_frame information. + + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Don't free memory not allocated dynamically. + + * semaphore.h: Remove __THROW marker from cancellation points. + * nptl/sysdeps/pthread/pthread.h: Likewise. + +2003-04-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Don't mark pthread_testcancel, + pthread_cancel, pthread_setcancelstate, and pthread_setcanceltype with + __THROW. + +2003-04-16 Jakub Jelinek <jakub@redhat.com> + + * tst-cancel4.c (do_test): Use %zd instead of %d when printing cnt. + +2003-04-15 Roland McGrath <roland@redhat.com> + + * forward.c (__pthread_unwind): Tweak to avoid warning. + +2003-04-15 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Move THREAD_ATOMIC_* replacements to the top. + +2003-04-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Don't + overflow CFA advance instructions. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + +2003-04-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Rename LOCK to LOCK_PREFIX. + * sysdeps/i386/pthread_spin_lock.c: Likewise. + * sysdeps/x86_64/tls.h: Likewise. Define LOCK_PREFIX if not already + defined. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Use + DW_CFA_advance_loc2 for .Laddl-.Lsubl. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use + DW_CFA_advance_loc for .Laddl-.Lsubl. + +2003-04-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Don't use + position-independent unwind data for static libraries. + Add missing unwind info. Add comments. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Add unwind info. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + +2003-04-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile: Make sure all cancellation points are compiled with + exception and asynchronous unwind tables. + + * sysdeps/x86_64/tls.h (THREAD_SETMEM): Word around compiler bug + which mishandles loading of global object addresses in PIC. + (THREAD_SETMEM_NC): Likewise. + +2003-04-11 Ulrich Drepper <drepper@redhat.com> + + * pthread.h: Define new data structure for cleanup buffer. Declare + new cleanup handler interfaces. + * descr.h: Include <unwind.h> if necessary. Define pthread_unwind_buf. + (struct pthread): Add cleanup_jmp_buf pointer. Define + HAVE_CLEANUP_JMP_BUF and not HAVE_CANCELBUF. + * pthreadP.h: Declare __pthread_unwind. Define __do_cancel to use + it. Declare old cleanup handler installation functions. + * cleanup.c: Rewrite. Install handler for unwind-based cleanup + handling. + * cleanup_defer.c: Likewise. + * cleanup_compat.c: New file. Old cleanup code. + * cleanup_def_compat.c: New file. Old cleanup code. + * pthread_create.c (start_thread): Initialize cleanup_jmp_buf element + if own thread descriptor. + * unwind.c: New file. + * forward.c: Add __pthread_unwind. + * init.c (pthread_functions): Add __pthread_unwind. + * sysdeps/pthread/pthread-functions.s (struct pthread_functions): + Add ptr___pthread_unwind. + * Versions [GLIBC_2.3.3] (libpthread): Export new cleanup handling + and unwind function. + * Makefile (libpthread-routines): Add cleanup_compat, + cleanup_def_compat, and unwind. Define CFLAGS to enable unwind + table generation if necessary. + * version.c: Record whether unwind support is compiled in. + * sysdeps/pthread/configure.in: Add checks for unwind unterfaces. + * sysdeps/pthread/bits/libc-lock.h: Add prototypes of the old cleanup + handler interfaces. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of + complication to generate unwind information for syscall wrappers. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define + __cleanup_fct_attribute. + + * Makefile: Add rules to build and run tst-cleanup0. + * tst-cleanup0.c: New file. + * tst-cleanup0.expect: New file. + + * pthread_create.c (deallocate_tsd): Don't take parameter. Adjust + caller. Optimize to avoid often unecessary local variable. + +2003-04-11 Roland McGrath <roland@redhat.com> + + * Makefile ($(objpfx)multidir.mk): New target, generated makefile that + sets variable `multidir'; include that. + (generated): Add it. + ($(objpfx)$(multidir)/crti.o): New target. + [$(multidir) != .] (generated-dirs, extra-objs, omit-deps): Add it. + +2003-04-11 Ulrich Drepper <drepper@redhat.com> + + * tst-attr2.c (do_test): Add cast to avoid warning. + * tst-mutex4.c (do_test): Likewise. + +2003-04-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Reset CPU clocks + in child. + +2003-04-09 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-detach1. + * tst-detach1.c: New file. + +2003-04-08 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Remove duplicate + pthread_cleanup_{push,pop} definitions. + + * tst-barrier2.c: Eliminate warnings. + * tst-cancel4.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-detach1.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-rwlock6.c: Likewise. + * tst-rwlock7.c: Likewise. + * tst-sem3.c: Likewise. + * tst-spin2.c: Likewise. + * tst-umask1.c: Likewise. + +2003-04-07 Ulrich Drepper <drepper@redhat.com> + + * pthread_detach.c (pthread_detach): Fix test for invalid TID. + +2003-04-06 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move cancelhandling member to the front. + +2003-04-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/register-atfork.c: Define malloc_prepare, + malloc_parent, and malloc_child statically. + (__register_atfork_malloc): New function. + (free_mem): Don't free any of the malloc_* variables on the list. + * sysdeps/unix/sysv/linux/fork.h: Declare __register_atfork_malloc. + Define HAVE_register_atfork_malloc. + +2003-04-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/createthread.c (create_thread): Add some more + comments explaining when to set multiple_threads and when not. + + * pthreadP.h: Define THREAD_ATOMIC_CMPXCHG_VAL and + THREAD_ATOMIC_BIT_SET if not already defined. + * sysdeps/i386/tls.h: Define THREAD_ATOMIC_CMPXCHG_VAL and + THREAD_ATOMIC_BIT_SET: + * sysdeps/x86_64/tls.h: Likewise. + * cleanup_defer.c (_pthread_cleanup_push_defer): Rewrite to use + THREAD_ATOMIC_CMPXCHG_VAL. + (_pthread_cleanup_pop_restore): Likewise. + * cancellation.c (__pthread_enable_asynccancel): Likewise. + (__pthread_enable_asynccancel_2): Likewise. + (__pthread_disable_asynccancel): Likewise. + * libc-cancellation.c (__libc_enable_asynccancel): Likewise. + (__libc_disable_asynccancel): Likewise. + * init.c (sigcancel_handler): Likewise. + * pthread_setcancelstate.c (__pthread_setcancelstate): Likewise. + * pthread_setcanceltype.c (__pthread_setcanceltype): Likewise. + +2003-04-03 Ulrich Drepper <drepper@redhat.com> + + * init.c (sigcancel_handler): Don't set EXITING_BIT here. + * libc-cancellation.c (__libc_enable_asynccancel): Likewise. + * pthreadP.h (__do_cancel): Set EXITING_BIT here. + * Makefile (tests): Add tst-cancel11. + * tst-cancel11.c: New file. + +2003-04-01 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (deallocate_tsd): Clear/free memory after the last + round, not the first. Use specific_used flag instead of local + found_nonzero variable. Use THREAD_[SG]ETMEM where possible. + (__free_tcb): Don't call deallocate_tsd here. + (start_thread): Call deallocate_tsd here. + * pthread_setspecific.c: Set specific_used flag really only when + needed. + * Makefile (tests): Add tst-tsd3.c and tst-tsd4. + * tst-tsd3.c: New file. + * tst-tsd4.c: New file. + +2003-03-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_mutex_lock): + Use atomic_exchange_and_add instead of __lll_add. + (__lll_mutex_timedlock): Likewise. + Patch by Ian Wienand. + +2003-03-24 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Fix typo. + * tst-cancel-wrappers.sh: Handle '.'ed symbols. + +2003-03-31 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-align. + * tst-align.c: New file. + * sysdeps/i386/Makefile: Define CFLAGS-tst-align. + + * sysdeps/i386/tls.h (CALL_THREAD_FCT): Align stack of called + function correctly. + + * tst-tsd2.c: Add casts to avoid warnings. + +2003-03-30 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move most often used elements to the front. + +2003-03-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pthread_atfork. + (libpthread-static-only-routines): Add pthread_atfork. + +2003-03-28 Kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/tls.h: Include nptl/descr.h after the definition + of TLS_DTV_AT_TP. + (INSTALL_DTV): Add parens. + (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, THREAD_SETMEM_NC): + Use passed descr instead of THREAD_SELF. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S + (__lll_mutex_timedlock_wait): Correct expected value after + spurious wakeup. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: + Release lock before waking up the waiters. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: Correct exit + criteria. Reorderstruct passed to cleanup handler. Fix + handling of cancellation and failung pthread_mutex_unlock call. + Use __pthread_enable_asynccancel_2 instead of + __pthread_enable_asynccancel. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + Return result of lock re-get if it fails. + * sysdeps/unix/sysv/linux/sh/pthread_once.S: Fix wrong argument + for __pthread_cleanup_push. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Fix + completely broken rwlock implementation. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_post.S: Fix error value. Use + versioned_symbol macro. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Use versioned_symbol macro. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise. + +2003-03-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: Don't declare + __timer_helper_thread. Declare __start_helper_thread, __helper_once, + and __helper_tid. + (struct timer): Remove th and bar field. + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): Remove + debugging code. Create only one helper thread. + * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Don't kill + helper thread. + * sysdeps/unix/sysv/linux/timer_routines.c (timer_helper_thread): + Renamed. Define statically. Use thread info from siginfo. + (__helper_once): New variable. + (__helper_tid): New variable. + (__reset_helper_control): New function. + (__start_helper_thread): New function. + + * pthread_create.c (start_thread): Don't use setjmp inside + __builtin_expect to work around gcc bug. + + * sysdeps/unix/sysv/linux/timer_delete.c (timer_delete): Even if + timer_delete syscall fails, but not with ENOSYS, set + __no_posix_timers. + + * sysdeps/unix/sysv/linux/timer_settime.c [!__ASSUME_POSIX_TIMERS] + (timer_settime): Fix typo. + * sysdeps/unix/sysv/linux/timer_getoverr.c + [!__ASSUME_POSIX_TIMERS] (timer_getoverrun): Likewise. + +2003-03-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Fix + offset of cleanupbuf.__prev. + +2003-03-26 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/timer_getoverr.c: Fix typo in name + of included file. + +2003-03-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/timer_create.c (timer_create): If EVP == + NULL provide default definition to syscall. + +2003-03-25 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/posix-timer.h (TIMER_MAX): Define if not defined. + (timer_id2ptr): Fix typo. + +2003-03-25 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Define SIGCANCEL and SIGTIMER. + * sysdeps/i386/pthreaddef.h: Remove SIGCANCEL definition. + * sysdeps/ia64/pthreaddef.h: Likewise. + * sysdeps/powerpc/pthreaddef.h: Likewise. + * sysdeps/s390/pthreaddef.h: Likewise. + * sysdeps/sh/pthreaddef.h: Likewise. + * sysdeps/x86_64/pthreaddef.h: Likewise. + * init.c (__pthread_initialize_minimal): Block SIGTIMER. + * sysdeps/pthread/sigaction.c: Also prevent SIGTIMER handler from + being changed. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Make sure + SIGTIMER is not unblocked. + * sysdeps/unix/sysv/linux/allocrtsig.c (current_rtmin): One more + RT signal taken. + * sysdeps/unix/sysv/linux/pthread_kill.c: Do not allow SIGTIMER to + be send. + * sysdeps/pthread/posix-timer.h (timer_id2ptr, timer_ptr2id): Just + pass pointer through as ID. + * sysdeps/unix/sysv/linux/bits/local_lim.h (TIMER_MAX): Removed. + * sysdeps/unix/sysv/linux/kernel-posix-timers.h: New file. + * sysdeps/unix/sysv/linux/timer_create.c: New file. + * sysdeps/unix/sysv/linux/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/timer_routines.c: New file. + * sysdeps/unix/sysv/linux/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/ia64/Versions: New file. + * sysdeps/unix/sysv/linux/ia64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/ia64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/Versions: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c: New file. + * sysdeps/unix/sysv/linux/x86_64/Versions: New file. + * sysdeps/unix/sysv/linux/x86_64/compat-timer.h: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_create.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_delete.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_gettime.c: New file. + * sysdeps/unix/sysv/linux/x86_64/timer_settime.c: New file. + + * pthreadP.h: Remove FRAME_LEFT definition. + * cleanup.c (_pthread_cleanup_push): Don't check for reference to + already left frame. Programs which have this problem are not POSIX + compliant. + * cleanup_defer.c (_pthread_cleanup_push_defer): Likewise. + +2003-03-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/tst-timer.c: Check return values of the + functions we test. + +2003-03-23 Roland McGrath <roland@redhat.com> + + * tst-tls3.c (do_test) [! HAVE___THREAD]: Don't test anything. + * tst-tls3mod.c: Likewise. + * tst-tls1.c: Likewise. + * tst-tls2.c: Likewise. + + * tst-mutex5.c (do_test): Unlock before destroy, otherwise we invoke + undefined behavior. + + * tst-join5.c (tf1, tf2): Add a cast. + + * Makeconfig (includes): Append -I$(..)nptl to this variable. + + * tst-barrier2.c (do_test) [! _POSIX_THREAD_PROCESS_SHARED]: + Don't test anything. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-flock2.c: Likewise. + * tst-mutex4.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-signal1.c: Likewise. + * tst-spin2.c: Likewise. + * tst-cond11.c [! _POSIX_CLOCK_SELECTION]: Likewise. + + * tst-mutex4.c: Use test-skeleton.c. + * tst-spin2.c: Likewise. + * tst-sysconf.c: Likewise. + * tst-barrier2.c: Likewise. + * tst-cond4.c: Likewise. + * tst-cond6.c: Likewise. + * tst-rwlock4.c: Likewise. + * tst-unload.c: Likewise. + * tst-flock2.c (do_test): Use return instead of exit. + +2003-03-22 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/fork.c (__fork): Add libc_hidden_def. + +2003-03-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h + (__lll_mutex_trylock): Use atomic_compare_and_exchange_val_acq + instead of __lll_compare_and_swap. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c (__pthread_once): + Likewise. + Removed definition if __lll_compare_and_swap. + + * cancellation.c: Adjust for new form of compare&exchange macros. + * cleanup_defer.c: Likewise. + * init.c: Likewise. + * libc-cancellation.c: Likewise. + * old_pthread_cond_broadcast.c: Likewise. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + * pthread_cancel.c: Likewise. + * pthread_create.c: Likewise. + * pthread_detach.c: Likewise. + * pthread_join.c: Likewise. + * pthread_key_delete.c: Likewise. + * pthread_setcancelstate.c: Likewise. + * pthread_setcanceltype.c: Likewise. + * pthread_timedjoin.c: Likewise. + * pthread_tryjoin.c: Likewise. + * sysdeps/pthread/createthread.c: Likewise. + +2003-03-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Include <atomic.h>. + Remove __lll_add, __lll_dec_if_positive, and __lll_test_and_set + definitions. Replace uses with calls to atomic_* functions. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/lowlevellock.c: Replace __lll_add and + __lll_test_and_set calls with atomic_exchange_and_add and + atomic_exchange calls respectively. + * sysdeps/unix/sysv/linux/sem_post.c: Likewise. + * sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_port.c: Likewise. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: Likewise. + + * allocatestack.c (allocate_stack): Assume atomic_exchange_and_add + returns the old value. + +2003-03-20 Martin Schwidefsky <sky@mschwid3.boeblingen.de.ibm.com> + + * sysdeps/s390/pthread_spin_lock.c (pthread_spin_lock): Use type + int for variable OLDVAL and correct inline assembler contraint. + * sysdeps/s390/pthread_spin_trylock.c (pthread_spin_trylock): Use + type int for variable OLD. + + * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it + only for s390-32. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h + (SINGLE_THREAD_P): Use global variable __local_multiple_threads + instead of multiple_threads field in the TCB. + +2003-03-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/bits/atomic.h: Removed. + * sysdeps/i386/i586/bits/atomic.h: Removed. + * sysdeps/i386/i486/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/x86_64/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/s390/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/sh/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/ia64/bits/atomic.h: Removed. Moved to glibc. + * sysdeps/powerpc/bits/atomic.h: Removed. Moved to glibc. + * atomic.h: Removed. Moved to glibc. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Add + support for clock selection. + + * sysdeps/pthread/pthread_cond_broadcast.c: Release lock before + signalling waiters. + +2003-03-18 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set): + Add __lll_rel_instr first. Add memory clobber. + (lll_mutex_unlock): Use __lll_test_and_set. + From Paul Mackerras <paulus@samba.org>. + + * sysdeps/powerpc/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define + unconditionally. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h + (SINGLE_THREAD_P): Add `header.' prefix. + From Paul Mackerras <paulus@samba.org>. + + * Versions (libpthread: GLIBC_2.3.2): Move pthread_tryjoin_np and + pthread_timedjoin_np to ... + (libpthread: GLIBC_2.3.3): ... here. + (libpthread: GLIBC_2.2): Move pthread_barrierattr_getpshared there too. + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Avoid shadowing VAL variable. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h (__lll_test_and_set): + New macro. + +2003-03-18 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond11. + * tst-cond11.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Reorder + struct passed to cleanup handler to eliminate one more + instruction. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthrad_cond_t): Replace __unused field with __clock. + + * sysdeps/pthread/pthread_cond_wait.c: Release condvar lock before + waken all waiters in cleanup handler. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + + * pthread_condattr_getclock.c: New file. + * pthread_condattr_setclock.c: New file. + * sysdeps/pthread/pthread.h: Declare these new functions. + * Versions [GLIBC_2.3.3] (libpthread): Add the new functions. + * Makefile (libpthread-routines): Add the new functions. + * sysdeps/unix/sysv/linux/internaltypes.h (struct pthread_condattr): + Renamed field to value. Document use of the bits. + * pthread_condattr_getpshared.c: Adjust for struct pthread_condattr + change. + * pthread_condattr_setpshared.c: Likewise. + * pthread_cond_init.c (__pthread_cond_init): Initialized __clock field. + * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add cond_clock symbol. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Add __clock field. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: + Implement clock selection. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * pthread-errnos.sym: Add ENOSYS. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_CLOCK_SELECTION. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Remove + invalid .size directive. + +2003-03-17 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_lock_wait): + Formatting tweaks. + +2003-03-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: Use __builtin_expect. + Use __lll_add instead of spelling it out. Use protected symbol names. + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Use __builtin_expect. + Use __lll_add. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (__lll_compare_and_swap): + Renamed from lll_compare_and_swap. Use new name where necessary. + (__lll_add): Defined. + (__lll_dec_if_positive): Defined. + (__lll_test_and_set): Defined. + * sysdeps/ia64/pthread_spin_init.c: Removed. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Removed. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: Removed. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: Removed. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Removed. + * sysdeps/ia64/bits/atomic.h: Add __builtin_expect where appropriate. + * sysdeps/ia64/pthread_spin_unlock.c (pthread_spin_unlock): Use + __sync_lock_release_si. + Patch by Jakub Jelinek. + + * sysdeps/unix/sysv/linux/lowlevellock.c (__lll_timedlock_wait): + Fix timeout handling. + (__lll_timedwait_tid): Likewise. + (lll_unlock_wake_cb): Wake up other waiters if necessary. + Patch by Jakub Jelinek. + + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Pretty printing. + +2003-03-17 Roland McGrath <roland@redhat.com> + + PowerPC port contributed by Paul Mackerras <paulus@samba.org>. + * sysdeps/pthread/pthread_spin_init.c: New file. + * sysdeps/pthread/pthread_spin_unlock.c: New file. + * sysdeps/powerpc/Makefile: New file. + * sysdeps/powerpc/pthread_spin_lock.c: New file. + * sysdeps/powerpc/pthread_spin_trylock.c: New file. + * sysdeps/powerpc/pthreaddef.h: New file. + * sysdeps/powerpc/tcb-offsets.sym: New file. + * sysdeps/powerpc/td_ta_map_lwp2thr.c: New file. + * sysdeps/powerpc/tls.h: New file. + * sysdeps/powerpc/bits/atomic.h: New file. + * sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/lowlevellock.c: New file. + + * sysdeps/unix/sysv/linux/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/sem_post.c: New file. + * sysdeps/unix/sysv/linux/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/sem_trywait.c: New file. + * sysdeps/unix/sysv/linux/sem_wait.c: New file. + * sysdeps/unix/sysv/linux/powerpc/Makefile: New file. + * sysdeps/unix/sysv/linux/powerpc/createthread.c: New file. + * sysdeps/unix/sysv/linux/powerpc/fork.c: New file. + * sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/powerpc/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: New file. + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: Use __gettimeofday, + not gettimeofday. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Likewise. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + +2003-03-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_wait.c: Correct exit criteria. + * sysdeps/pthread/pthread_cond_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + Patch by Ewald Snel <ewald@rambo.its.tudelft.nl>. + +2003-03-16 Roland McGrath <roland@redhat.com> + + * tst-fork4.c: Include <string.h>. + * tst-signal2.c: Likewise. + * tst-mutex5.c (do_test): exit -> return. + * tst-mutex2.c: Include <stdlib.h>. + +2003-03-16 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_timedlock_wait): Correct expected value after + spurious wakeup. Otherwise we would never wait again. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Work around red + zone versus inline asm stupidity. Use correct instructions. + + * tst-rwlock6.c: Add some more status output. + +2003-03-15 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/configure.in: New file. + * sysdeps/pthread/configure: New file (generated). + +2003-03-15 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Store the exact stack size of + user allocated stacks. + +2003-03-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h + (SINGLE_THREAD): Use `header' prefix instead of `header.data'. + * sysdeps/sh/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise. + * sysdeps/sh/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h (SINGLE_THREAD_P): + Use `header.' prefix. + * sysdeps/ia64/tcb-offsets.sym (MULTIPLE_THREADS_OFFSET): Likewise. + +2003-03-15 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/pthreaddef.h (CURRENT_STACK_FRAME): Don't use + __builtin_frame_address, use stack pointer. + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Use CURRENT_STACK_FRAME + instead of __builtin_frame_pointer. + +2003-03-14 Ulrich Drepper <drepper@redhat.com> + + * tst-basic1.c (do_test): Add cast to avoid warning. + * tst-basic2.c (do_test): Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Use correct + amount of stack correction. + + * tst-fork4.c: Use test-skeleton.c. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * init.c: Fix typo "#eli" for "#else". + +2003-03-14 Steven Munroe <sjmunroe@us.ibm.com> + + * allocatestack.c (__stack_user): Use hidden_data_def. + * pthread_create.c (__pthread_keys): Likewise. + + * init.c [__powerpc__] (__NR_set_tid_address): Define it. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * tst-fork4.c: New file. + * Makefile (tests): Add it. + + * descr.h (struct pthread): Move the union out of [!TLS_DTV_AT_TP], so + we always define the padding space. + [!TLS_DTV_AT_TP]: Give tcbhead_t field a name, `header', since GCC + stopped supporting its own extensions fully. + [TLS_MULTIPLE_THREADS_IN_TCB]: Put `multiple_threads' inside a wrapper + struct also called `header', so `header.multiple_threads' is the field + name to use on all machines. + * allocatestack.c (allocate_stack): Use `header.' prefix. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * pthread_create.c (__pthread_create_2_1): Likewise. + * sysdeps/i386/tls.h (INSTALL_NEW_DTV, THREAD_DTV): Likewise. + (THREAD_SELF): Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + + * sysdeps/s390/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Use REGS[18] + value directly. + +2003-03-14 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (start_thread): Use CALL_THREAD_FCT if defined. + * sysdeps/i386/tls.h: Define CALL_THREAD_FCT. + + * pthread_create.c (start_thread): setjmp is expected to return 0. + + * sysdeps/x86_64/tls.h (THREAD_GETMEM): Mark asms volatile. + (THREAD_GETMEM_NC): Likewise. + +2003-03-13 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): If MULTI_PAGE_ALIASING is defined + and the size of the stack which must be allocated is a multiple, + allocate one more page. + * sysdeps/i386/i686/Makefile: Don't define COLORING_INCREMENT, but + MULTI_PAGE_ALIASING. + +2003-03-13 Roland McGrath <roland@redhat.com> + + * pthread_create.c (start_thread): Set EXITING_BIT after the + event-reporting (and destructors), not before. + +2003-03-13 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h (lll_futex_timed_wait, + lll_futex_wake): Declare register variables as long int instead of + unsigned long int. Patch by Ian Wienand <ianw@gelato.unsw.edu.au>. + Make syscall arguments clobbered by the syscall. + (lll_futex_wait): Define using lll_futex_timed_wait. + + * sysdeps/ia64/td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Cast regs[13] + to void *. + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Only declare and set + PPID if [! NDEBUG]. + + * allocatestack.c (nptl_ncreated): Only declare if + COLORING_INCREMENT != 0. + + * pthreadP.h (__pthread_enable_asynccancel_2): New prototype. + (__libc_enable_asynccancel_2): Remove prototype. + + * sysdeps/unix/sysv/linux/ia64/fork.c (ARCH_FORK): Swap ptid and + ctid to match kernel. + +2003-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Add + libc_multiple_threads. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Move definition of + __libc_multiple_threads to... + * sysdeps/unix/sysv/linux/libc_multiple_threads.c: ...here. New file. + + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Remove unnecessary + versioning. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S + (__pthread_once_internal): Define. + + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Use shlib-compat.h + macros instead of .symver directly. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise. + + * sysdeps/x86_64/tls.h [__ASSEMBLER__]: Include tcb-offsets.h. + * sysdeps/x86_64/tcb-offsets.sym: New file. + * sysdeps/x86_64/Makefile: New file. + + * sysdeps/i386/tcb-offsets.sym: Add SELF. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Use SELF + to access own pthread_t in TCB. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + +2003-03-12 Roland McGrath <roland@redhat.com> + + * pthread-errnos.sym: New file. + * Makefile (gen-as-const-headers): New variable, list that file. + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Include generated + header <pthread-errnos.h> instead of defining errno values here. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Likewise. + * sysdeps/i386/i486/pthread_spin_trylock.S: Likewise. + * sysdeps/x86_64/pthread_spin_trylock.S: Likewise. + * sysdeps/sh/pthread_spin_trylock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: Likewise. + + * sysdeps/unix/sysv/linux/fork.c: Add an assert to check that + CLONE_CHILD_SETTID worked. + +2003-03-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S: New + file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S: New + file. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h + (pthread_cond_t): Add padding. + + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S + (__pthread_rwlock_timedwrlock): Add missing opcode suffix. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S + (__pthread_rwlock_timedrdlock): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S + (__pthread_rwlock_wrlock): Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S + (__pthread_rwlock_rdlock): Likewise. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Return + result of lock re-get if it fails. + +2003-03-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: Fix asm syntax. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise. + + * sysdeps/x86_64/tls.h (THREAD_SELF, THREAD_GETMEM, THREAD_GETMEM_NC, + THREAD_SETMEM, THREAD_SETMEM_NC): Correct asm syntax. + + * allocatestack.c [! TLS_MULTIPLE_THREADS_IN_TCB] (allocate_stack): + Initialize *__libc_multiple_threads_ptr not __libc_multiple_threads. + * sysdeps/pthread/createthread.c [! TLS_MULTIPLE_THREADS_IN_TCB] + (create_thread): Likewise. + Define __pthread_multiple_threads and __libc_multiple_threads_ptr. + * init.c (__pthread_initialize_minimal_internal): Initialize + __libc_multiple_threads_ptr if necessary. + * pthreadP.h: Adjust prototype for __libc_pthread_init. Declare + __pthread_multiple_threads and __libc_multiple_threads_ptr. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Define + __libc_multiple_threads. + (__libc_pthread_init): Return pointer to __libc_pthread_init if + necessary. + + * sysdeps/i386/tls.h (THREAD_SETMEM): Fix one-byte variant. + (THREAD_SETMEM_NC): Likewise. + + * sysdeps/x86_64/pthread_spin_trylock.c: Removed. + * sysdeps/x86_64/pthread_spin_trylock.S: New file. + * sysdeps/x86_64/pthread_spin_unlock.c: Removed. + * sysdeps/x86_64/pthread_spin_unlock.S: New file. + + * sysdeps/i386/i486/pthread_spin_trylock.S (pthread_spin_trylock): + Eliminate one entire instruction. + + * cancellation.c (__pthread_enable_asynccancel_2): New function. + * pthreadP.h: Declare __pthread_enable_asynccancel_2. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Use __pthread_enable_asynccancel_2 + instead of __pthread_enable_asynccancel. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Likewise. + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Likewise. + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__condvar_cleanup): Wake up all waiters in case we got signaled + after being woken up but before disabling asynchronous + cancellation. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S + (__condvar_cleanup): Likewise. + + * init.c (__NR_set_tid_address): If already defined, don't redefine. + Make it an error if architecture has no #if case. Add x86-64. + + * sysdeps/unix/sysv/linux/x86_64/Makefile: Add flags for + pt-initfini.s generation. + + * sysdeps/x86_64/tls.h: Include <asm/prctl.h>. + (TLS_INIT_TP): Fix typo. + +2003-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/ia64/bits/atomic.h (atomic_exchange_and_add): Swap 2nd and + 3rd argument of __arch_compare_and_exchange_{32,64}_val_acq. + + * sysdeps/unix/sysv/linux/ia64/sem_post.c: Include semaphore.h. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise. + +2003-03-11 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Return the result of the final + locking. If it succeeds, the regular function return value. + + * sysdeps/pthread/pthread_cond_wait.c (__pthread_cond_wait): + Return result of the final locking. + * version.c (__nptl_main): Work around problems with the strange + INTERNAL_SYSCALL macro on ppc32. + * init.c (__pthread_initialize_minimal_internal): Unblock + SIGCANCEL in case the parent blocked it. + Reported by Paul Mackerras <paulus@samba.org>. + + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: New file. + +2003-03-11 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_cond_timedwait.c + (__pthread_cond_timedwait): Unlock and fail if + __pthread_mutex_unlock_internal failed. + + * sysdeps/pthread/createthread.c (ARCH_CLONE): Define if not defined. + (create_thread): Only assert PD->tcb != NULL under [TLS_TCB_AT_TP]. + Use ARCH_CLONE. + * allocatestack.c (ALLOCATE_STACK_PARMS): New macro. + [NEED_SEPARATE_REGISTER_STACK] (STACK_VARIABLES, + STACK_VARIABLES_ARGS, STACK_VARIABLES_PARMS, ALLOCATE_STACK_PARMS, + ALLOCATE_STACK): New macros. + (TLS_TPADJ): New macro. + (get_cached_stack, queue_stack, __deallocate_stack): Use TLS_TPADJ. + (allocate_stack): Handle TLS_DTV_AT_TP and + NEED_SEPARATE_REGISTER_STACK. Use TLS_TPADJ. + * pthread_create.c (__pthread_create_2_1) [! TLS_TCB_AT_TP]: + Don't set PD->self. + * init.c [__ia64__] (__NR_set_tid_address): Define. + + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/ia64/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/ia64/fork.c: New file. + * sysdeps/unix/sysv/linux/ia64/createthread.c: New file. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/ia64/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/ia64/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/ia64/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/ia64/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/ia64/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_post.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_trywait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sem_wait.c: New file. + * sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: New file. + * sysdeps/ia64/bits/atomic.h: New file. + * sysdeps/ia64/Makefile: New file. + * sysdeps/ia64/pthread_spin_init.c: New file. + * sysdeps/ia64/pthread_spin_lock.c: New file. + * sysdeps/ia64/pthread_spin_trylock.c: New file. + * sysdeps/ia64/pthread_spin_unlock.c: New file. + * sysdeps/ia64/pthreaddef.h: New file. + * sysdeps/ia64/tcb-offsets.sym: New file. + * sysdeps/ia64/td_ta_map_lwp2thr.c: New file. + * sysdeps/ia64/tls.h: New file. + + * sysdeps/s390/pthreaddef.h (__exit_thread_inline): Pass 1 argument + to syscall instead of no arguments. + +2003-03-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/sem_post.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Fix error value in + unused code. + + * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S: New file + + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add + lowlevelbarrier.sym. + * sysdeps/unix/sysv/linux/lowlevelbarrier.sym: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: + Include lowlevelbarrier.h and don't define offsets locally. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h + (__lll_mutex_lock_wait): Reverse order of first two parameters. + (__lll_mutex_timedlock_wait): Likewise. + (lll_mutex_lock): Adjust asm for that. + (lll_mutex_timedlock): Likewise. Mark cx, cc, r10 as clobbered. + (lll_lock): Adjust asm for operand order change. + * sysdeps/unix/sysv/linux/x86_64/lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevelmutex.S: New file. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (__lll_lock_wait): + Reverse order of parameters. + (__lll_timedwait_tid): Remove regparms attribute. + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: New file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_timedwait_tid): Remove one unnecessary instruction. + + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: Define + __lll_mutex_timedlock_wait only for NOT_IN_libc. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: Include + lowlevelmutex.S. + + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Define + lll_unlock_wake_cb, __lll_wait_tid, and __lll_timedwait_tid only + for NOT_IN_libc. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Include + lowlevellock.S. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Don't define + LOCK is already defined. Don't define __lll_mutex_timedlock_wait + for libc.so. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Only + define LOCK here (if UP is not defined). The actual code is in + lowlevelmutex.S. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Don't define + LOCK is already defined. Don't define lll_unlock_wake_cb and + __lll_timedwait_tid for libc.so. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Only + define LOCK here (if UP is not defined). The actual code is in + lowlevellock.S. + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Not needed anymore. + * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_post.c: Include lowlevellock.h + instead of lowlevelsem.h. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_trywait.c: Likewise. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: Likewise. + + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add + lowlevelrwlock.sym. + * sysdeps/unix/sysv/linux/lowlevelrwlock.sym: New file. + * sysdeps/unix/sysv/linux/i386/lowlevelrwlock.h: Removed. + * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: Removed. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h (lll_trylock): Fix + register loading. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_trylock): Undo + last changed. D'oh. + + * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove declaration + of __libc_locking_needed. + (lll_trylock): Initialize %eax to zero. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Update + pthread_cond_t definition. + +2003-03-10 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/lowlevelcond.sym: New file. + * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add it. + * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: File removed. + * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: Likewise. + + * allocatestack.c (allocate_stack) [!TLS_MULTIPLE_THREADS_IN_TCB]: + Instead of setting PD->multiple_threads, set globals + __pthread_multiple_threads and __libc_multiple_threads. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * sysdeps/i386/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Define it. + * sysdeps/s390/tls.h (TLS_MULTIPLE_THREADS_IN_TCB): Likewise. + + * descr.h (struct pthread): Conditionalize first member on + [!TLS_DTV_AT_TP]. Replace the `header' member with an anonymous union + containing an anonymous tcbhead_t. Move `list' member out. + [TLS_MULTIPLE_THREADS_IN_TCB]: Define a `multiple_threads' member. + * allocatestack.c: Remove use of `header.data.' prefix. + * pthread_create.c: Likewise. + * init.c (__pthread_initialize_minimal_internal): Likewise. + * sysdeps/pthread/createthread.c (create_thread): Likewise. + * sysdeps/i386/tls.h (INSTALL_DTV): Add parens. + (THREAD_SELF, THREAD_DTV, INSTALL_NEW_DTV): No `header.data.' prefix. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h + (SINGLE_THREAD_P): Likewise. + * sysdeps/i386/tls.h (tcbhead_t): Remove `list' member. + * sysdeps/s390/tls.h (tcbhead_t): Likewise. + +2003-03-09 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/lowlevelcond.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/x86_64/fork.c: New file. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Fix many + leftovers from the ia32 code. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Remove unneccessary + memory load. + (clear_once_control): Don't load %esi. + + * sysdeps/x86_64/tls.h: Remove all traces of segment descriptor + handling. + + * sysdeps/unix/sysv/linux/x86_64/fork.c: New file. + + * sysdeps/unix/sysv/linux/s390/createthread.c: Moved to... + * sysdeps/unix/sysv/linux/createthread.c: ...here. + + * Makefile (tests): Add tst-cond10. + * tst-cond10.c: New file. + +2003-03-08 Ulrich Drepper <drepper@redhat.com> + + * tst-tls2.c (do_test): Add TEMP_FAILURE_RETRY around sem_wait call. + * tst-signal3.c (do_test): Likewise. + * tst-sem5.c (do_test): Likewise. + * tst-kill6.c (do_test): Likewise. + * tst-tls3.c (do_test): Likewise. Include <errno.h>. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use add/sub instead + of inc/dec. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise. + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + + * allocatestack.c (allocate_stack): If mprotect() fails free the + TLS memory. + +2003-03-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i486/bits/atomic.h: Fix a few unused definitions. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Remove all trace of + lll_wake_tid. This was used only to work around kernel limits in + the early days. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise. + + * init.c (__static_tls_align_m1): Renamed from __static_tls_align. + (__pthread_initialize_minimal_internal): Change initialization of + __static_tls_align_m1 appropriately. + * pthreadP.h (__static_tls_align_m1): Renamed from + __static_tls_align. + * allocatestack.c (allocate_stack): Use __static_tls_align_m1 + instead of __static_tls_align-1. + +2003-03-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/x86_64/Makefile: New file. + + * pthread_create.c: Define __pthread_keys using nocommon + attribute, not by placing it explicitly in bss. + Remove DEFINE_DEALLOC definition. Not needed anymore. + + * allocatestack.c: Define ARCH_MAP_FLAGS if not already defined. + Use it in mmap call to allocate stacks. + + * sysdeps/pthread/createthread.c (create_thread): Fix comment. + + * pthread_create.c (start_thread): Use THREAD_SETMEM to store + result of the thread function. + +2003-03-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: Removed. The generic + version is just fine. + + * sysdeps/unix/sysv/linux/libc_pthread_init.c + (__pthread_child_handler): Renamed from pthread_child_handler, + exported, and marked hidden. Change all users. + * sysdeps/unix/sysv/linux/register-atfork.c (free_mem): Do not + free __pthread_child_handler from child list. + +2003-03-03 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * atomic.h (atomic_exchange_and_add): Return newval, not oldval. + + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Fix handling of cancellation and failing pthread_mutex_unlock call. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Likewise. + (__pthread_cond_wait): Likewise. + + * sysdeps/pthread/pthread_rwlock_timedrdlock.c + (pthread_rwlock_timedrdlock): Fix clobber of result variable by + lll_futex_timed_wait call. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c + (pthread_rwlock_timedwrlock): Likewise. + + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c (___lll_lock): + Don't define lll_unlock_wake_cb and ___lll_timedwait_tid in libc.so. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Remove XXX comments. + + * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Fix + check of lll_futex_wake return value. + +2003-03-03 Roland McGrath <roland@redhat.com> + + * forward.c: Fix typo in __pthread_attr_init_2_0 compat_symbol decl. + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Argument to ptr___pthread_cleanup_upto is __jmp_buf, not jmp_buf. + * sysdeps/unix/sysv/linux/jmp-unwind.c: Likewise. + +2003-03-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/timer_create.c (timer_create): Return correct + error for CPU clocks. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define + _POSIX_MONOTONIC_CLOCK. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Likewise. + + * tst-cancel4.c (tf_sleep): Lower sleep time a bit to not upset + recent kernels. + +2003-03-01 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread): Move cleanup field to the front. + +2003-03-01 Roland McGrath <roland@redhat.com> + + * sem_open.c (sem_open): Braino fix. + +2003-03-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tcb-offsets.sym: Add CLEANUP and CLEANUP_PREV. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Inline + __pthread_cleanup_pop functionality. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + + * descr.h (struct pthread): Move tid field to the front now that + it is often used. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S + (__lll_mutex_timedlock_wait): Remove. + (__lll_mutex_unlock_wake): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S + (__lll_mutex_unlock_wake): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (lll_unlock_wake_cb): Don't save and restore %esi. + (__lll_unlock_wake): Add alignment. Don't save, load, and restore + %esi. + (__lll_timedwait_tid): Add alignment. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S + (__lll_unlock_wake): Add alignment. Don't save, load, and restore + %esi. + (__lll_timedwait_tid): Removed. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S + (__pthread_cond_broadcast): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S + (pthread_barrier_wait): Don't save, load, and restore %esi for + last thread. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S + (__pthread_cond_signal): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S + (__pthread_rwlock_unlock): Don't save, load, and restore %esi. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S (__new_sem_post): + Don't save, load, and restore %esi. + +2003-02-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: + Release lock before waking up the waiters. + + * tst-exit1.c (do_test): Don't start more than one thread in parallel. + + * tst-rwlock9.c (writer_thread): Correct adding TIMEOUT. + (reader_thread): Likewise. + + * sysdeps/pthread/pthread_rwlock_unlock.c + (__pthread_rwlock_unlock): Release internal lock early. Don't try + to wake up readers if there are none. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: + Release internal lock before wake threads. + +2003-02-26 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-rwlock10 and tst-rwlock11. + * tst-rwlock8.c: Initialize lock with INIT. Allow INIT to be + predefined. + * tst-rwlock9.c: Likewise. + * tst-rwlock10.c: New file. + * tst-rwlock11.c: New file. + + * Makefile (tests): Add tst-dlsym1. + * tst-dlsym1.c: New file. + + * init.c (__pthread_initialize_minimal_internal): Set + GL(dl_error_catch_tsd) to __libc_dl_error_tsd. + * Versions (libc:GLIBC_PRIVATE): Export __libc_dl_error_tsd. + +2003-02-24 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c (sem_open): Fix handling of O_CREAT without O_EXCL. + + * tst-cond2.c: Fix sychronization with child. + + * tst-rwlock8.c (reader_thread): Remove unused variable. + + * Makefile: Add rules to build and run tst-tls3. + * tst-tls3.c: New file. + * tst-tls3mod.c: New file. + + * Makefile (tests): Add tst-rwlock8 and tst-rwlock9. + * tst-rwlock8.c: New file. + * tst-rwlock9.c: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Fix + complete broken rwlock implementation. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: Likewise. + * sysdeps/pthread/pthread_rwlock_rdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_unlock.c: Likewise. + * sysdeps/pthread/pthread_rwlock_wrlock.c: Likewise. + +2003-02-23 Roland McGrath <roland@redhat.com> + + * Makefile (nptl-version): Change regexp so case sensitivity is ok. + +2003-02-23 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-context1. + * tst-context1.c: New file. + + * Makefile (tests): Add tst-tls1 and tst-tls2. + * tst-tls1.c: New file. + * tst-tls2.c: New file. + + * libc-cancellation.c (__libc_enable_asynccancel): Correct test + for failed cmpxchg. + + * pthread_create.c (start_thread): Set EXITING_BIT early. + + * sysdeps/i386/tls.h (THREAD_GETMEM): Mark asm as volatile. + (THREAD_GETMEM_NC): Likewise. + +2003-02-22 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Shave + off 3 more bytes by using offset-less instructions when possible. + + * Makefile: Add dependency for $(objpfx)version.d. + + * eintr.c (eintr_source): Add unnecessary return but the compiler + insists. + + * tst-kill3.c: Include <unistd.h>. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * pthread_create.c (start_thread): Call __libc_thread_freeres. + +2003-02-21 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-eintr1. + (distribute): Add eintr.c. + * tst-eintr1.c: New file. + * eintr.c: New file. + + * pthread_cancel.c (pthread_cancel): Use tkill directly. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): + Disallow sending SIGCANCEL. + + * Makefile (tests): Remove tst-basic7. Add tst-kill1, tst-kill2, + tst-kill3, tst-kill4, tst-kill5, tst-kill6. + * tst-kill1.c: New file. + * tst-kill2.c: New file. + * tst-kill3.c: New file. + * tst-kill5.c: New file. + * tst-kill6.c: New file. + * tst-basic7.c: Renamed to... + * tst-kill4.c: ...this. + +2003-02-21 Roland McGrath <roland@redhat.com> + + * Makefile (install-lib-ldscripts): New variable. + +2003-02-21 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Define INVALID_TD_P and INVALID_NOT_TERMINATED_TD_P. + * pthread_cancel.c: Use INVALID_TD_P. + * pthread_detach.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_setschedparam.c: Likewise. + * sysdeps/pthread/pthread_getcpuclockid.c: Likewise. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * pthread_join.c: Use INVALID_NOT_TERMINATED_TD_P. + * pthread_timedjoin.c: Likewise. + + * tst-basic7.c: Include <signal.h>. + + * pthread_join.c (pthread_join): Limited checking for invalid + descriptors. + * pthread_timedjoin.c (pthread_timedjoin_np): Likewise. + +2003-02-20 Ulrich Drepper <drepper@redhat.com> + + * pthread_create.c (deallocate_tsd): Reset found_nonzero at the + beginning of the loop. Clear the entire first block of TSD. + * Makefile (tests): Add tst-key4. + * tst-key4.c: New file. + +2003-02-18 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic7. + * tst-basic7.c: New file. + + * pthread_create.c (deallocate_tsd): Mark as internal_function. + Add some more __builtin_expect. + + * pthreadP.h: Define dummy version of DEBUGGING_P. + +2003-02-17 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remnove + _POSIX_THREAD_PRIORITY_SCHEDULING. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: Remove + _XOPEN_REALTIME_THREADS. + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Likewise. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): The + kernel returns EINVAL for PID <= 0, work around it. + + * Makefile (tests): Add tst-signal5. + * tst-signal5.c: New file. + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Define TTY_NAME_MAX + and LOGIN_NAME_MAX. + + * tst-cancel1.c (tf): Block all signals. + + * Makefile (tests): Add tst-basic6. + * tst-basic6.c: New file. + + * tst-basic1.c: Add test for process ID. + + * Makefile (tests): Add tst-cancel10. + * tst-cancel10.c: New file. + + * Makefile (tests): Add tst-signal4. + * tst-signal4.c: New file. + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use + __sigismember instead of sigismember. Add __builtin_expect. + +2003-02-16 Ulrich Drepper <drepper@redhat.com> + + * tst-attr1.c (do_test): Add tests for pthread_setcanceltype, + pthread_setcancelstate, and pthread_rwlock_setpshared. + + * tst-cancel7.c (do_test): Make sure the pid file exists before + canceling the thread. + + * tst-rwlock6.c: More pthread_rwlock_timedwrlock and + pthread_rwlock_timedrdlock tests. + * tst-rwlock7.c: More pthread_rwlock_timedwrlock tests. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + Check for invalid tv_nsec field. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + Likewise. + + * pthread_mutex_trylock.c (__pthread_mutex_trylock): Protect + recursive mutex of overflow. + + * tst-attr1.c (do_test): Add test for pthread_mutexattr_setpshared. + + * libc-cancellation.c (__libc_enable_asynccancel): Rewrite to avoid + going into an endless loop. + * Makefile (tests): Add tst-cancel9. + * tst-cancel9.c: New file. + + * pthread_cancel.c (pthread_cancel): Use the result of __pthread_kill. + +2003-02-15 Ulrich Drepper <drepper@redhat.com> + + * tst-mutex5.c (do_test): Add more timedlock tests. + + * tst-mutex2.c: Tests of trylock and unlock with ERROR mutexes. + * tst-mutex3.c (do_test): Add tests for trylock with RECURSIVE mutexes. + + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Don't + use INLINE_SYSCALL. Error number is returned, not -1. + + * pthreadP.h: Mark declarations of __find_in_stack_list, __free_tcb, + and __deallocate_stack with internal_function. + * pthread_create.c: Adjust definitions appropriately. + * allocatestack.c: Likewise. + + * pthread_join.c: Add one more __builtin_expect. + * pthread_timedjoin.c: Likewise. + + * pthread_getspecific.c (__pthread_getspecific): Clear data->data + not data of sequence number does not match. + Add one __builtin_expect. + + * Makefile (tests): Add tst-clock1. + * tst-clock1.c: New file. + + * pthread_setconcurrency.c (pthread_setconcurrency): Fail for + negative arguments. + * Makefile (tests): Add tst-basic5. + * tst-basic5.c: New file. + +2003-02-14 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic4. + * tst-basic4.c: New file. + + * pthreadP.h: Add declaraction for __nptl_nthreads. + * pthread_create.c: Define __nptl_nthreads + (start_thread): Increment __nptl_nthreads at beginning. Decrement + after thread is done. If then zero, call exit(0). + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Add ptr_nthreads. Define HAVE_PTR_NTHREADS. + * init.c (pthread_functions): Initialize ptr_nthreads. + * allocatestack.c (nptl_nthreads): Remove definition and all uses. + (__reclaim_stacks): Decrement __nptl_nthreads. + * sysdeps/pthread/Makefile [$(subdir)==csu] (CFLAGS-libc-start.c): + Define. + * Makefile (tests): Add tst-basic3. + * tst-basic3.c: New file. + + * descr.h: Define CANCELING_BIT and CANCELING_BITMASK. Introduce + after CANCELTYPE_BIT, move the other bits up. Update CANCEL_RESTMASK. + * init.c (sigcancel_handler): Also set CANCELING_BITMASK bit in newval. + * pthread_cancel.c (pthread_cancel): Likewise. Also set CANCELING_BIT + if asynchronous canceling is enabled. + * pthread_join.c (pthread_join): When recognizing circular joins, + take into account the other thread might be already canceled. + * Makefile (tests): Add tst-join5. + * tst-join5.c: New file. + + * Makefile (tests): Add tst-join4. + * tst-join4.c: New file. + +2003-02-13 Ulrich Drepper <drepper@redhat.com> + + * tst-cond4.c (main): Add test of pthread_attr_getpshared. + +2003-02-13 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/s390/tls.h (THREAD_GETMEM, THREAD_GETMEM_NC, THREAD_SETMEM, + THREAD_SETMEM_NC): Use passed descr instead of THREAD_SELF. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c (_longjmp_unwind): Avoid + warning. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: Include <sys/time.h> + to avoid warning. + * sysdeps/unix/sysv/linux/s390/sem_post.c (__new_sem_post): Return + error if lll_futex_wake failed. + +2003-02-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Fix + handling of cancellation and failung pthread_mutex_unlock call. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * Makefile (tests): Add tst-cond8 and tst-cond9. + * tst-cond8.c: New file. + * tst-cond9.c: New file. + + * tst-cond7.c (do_test): Unlock the mutex before canceling the thread. + + * sysdeps/pthread/pthread.h: Add missing initializers. Protect + non-standard initializers with __USE_GNU. + + * Makefile (tests): Add tst-cleanup3. + * tst-cleanup3.c: New file. + +2003-02-12 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-attr1 and tst-attr2. + * tst-attr1.c: New file. + * tst-attr2.c: New file. + + * Makefile: Add rules to build and run tst-atfork2 test. + * tst-atfork2.c: New file. + * tst-atfork2mod.c: New file. + + * sysdeps/unix/sysv/linux/unregister-atfork.c + (__unregister_atfork): Free the memory allocated for the handlers + after removing them from the lists. + + * sysdeps/unix/sysv/linux/register-atfork.c: Define memeory + cleanup function. + + * tst-atfork1.c (do_test): Wait for the child we forked. + Report error in child. + + * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Fix comment. + + * sysdeps/pthread/Makefile: Define CFLAGS-confstr.c. + +2003-02-10 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel8. + * tst-cancel8.c: New file. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S (clear_once_control): Fix + clearing of control variable. + * Makefile (tests): Add tst-once3 and tst-once4. + * tst-once3.c: New file. + * tst-once4.c: New file. + +2003-02-08 kaz Kojima <kkojima@rr.iij4u.or.jp> + + * sysdeps/sh/Makefile: New file. + * sysdeps/sh/bits/atomic.h: New file. + * sysdeps/sh/pthread_spin_init.c: New file. + * sysdeps/sh/pthread_spin_lock.c: New file. + * sysdeps/sh/pthread_spin_trylock.S: New file. + * sysdeps/sh/pthread_spin_unlock.S: New file. + * sysdeps/sh/pthreaddef.h: New file. + * sysdeps/sh/tcb-offsets.sym: New file. + * sysdeps/sh/td_ta_map_lwp2thr.c: New file. + * sysdeps/sh/tls.h: New file. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/sh/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/sh/createthread.c: New file. + * sysdeps/unix/sysv/linux/sh/fork.c: New file. + * sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/sh/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelcond.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/sh/lowlevelrwlock.h: New file. + * sysdeps/unix/sysv/linux/sh/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/sh/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_once.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_post.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/sh/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/sh/sysdep-cancel.h: New file. + +2003-02-08 Ulrich Drepper <drepper@redhat.com> + + * tst-cond2.c: Rearrange code to not rely on behavior undefined + according to POSIX. + + * tst-basic2.c (do_test): Lock mutex before creating the thread. + +2003-02-07 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/tls.h: Remove unnecessary macros, left over from x86. + (TLS_GET_FS): New #define. + (TLS_SET_FS): New #define. + Correct value of __NR_set_thread_area. + + * sysdeps/x86_64/td_ta_map_lwp2thr.c: New file. + +2003-02-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-popen1. + * tst-popen1.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Remove wrong + but inactive generalization. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: Likewise. + Minor optimization, remove one instruction. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Likewise. + +2003-02-04 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * sysdeps/unix/sysv/linux/s390/fork.c: Correct order of parameters. + +2003-01-31 Martin Schwidefsky <schwidefsky@de.ibm.com> + + * init.c (__NR_set_tid_address): Add #ifdef for s390. + * sysdeps/pthread/pthread_barrier_wait.c: New file. + * sysdeps/pthread/pthread_cond_broadcast.c: New file. + * sysdeps/pthread/pthread_cond_signal.c: New file. + * sysdeps/pthread/pthread_cond_timedwait.c: New file. + * sysdeps/pthread/pthread_cond_wait.c: New file. + * sysdeps/pthread/pthread_rwlock_rdlock.c: New file. + * sysdeps/pthread/pthread_rwlock_timedrdlock.c: New file. + * sysdeps/pthread/pthread_rwlock_timedwrlock.c: New file. + * sysdeps/pthread/pthread_rwlock_unlock.c: New file. + * sysdeps/pthread/pthread_rwlock_wrlock.c: New file. + * sysdeps/s390/Makefile: New file. + * sysdeps/s390/bits/atomic.h: New file. + * sysdeps/s390/pthread_spin_init.c: New file. + * sysdeps/s390/pthread_spin_lock.c: New file. + * sysdeps/s390/pthread_spin_trylock.c: New file. + * sysdeps/s390/pthread_spin_unlock.c: New file. + * sysdeps/s390/pthreaddef.h: New file. + * sysdeps/s390/tcb-offsets.sym: New file. + * sysdeps/s390/td_ta_map_lwp2thr.c: New file. + * sysdeps/s390/tls.h: New file. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: New file. + * sysdeps/unix/sysv/linux/s390/bits/semaphore.h: New file. + * sysdeps/unix/sysv/linux/s390/createthread.c: New file. + * sysdeps/unix/sysv/linux/s390/dl-sysdep.h: New file. + * sysdeps/unix/sysv/linux/s390/fork.c: New file. + * sysdeps/unix/sysv/linux/s390/jmp-unwind.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevellock.h: New file. + * sysdeps/unix/sysv/linux/s390/lowlevelmutex.c: New file. + * sysdeps/unix/sysv/linux/s390/lowlevelsem.h: New file. + * sysdeps/unix/sysv/linux/s390/pthread_once.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-initfini.c: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/pt-vfork.S: New file. + * sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/s390/sem_post.c: New file. + * sysdeps/unix/sysv/linux/s390/sem_timedwait.c: New file. + * sysdeps/unix/sysv/linux/s390/libc-lowlevellock.c: New file. + * sysdeps/unix/sysv/linux/s390/sem_wait.c: New file. + +2003-02-04 Ulrich Drepper <drepper@redhat.com> + + * atomic.h: Add a couple more default implementations. + (atomic_compare_and_exchange_acq): Use + __arch_compare_and_exchange_32_acq in return value definition. It + always exists. + (atomic_bit_set): Renamed from atomic_set_bit. + Add missing atomic_ prefixes. + + * sysdeps/pthread/bits/libc-lock.h (__libc_once): In case no + thread library is available, use correct value to mark initialized + once variable. + +2003-02-03 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): Use __getpagesize instead of + __sysconf to determine pagesize. + + * pthread_create.c: Include <atomic.h>. + * allocatestack.c (allocate_stack): Implement coloring of the + allocated stack memory. Rename pagesize to pagesize_m1. It's the + size minus one. Adjust users. + * sysdeps/i386/i686/Makefile: New file. + +2003-02-02 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c: Improve comment throughout the file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S + (__lll_lock_wait): Add branch prediction. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S + (__lll_lock_wait): Likewise. + (lll_unlock_wake_cb): Removed. + +2003-01-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Remove + _POSIX_THREAD_PRIORITY_SCHEDULING. + +2003-01-30 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread-functions.h (struct pthread_functions): + Fix return type of ptr___pthread_getspecific. + +2003-01-29 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-umask1. + (tst-umask1-ARGS): Define. + * tst-umask1.c: New file. + +2003-01-28 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Remove lowlevelrwlock. Add + pthread_rwlock_rdlock, pthread_rwlock_timedrdlock, + pthread_rwlock_wrlock, pthread_rwlock_timedwrlock, and + pthread_rwlock_unlock. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S: + New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S: New file. + + * Makefile (libpthread-routines): Remove lowlevelcond and + lowlevelsem. Add sem_wait, sem_trywait, sem_timedwait, sem_post, + pthread_cond_wait, pthread_cond_timedwait, pthread_cond_signal, + and pthread_cond_broadcast. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S: Removed + * sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S: Removed + * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/sem_post.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S: New file. + * sysdeps/unix/sysv/linux/i386/lowlevelcond.h: New file. + + * sysdeps/unix/sysv/linux/i386/createthread.c: Define + PREPARE_CREATE and TLS_VALUE with x86-specific bits. All the rest + of the code is moved to ... + * sysdeps/pthread/createthread.c: ...here. New file. + +2003-01-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S + (__new_sem_post): Clear %eax before returning. + Reported by MAEDA Naoaki <maeda.naoaki@jp.fujitsu.com>. + + * Makefile (tests): Add tst-cleanup2. + * tst-cleanup2.c: New file. + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start): + Interpret first parameter correctly. + +2003-01-17 Ulrich Drepper <drepper@redhat.com> + + * Makefile (headers): Add bits/semaphore.h. + +2003-01-16 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h (INIT_SYSINFO): Initialize _head->sysinfo even + if not SHARED. + +2003-01-14 Ulrich Drepper <drepper@redhat.com> + + * sem_open.c (sem_open): Return SEM_FAILED if existing semaphore + must be used and mapping failed. + Reported by Luke Elliott <luke.elliott@activfinancial.com>. + + * Makefile (CFLAGS-pthread_self.os): Define this, not + CFLAGS-pthread_self.c. + +2003-01-13 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Don't export + lll_unlock_wake_cb. + + * Makefile (libpthread-routines): Add version. Add rules to build + version.os and banner.h. + * version.c: New file. + +2003-01-13 Jakub Jelinek <jakub@redhat.com> + + * pthread_mutex_lock.c (__pthread_mutex_lock_internal): Make + the alias unconditional. + * pthread_mutex_unlock.c (__pthread_mutex_unlock_internal): Likewise. + +2003-01-13 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-pthread_self.c): New definition. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Add + INTERNAL_SYSCALL_DECL, add err argument to INTERNAL_SYSCALL* macros. + * sysdeps/unix/sysv/linux/raise.c (raise): Likewise. + * init.c (__pthread_initialize_minimal_internal): Likewise. + +2003-01-07 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (__pthread_cond_timedwait): Add prototype. + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h + (RTLD_CORRECT_DYNAMIC_WEAK): Remove. + (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h + (RTLD_CORRECT_DYNAMIC_WEAK): Remove. + (DL_SYSINFO_IMPLEMENTATION): Change into .text section and back. + +2003-01-06 Jakub Jelinek <jakub@redhat.com> + + * pthreadP.h (LIBC_CANCEL_HANDLED): Define. + * pt-system.c (LIBC_CANCEL_HANDLED): Add. + * tst-cancel-wrappers.sh: Remove all exceptions. + +2003-01-05 Ulrich Drepper <drepper@redhat.com> + + * tst-cancel-wrappers.sh: Invoke gawk not awk since we use GNU awk + features. Reported by Marijn Ros <marijn@mad.scientist.com>. + + * sysdeps/unix/sysv/linux/jmp-unwind.c: Include <pthread-functions.h>. + Use __libc_pthread_functions array if SHARED. + + * pthreadP.h: Move pthread_cond_2_0_t definition to... + * sysdeps/unix/sysv/linux/internaltypes.h: ...here. + + * sysdeps/pthread/bits/libc-lock.h (__libc_ptf_call): New #define. + (__libc_rwlock_rdlock, __libc_rwlock_wrlock, __libc_rwlock_unlock, + __libc_key_create, __libc_getspecific, __libc_setspecific): Use + __libc_ptf_call instead of __libc_maybe_call. + (PTF): New #define. + (__libc_cleanup_region_start): Wrap function name with PTF call. + (__libc_cleanup_region_end): Likewise. + (__libc_cleanup_end): Likewise. + + * pthread_getspecific.c: Add __pthread_getspecific_internal alias. + * pthread_setspecific.c: Add __pthread_setspecific_internal alias. + * pthread_key_create.c: Add __pthread_key_create_internal alias. + * pthreadP.h: Add prototypes. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Add + __pthread_rwlock_rdlock, __pthread_rwlock_wrlock, and + __pthread_rwlock_unlock aliases. + * pthreadP.h: Add prototypes for new aliases. + + * pthreadP.h (struct pthead_functions): Moved to... + * sysdeps/pthread/pthread-functions.h: ...here. New file. + * init.c (pthread_functions): Add initializers for new elements. + + * cleanup_defer.c: Add __pthread_cleanup_push_defer and + __pthread_cleanup_pop_restore aliases. + * pthreadP.h: Add prototypes. + + * cleanup.c: Rename _GI_pthread_cleanup_push to __pthread_cleanup_push + and _GI_pthread_cleanup_pop to __pthread_cleanup_pop. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Adjust caller. + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Likewise. + * pthreadP.h: Adjust prototypes and callers. + +2003-01-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel7. + (tst-cancel7-ARGS): New variable. + * tst-cancel7.c: New file. + + * old_pthread_cond_broadcast.c: Optimize initialization a bit to work + around gcc defficiencies. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + + * pthreadP.h (pthread_cond_2_0_t): Remove unneeded lock element. + +2003-01-03 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cond7. + * tst-cond7.c: New file. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S + (condvar_cleanup): Get condvar address from the right place. + + * atomic.h: Correct definitions of atomic_full_barrier, + atomic_read_barrier, atomic_write_barrier. + + * old_pthread_cond_broadcast.c: Make memory allocate and initialization + race-free. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + +2003-01-03 Jakub Jelinek <jakub@redhat.com> + + * Makefile ($(objpfx)libpthread.so): Depend on ld.so. + +2003-01-03 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h (pthread_cond_2_0_t): New type. + (struct pthread_functions): Use new type for 2.0 condvar callbacks. + Use new type for the 2.0 condvar function prototypes. + * forward.c: Use pthread_cond_2_0_t for 2.0 condvar functions. + * old_pthread_cond_init.c: Use pthread_cond_2_0_t for condvar + parameter. + * old_pthread_cond_destroy.c: Likewise. + * old_pthread_cond_broadcast.c: Likewise. Lock appropriately. + * old_pthread_cond_signal.c: Likewise. + * old_pthread_cond_timedwait.c: Likewise. + * old_pthread_cond_wait.c: Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S + (__pthread_cond_wait): Don't save cancellation mode and seq value + in same location. + + * herrno.c (__h_errno_location): Don't define as weak. + +2003-01-02 Jakub Jelinek <jakub@redhat.com> + + * Versions [libc] (GLIBC_2.3.2): Export pthread_cond_broadcast, + pthread_cond_destroy, pthread_cond_init, pthread_cond_signal + and pthread_cond_wait. + * old_pthread_cond_broadcast.c (__old_pthread_cond_broadcast): + Renamed to... + (__pthread_cond_broadcast_2_0): ... this. + * old_pthread_cond_destroy.c (__old_pthread_cond_destroy): + Renamed to... + (__pthread_cond_destroy_2_0): ... this. + * old_pthread_cond_init.c (__old_pthread_cond_init): + Renamed to... + (__pthread_cond_init_2_0): ... this. + * old_pthread_cond_signal.c (__old_pthread_cond_signal): + Renamed to... + (__pthread_cond_signal_2_0): ... this. + * old_pthread_cond_wait.c (__old_pthread_cond_wait): + Renamed to... + (__pthread_cond_wait_2_0): ... this. + * pthread_cond_destroy.c: Include shlib-compat.h. + (pthread_cond_destroy): Change strong_alias into versioned_symbol. + * pthread_cond_init.c: Include shlib-compat.h. + (pthread_cond_init): Change strong_alias into versioned_symbol. + * pthreadP.h (struct pthread_functions): Rename ptr_pthread_cond_* + fields to ptr___pthread_cond_* and add ptr___pthread_cond_*_2_0 + fields. + (__pthread_cond_broadcast_2_0, __pthread_cond_destroy_2_0, + __pthread_cond_init_2_0, __pthread_cond_signal_2_0, + __pthread_cond_wait_2_0): New prototypes. + (__old_pthread_cond_broadcast, __old_pthread_cond_destroy, + __old_pthread_cond_init, __old_pthread_cond_signal, + __old_pthread_cond_wait): Removed. + * init.c: Include shlib-compat.h. + (pthread_functions): Guard ptr___pthread_attr_init_2_0 + initialization with SHLIB_COMPAT (GLIBC_2_0, GLIBC_2_1). + Rename ptr_pthread_cond_* to ptr___pthread_cond_*, initialize + ptr___pthread_cond_*_2_0 fields. + * forward.c: Export both pthread_cond_*@@GLIBC_2.3.2 and + pthread_cond_*@GLIBC_2.0 compatibility symbols. + + * sysdeps/pthread/sigaction.c (SIGCANCEL): Only define if + LIBC_SIGACTION was not yet defined. + [!defined LIBC_SIGACTION]: Define LIBC_SIGACTION, #include self. + [!defined LIBC_SIGACTION] (__sigaction): New function and + libc_hidden_weak. + [!defined LIBC_SIGACTION] (sigaction): New weak_alias. + [defined LIBC_SIGACTION]: #include_next <sigaction.c>. + +2003-01-02 Jakub Jelinek <jakub@redhat.com> + + * Makefile (CFLAGS-pthread_atfork.c): Add -DNOT_IN_libc. + +2003-01-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + New, larger type definition. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: New condvar + implementation. + * Versions [libpthread]: Add definitions for new pthread_cond_* + interfaces for version GLIBC_2.3.2. + * pthread_cond_init.c: Update initialization for new type definition. + * Makefile (libpthread-routines): Remove pthread_cond_wait, + pthread_cond_timedwait, pthread_cond_signal, and + pthread_cond_broadcast. Add old_pthread_cond_init, + old_pthread_cond_destroy, old_pthread_cond_wait, + old_pthread_cond_timedwait, old_pthread_cond_signal, and + old_pthread_cond_broadcast. + * old_pthread_cond_broadcast.c: New file. + * old_pthread_cond_destroy.c: New file. + * old_pthread_cond_init.c: New file. + * old_pthread_cond_signal.c: New file. + * old_pthread_cond_timedwait.c: New file. + * old_pthread_cond_wait.c: New file. + * pthreadP.h: Add prototypes for the compatibility interfaces. + + * pthread_cond_destroy.c: Don't include <errno.h>. + +2003-01-01 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Avoid + unnecessary zero offset when addressing MUTEX. + +2002-12-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for + __register_atfork. + * sysdeps/unix/sysv/linux/register-atfork.c: Add libc_hidden_def + for __register_atfork. + +2002-12-31 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use __ASSEMBLER__ + instead of ASSEMBLER test macro. + + * sysdeps/unix/sysv/linux/allocrtsig.c (__libc_current_sigrtmin, + __libc_current_sigrtmax): Add libc_hidden_def. + + * sysdeps/pthread/list.h: Remove assert.h include. + +2002-12-31 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Use + __pthread_initialize_minimal_internal not + __pthread_initialize_minimal. + +2002-12-30 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pt-initfini.c (call_initialize_minimal): Mark + __pthread_initialize_minimal as hidden. + + * init.c (__pthread_initialize_minimal_internal): Don't mark as + constructor. + +2002-12-31 Jakub Jelinek <jakub@redhat.com> + + * Makefile ($(inst_libdir)/libpthread.so): Depend on + $(common-objpfx)format.lds, include that into the output script. + Fix comment. + (extra-B-pthread.so): Change linuxthreads/ into nptl/. + +2002-12-28 Andreas Jaeger <aj@suse.de> + + * sysdeps/unix/sysv/linux/xstatconv.c (xstat_conv): Adjust for + nsec resolution changes. + (xstat64_conv): Likewise. + (xstat32_conv): Likewise. + * sysdeps/unix/sysv/linux/kernel_stat.h: Add nsec resolution for + struct kernel_stat. + * sysdeps/unix/sysv/linux/bits/stat.h: Add nsec resolution for + structs stat and stat64. + * time/time.h (__timespec_defined): Define for __USE_MISC. + * io/sys/stat.h [__USE_MISC]: Define __need_timespec for struct stat. + +2002-12-30 Jakub Jelinek <jakub@redhat.com> + + * forward.c (FORWARD2): Renamed from FORWARD3. Remove unused export + argument. + (pthread_attr_init_2_0, pthread_attr_init_2_1): Use FORWARD macro. + (pthread_exit): Use strong_alias to avoid warnings. + * pthreadP.h (struct pthread_functions): Rename ptr_pthread_exit + and ptr_pthread_attr_init_2_* to ptr___pthread_exit and + ptr___pthread_attr_init_2_*. + * init.c (pthread_functions): Adjust. + +2002-12-29 Ulrich Drepper <drepper@redhat.com> + + * forward.c: Make all functions available by default again. It + caused too much trouble. + + * pt-siglongjmp.c: Removed. + +2002-12-28 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Include tcb-offsets.h in assembler. + (SYSINFO_OFFSET, MULTIPLE_THREADS_OFFSET): Remove. + * sysdeps/i386/Makefile: New file. + * sysdeps/i386/tcb-offsets.sym: New file. + * sysdeps/pthread/tcb-offsets.h: New file. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + Remove MULTIPLE_THREADS_OFFSET and SYSINFO_OFFSET checks. + + * sysdeps/unix/sysv/linux/Versions [libc] (GLIBC_PRIVATE): Move + __register_atfork... + (GLIBC_2.3.2): ...here. + +2002-12-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h: Mark pthread_attr_getstackaddr and + pthread_attr_setstackaddr with __attribute_deprecated__. + +2002-12-27 Jakub Jelinek <jakub@redhat.com> + + * pt-system.c (system): Remove cancellation handling. + * tst-cancel-wrappers.sh: Allow pt-system.o* to not use the + cancellation routines. + +2002-12-28 Ulrich Drepper <drepper@redhat.com> + + * descr.h: Include <dl-sysdep.h>. + (struct pthread): Move header.data.list to the back of the struct. + * sysdeps/i386/tls.h (tcbhead_t): Move list to the back of the struct. + (MULTIPLE_THREADS_OFFSET): Adjust offset. + (SYSINFO_OFFSEET): Likewise. + +2002-12-27 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h (USE_DL_SYSINFO): + Define. + (DL_SYSINFO_DEFAULT): Cast to uintptr_t to avoid warnings. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h (NEED_DL_SYSINFO, + DL_SYSINFO_DEFAULT, DL_SYSINFO_IMPLEMENTATION): Define. + (USE_DL_SYSINFO): Undef. + +2002-12-22 Jakub Jelinek <jakub@redhat.com> + + * Makefile (tests-reverse): Use $(objpfx)../libc.so instead of + $(common-objpfx)libc.so. + * tst-cancel4.c (tf_write, tf_writev): Increase buf sizes so that + it is bigger than pipe buffer size even on arches with bigger + page size. + (tf_usleep): Cast usleep argument to useconds_t to avoid warnings. + +2002-12-25 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Implement + correct errno access for case that USE___THREAD is not defined. + +2002-12-24 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Add missing #endif. + Patch by Marijn Ros <marijn@mad.scientist.com>. + +2002-12-22 Roland McGrath <roland@redhat.com> + + * Makefile (omit-deps): Add $(unix-syscalls:%=ptw-%). + +2002-12-20 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/bits/stdio-lock.h (_IO_lock_inexpensive): Define. + +2002-12-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Don't define + NEED_DL_SYSINFO since no processor < i686 had the sysenter opcode. + * sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h: New file. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Use ENTER_KERNEL instead + of int $0x80. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S: Likewise. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Add support for using + sysenter. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Likewise. + + * sysdeps/i386/tls.h: Unconditionally include <dl-sysdep.h>. + + * allocatestack.c (allocate_stack) [NEED_DL_SYSINFO]: Set sysinfo + in new TCB. + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Check + that sysinfo is properly initialized. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define RTLD_PRIVATE_ERRNO + to 1 only for ld.so. + + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: Define + RTLD_CORRECT_DYNAMIC_WEAK. + +2002-12-19 Jakub Jelinek <jakub@redhat.com> + + * forward.c (pthread_attr_init_2_0, pthread_attr_init_2_1): + Use return 0 as 6th argument to FORWARD4. + * pthread_equal.c: Include pthreadP.h instead of pthread.h. + +2002-12-18 Ulrich Drepper <drepper@redhat.com> + + * descr.h (struct pthread) [NEED_DL_SYSINFO]: Add sysinfo member. + * sysdeps/i386/tls.h (tcbhead_t): Add sysinfo member. + Define SYSINFO_OFFSEET if NEED_DL_SYSINFO is defined. + (INIT_SYSINFO): New #define. + (TLS_TP_INIT): Use INIT_SYSINFO. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + At test to make sure SYSINFO_OFFSET value is correct. + * sysdeps/unix/sysv/linux/i386/dl-sysdep.h: New file. + +2002-12-18 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/flockfile.c (flockfile): Change into weak alias. + * sysdeps/unix/sysv/linux/raise.c (gsignal): Add weak alias to raise. + * Versions [libc: GLIBC_2.0]: Add pthread_attr_init. + [libpthread: GLIBC_2.1]: Remove __pthread_rwlock_init, + __pthread_rwlock_destroy, __pthread_rwlock_rdlock, + __pthread_rwlock_wrlock, __pthread_rwlock_unlock, + __pthread_rwlock_tryrdlock and __pthread_rwlock_trywrlock. + +2002-12-18 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Use ENTER_KERNEL + macro instead of using int $0x80 directly. + + * sysdeps/pthread/bits/stdio-lock.h: New file. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevelmutex.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevelmutex.S: New file. + * Makefile (routines): Add libc-lowlevelmutex. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Remove + __i686.get_pc_thunk.dx. + +2002-12-17 Jakub Jelinek <jakub@redhat.com> + + * Makefile (libpthread-shared-only-routines): Add pt-allocrtsig. + (tests): Depend on $(objpfx)tst-cancel-wrappers.out. + ($(objpfx)tst-cancel-wrappers.out): New rule. + * tst-cancel-wrappers.sh: New test. + * tst-locale1.c: Include signal.h. + (uselocale): Test static linking of __libc_current_sigrt*. + +2002-12-17 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cancel6. + * tst-cancel6.c: New file + +2002-12-17 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h (SINGLE_THREAD_P): + Define meaningfully for assembler as well. + * pthreadP.h (struct pthread_functions): Remove + ptr_pthread_attr_init field. Add ptr_pthread_attr_init_2_0 + and ptr_pthread_attr_init_2_1 fields. + * init.c (pthread_functions): Initialize ptr_pthread_attr_init_2_0 + and ptr_pthread_attr_init_2_1 instead of ptr_pthread_attr_init. + * forward.c (FORWARD4): Renamed from FORWARD3. Add export argument. + (FORWARD3): Define using FORWARD4. + (pthread_attr_init): Provide both @GLIBC_2.0 and @@GLIBC_2.1 + versions. + * pt-system.c: Remove duplicate stdlib.h include. + +2002-12-16 Ulrich Drepper <drepper@redhat.com> + + * sem_init.c: Define sem_init@GLIBC_2.0. + * sem_destroy.c: Define sem_destroy@GLIBC_2.0. + * sem_getvalue.c: Define sem_getvalue@GLIBC_2.0. + + * flockfile.c: Moved to... + * sysdeps/pthread/flockfile.c: ...here. New file. + * funlockfile.c: Moved to... + * sysdeps/pthread/funlockfile.c: ...here. New file. + * ftrylockfile.c: Moved to... + * sysdeps/pthread/ftrylockfile.c: ...here. New file. + +2002-12-16 Jakub Jelinek <jakub@redhat.com> + + * libc-cancellation.c: Guard both function with + #if !defined NOT_IN_libc. + * Makefile (libpthread-routines): Use ptw-, not pt- prefix for the + automatically provided pthread wrappers. + * pthreadP.h (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): Define to + CANCEL_* if IS_IN_libpthread and to dummy versions if not in libc + nor in libpthread. + * pt-open.c: Removed. + * pt-fcntl.c: Removed. + * pt-fsync.c: Removed. + * pt-lseek.c: Removed. + * pt-msgrcv.c: Removed. + * pt-msgsnd.c: Removed. + * pt-msync.c: Removed. + * pt-nanosleep.c: Removed. + * pt-open64.c: Removed. + * pt-pause.c: Removed. + * pt-pread.c: Removed. + * pt-pread64.c: Removed. + * pt-pwrite.c: Removed. + * pt-pwrite64.c: Removed. + * pt-read.c: Removed. + * pt-recv.c: Removed. + * pt-recvfrom.c: Removed. + * pt-recvmsg.c: Removed. + * pt-send.c: Removed. + * pt-sendto.c: Removed. + * pt-sigtimedwait.c: Removed. + * pt-sigwait.c: Removed. + * pt-wait.c: Removed. + * pt-waitpid.c: Removed. + * pt-write.c: Removed. + * pt-accept.c: Removed. + * pt-close.c: Removed. + * pt-connect.c: Removed. + * pt-lseek64.c: Removed. + * pt-sendmsg.c: Removed. + * pt-tcdrain.c: Removed. + +2002-12-15 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal_internal): Renamed from + __pthread_initialize_minimal. Make old name an alias. This + converts a normal relocation into a relative relocation. + + * pt-fcntl.c (__fcntl): Use fcntl64 syscall, not fcntl. + + * Versions [libpthread: GLIBC_2.3.2]: Remove creat, poll, pselect, + readv, select, sigpause, sigsuspend, sigwaitinfo, waitid, writev. + * Makefile (libpthread-routines): Remove pt-creat, pt-poll, + pt-pselect, pt-readv, pt-select, pt-sigpause, pt-sigsuspend, + pt-sigwaitinfo, pt-waitid, and pt-writev. + * pt-creat.c: Removed. + * pt-poll.c: Removed. + * pt-pselect.c: Removed. + * pt-readv.c: Removed. + * pt-select.c: Removed. + * pt-sigpause.c: Removed. + * pt-sigsuspend.c: Removed. + * pt-sigwaitinfo.c: Removed. + * pt-waitid.c: Removed. + * pt-writev.c: Removed. + + * init.c (pthread_functions): New variable. + (__pthread_initialize_minimal): Pass pointer to pthread_functions + (or NULL) to __libc_pthread_init. + * forward.c: Rewrite to use __libc:pthread_functions array to get + function addresses. + * sysdeps/unix/sysv/linux/fork.h: Remove __libc_pthread_init + prototype. + * sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init): + Take new parameter. Copy content of variable pointed to by it + to __libc_pthread_init. + + * pthreadP.h (struct pthread_functions): New type. + (__libc_pthread_init): Declare. + + * pthread_attr_destroy.c: Add namespace protected alias. + * pthread_attr_getdetachstate.c: Likewise. + * pthread_attr_getinheritsched.c: Likewise. + * pthread_attr_getschedparam.c: Likewise. + * pthread_attr_getschedpolicy.c: Likewise. + * pthread_attr_getscope.c: Likewise. + * pthread_attr_setdetachstate.c: Likewise. + * pthread_attr_setinheritsched.c: Likewise. + * pthread_attr_setschedparam.c: Likewise. + * pthread_attr_setschedpolicy.c: Likewise. + * pthread_attr_setscope.c: Likewise. + * pthread_cond_broadcast.c: Likewise. + * pthread_cond_destroy.c: Likewise. + * pthread_cond_init.c: Likewise. + * pthread_cond_signal.c: Likewise. + * pthread_cond_wait.c: Likewise. + * pthread_condattr_destroy.c: Likewise. + * pthread_condattr_init.c: Likewise. + * pthread_equal.c: Likewise. + * pthread_exit.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_self.c: Likewise. + * pthread_setcancelstate.c: Likewise. + * pthread_setschedparam.c: Likewise. + * pthread_mutex_destroy.c: Likewise. + * pthread_mutex_init.c: Likewise. + * pthreadP.h: Add prototypes for the aliases. + + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Set + multiple_threads member in correct TCB to 1. + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Define + SINGLE_THREAD_P. If in libc or libpthread examine multiple_thread + member of thread decriptor, otherwise return unconditionally 1. + +2002-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pt-socket.S: Changes folded into the + regular Linux version. Remove file. + * sysdeps/unix/sysv/linux/connect.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/llseek.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/msgrcv.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/msgsnd.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/open64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/poll.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pread.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pread64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pselect.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pwrite.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/pwrite64.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/readv.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recv.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recvfrom.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/recvmsg.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/send.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sendmsg.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sendto.S: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigpause.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigsuspend.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigtimedwait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigwait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/system.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/tcdrain.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/wait.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/waitid.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/waitpid.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/writev.c: Likewise. Remove file. + * sysdeps/unix/sysv/linux/i386/fcntl.c: Likewise. Remove file. + +2002-12-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: New file. + * sysdeps/unix/sysv/linux/open.c: Removed. + * sysdeps/unix/sysv/linux/fsync.c: Removed. + * sysdeps/unix/sysv/linux/lseek.c: Removed. + * sysdeps/unix/sysv/linux/msync.c: Removed. + * sysdeps/unix/sysv/linux/read.c: Removed. + * sysdeps/unix/sysv/linux/close.c: Removed. + * sysdeps/unix/sysv/linux/creat.c: Removed. + * sysdeps/unix/sysv/linux/nanosleep.c: Removed. + * sysdeps/unix/sysv/linux/pause.c: Removed. + * sysdeps/unix/sysv/linux/select.c: Removed. + * sysdeps/unix/sysv/linux/write.c: Removed. + +2002-12-14 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/pt-socket.S: Check multiple_threads + element in TCB to see whether locking is needed. + + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Check that + MULTIPLE_THREADS_OFFSET value is correct. + + * sysdeps/unix/sysv/linux/close.c: New file. + * sysdeps/unix/sysv/linux/connect.S: New file. + * sysdeps/unix/sysv/linux/creat.c: New file. + * sysdeps/unix/sysv/linux/fsync.c: New file. + * sysdeps/unix/sysv/linux/llseek.c: New file. + * sysdeps/unix/sysv/linux/lseek.c: New file. + * sysdeps/unix/sysv/linux/msgrcv.c: New file. + * sysdeps/unix/sysv/linux/msgsnd.c: New file. + * sysdeps/unix/sysv/linux/msync.c: New file. + * sysdeps/unix/sysv/linux/nanosleep.c: New file. + * sysdeps/unix/sysv/linux/open.c: New file. + * sysdeps/unix/sysv/linux/open64.c: New file. + * sysdeps/unix/sysv/linux/pause.c: New file. + * sysdeps/unix/sysv/linux/poll.c: New file. + * sysdeps/unix/sysv/linux/pread.c: New file. + * sysdeps/unix/sysv/linux/pread64.c: New file. + * sysdeps/unix/sysv/linux/pselect.c: New file. + * sysdeps/unix/sysv/linux/pwrite.c: New file. + * sysdeps/unix/sysv/linux/pwrite64.c: New file. + * sysdeps/unix/sysv/linux/readv.c: New file. + * sysdeps/unix/sysv/linux/recv.S: New file. + * sysdeps/unix/sysv/linux/recvfrom.S: New file. + * sysdeps/unix/sysv/linux/recvmsg.S: New file. + * sysdeps/unix/sysv/linux/select.c: New file. + * sysdeps/unix/sysv/linux/send.S: New file. + * sysdeps/unix/sysv/linux/sendmsg.S: New file. + * sysdeps/unix/sysv/linux/sendto.S: New file. + * sysdeps/unix/sysv/linux/sigpause.c: New file. + * sysdeps/unix/sysv/linux/sigsuspend.c: New file. + * sysdeps/unix/sysv/linux/sigtimedwait.c: New file. + * sysdeps/unix/sysv/linux/sigwait.c: New file. + * sysdeps/unix/sysv/linux/sigwaitinfo.c: New file. + * sysdeps/unix/sysv/linux/system.c: New file. + * sysdeps/unix/sysv/linux/tcdrain.c: New file. + * sysdeps/unix/sysv/linux/wait.c: New file. + * sysdeps/unix/sysv/linux/waitid.c: New file. + * sysdeps/unix/sysv/linux/waitpid.c: New file. + * sysdeps/unix/sysv/linux/writev.c: New file. + * sysdeps/unix/sysv/linux/i386/fcntl.c: New file. + + * pt-readv.c: Fix comment. + +2002-12-14 Jakub Jelinek <jakub@redhat.com> + + * tst-cleanup1.c: Include stdlib.h. + + * tst-cancel5.c: New test. + * Makefile (tests): Add tst-cancel5. + (tst-cancel5): Link against libc.so libpthread.so in that order. + +2002-12-13 Ulrich Drepper <drepper@redhat.com> + + * forward.c (test_loaded): Prevent recursive calls. + + * Makefile (routines): Add libc-cancellation. + * libc-cancellation.c: New file. + * descr.h (struct pthread): Add multiple_threads field. + * allocatestack.c (allocate_stack): Initialize multiple_header field of + new thread descriptor to 1. + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): + Initialize multiple_thread field after successful thread creation. + * cancellation.c (__do_cancel): Move to pthreadP.h. + (__pthread_enable_asynccancel): Remove parameter from __do_cancel call. + (__pthread_disable_asynccancel): Add internal_function attribute. + * init.c (sigcancel_handler): Remove parameter from __do_cancel call. + * pthread_setcancelstate.c: Likewise. + * pthread_setcanceltype.c: Likewise. + * pthread_exit.c: Likewise. + * pthreadP.h (CANCELLATION_P): Likewise. + (__do_cancel): Define as static inline. + (LIBC_CANCEL_ASYNC, LIBC_CANCEL_RESET): New #defines. + (__libc_enable_asynccancel, __libc_disable_asynccancel): New + declarations. + * sysdeps/i386/tls.h (tcbhead_t): Add list and multiple_threads + fields. Define MULTIPLE_THREADS_OFFSET. + * sysdeps/pthread/bits/libc-lock.h: Remove __libc_locking_needed + declaration. + * sysdeps/unix/sysv/linux/accept.S: New file. + * sysdeps/unix/sysv/linux/read.c: New file. + * sysdeps/unix/sysv/linux/write.c: New file. + * sysdeps/unix/sysv/linux/i386/pt-socket.S: New file. + * sysdeps/unix/sysv/linux/libc_pthread_init.c: Remove definition and + initialization of __libc_locking_needed. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Don't use + __libc_locking_needed, use multiple_threads field in TCB. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + +2002-12-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: Use i486 + version. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: Likewise. + + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Correct + access to __libc_locking_needed for PIC. + +2002-12-12 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_locking_needed): Only + declare for libc.so. + (__libc_lock_init, __libc_lock_init_recursive): Change into comma + expression. + (__libc_lock_lock): Put into statement expression. + (__libc_lock_unlock): Remove trailing semicolon. + * sysdeps/unix/sysv/linux/fork.h (__libc_pthread_init): Fix typo. + +2002-12-12 Roland McGrath <roland@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use asm operand with + "m" constraint to refer to __libc_locking_needed. Declare it here. + +2002-12-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/fork-gen.c: Renamed to... + * sysdeps/unix/sysv/linux/libc_pthread_init.c: ...this. + Initialize __libc_locking_needed. + * init.c (__pthread_initialize_minimal): Call __libc_pthread_init + instead of __register_pthread_fork_handler. + * sysdeps/pthread/bits/libc-lock.h: Declare __libc_locking_needed. + * sysdeps/unix/sysv/linux/Makefile (sysdep_routimes): Replace + fork-gen with libc_pthread_init. + * sysdeps/unix/sysv/linux/Versions: Use __libc_pthread_init instead + of __register_pthread_fork_handler. + * sysdeps/unix/sysv/linux/fork.h: Declare __libc_pthread_init instead + of __register_pthread_fork_handler. + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Use + __libc_locking_needed to determine whether lock prefix can be avoided. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Likewise. + +2002-12-11 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-cleanup1. + * tst-cleanup1.c: New file. + * cancellation.c (__cleanup_thread): Removed. + (__do_cancel): Remove call to __cleanup_thread. + * pthreadP.h: Remove __cleanup_thread prorotype. + + * sysdeps/pthread/bits/libc-lock.h (__libc_cleanup_region_start): + Remember function and argument even if cancellation handler + function is not available. + (__libc_cleanup_region_end): Execute registered function directly if + pthread functions are not available. + (__libc_cleanup_end): Likewise. + + * init.c (__pthread_initialize_minimal): Fix initialization in + static lib by preventing gcc from being too clever. + +2002-12-10 Ulrich Drepper <drepper@redhat.com> + + * init.c (__pthread_initialize_minimal): Remove unneccesary + sigaddset call. + + * Makefile (tests): We can run tst-locale2 now. + +2002-12-09 Ulrich Drepper <drepper@redhat.com> + + * Versions: Remove duplicated sigwait entry. + +2002-12-08 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Enable pthread_cleanup_{push,pop} optimizations only + inside libpthread. + + * pt-fcntl.c (__fcntl): Initialize oldtype to avoid warning. + + * pthreadP.h: Declare __pthread_enable_asynccancel and + __pthread_disable_asynccancel. + (CANCEL_ASYNC): Use __pthread_enable_asynccancel. + (CANCEL_RESET): Use __pthread_disable_asynccancel. + * cancellation.c (__pthread_enable_asynccancel): New function. + (__pthread_disable_asynccancel): New function. + * pt-accept.c: Adjust for CANCEL_ASYNC and CANCEL_RESET change. + * pt-close.c: Likewise. + * pt-connect.c: Likewise. + * pt-creat.c: Likewise. + * pt-fcntl.c: Likewise. + * pt-fsync.c: Likewise. + * pt-lseek.c: Likewise. + * pt-lseek64.c: Likewise. + * pt-msgrcv.c: Likewise. + * pt-msgsnd.c: Likewise. + * pt-msync.c: Likewise. + * pt-nanosleep.c: Likewise. + * pt-open.c: Likewise. + * pt-open64.c: Likewise. + * pt-pause.c: Likewise. + * pt-poll.c: Likewise. + * pt-pread.c: Likewise. + * pt-pread64.c: Likewise. + * pt-pselect.c: Likewise. + * pt-pwrite.c: Likewise. + * pt-pwrite64.c: Likewise. + * pt-read.c: Likewise. + * pt-readv.c: Likewise. + * pt-recv.c: Likewise. + * pt-recvfrom.c: Likewise. + * pt-recvmsg.c: Likewise. + * pt-select.c: Likewise. + * pt-send.c: Likewise. + * pt-sendmsg.c: Likewise. + * pt-sendto.c: Likewise. + * pt-sigpause.c: Likewise. + * pt-sigsuspend.c: Likewise. + * pt-sigtimedwait.c: Likewise. + * pt-sigwait.c: Likewise. + * pt-sigwaitinfo.c: Likewise. + * pt-system.c: Likewise. + * pt-tcdrain.c: Likewise. + * pt-wait.c: Likewise. + * pt-waitid.c: Likewise. + * pt-waitpid.c: Likewise. + * pt-write.c: Likewise. + * pt-writev.c: Likewise. + * pthread_join.c: Likewise. + * pthread_timedjoin.c: Likewise. + + * pt-sigpause.c (sigsuspend): Call __sigsuspend. + (__xpg_sigpause): New function. + * Versions (libpthread:GLIBC_2.3.2): Add __xpg_sigpause. + +2002-12-07 Ulrich Drepper <drepper@redhat.com> + + * Makefile (CFLAGS-ftrylockfile.c): Add -D_IO_MTSAFE_IO. + + * cleanup.c: Move declarations of _GI_pthread_cleanup_push and + _GI_pthread_cleanup_pop to pthreadP.h. + + * ftrylockfile.c: Use _IO_lock_trylock instead of + pthread_mutex_trylock. + + * pthreadP.h (CANCEL_ASYNC): Use __pthread_setcanceltype. + (CANCEL_RESET): Likewise. + (__pthread_setcanceltype_): Declare. + (__pthread_mutex_lock_internal): Declare. + (__pthread_mutex_unlock_internal): Declare. + (__pthread_once_internal): Declare. + (pthread_cleanup_push): Redefine using _GI_pthread_cleanup_push. + (pthread_cleanup_pop): Redefine using _GI_pthread_cleanup_pop. + + * pthread_cond_timedwait.c: Use INTUSE is calls to pthread_mutex_lock + and pthread_mutex_unlock. + * pthread_cond_wait.c: Likewise. + * pthread_mutex_lock.c: Use INTDEF to define alias if needed. + * pthread_mutex_unlock.c: Likewise. + + * pthread_setcanceltype.c: Add additional alias + __pthread_setcanceltype. + + * sem_unlink.c (sem_unlink): Use __pthread_once with INTDEF. + * sem_open.c (sem_open): Likewise. + Use __libc_open, __libc_write, and __libc_close instead of + open, write, and close respectively. + + * sysdeps/pthread/bits/libc-lock.h (__libc_lock_trylock_internal): + Rewrite as statement expression since it must return a value. + + * pthread_cancel.c: Use __pthread_kill instead of pthread_kill. + * sysdeps/unix/sysv/linux/pthread_kill.c: Define additional alias + __pthread_kill. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Define additional + alias __pthread_once_internal. + + * sysdeps/unix/sysv/linux/raise.c: Use libc_hidden_def for raise. + +2002-12-06 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-stdio1 and tst-stdio2. + * tst-stdio1.c: New file. + * tst-stdio2.c: New file. + + * init.c (__pthread_initialize_minimal): Correct INIT_LIST_HEAD use. + + * Makefile (tests): Comment out tst-locale2 for now. + (CFLAGS-flockfile.c, CFLAGS-funlockfile.c): Define to -D_IO_MTSAFE_IO. + + * sysdeps/unix/sysv/linux/Makefile: Define CFLAGS-fork.c to + -D_IO_MTSAFE_IO. + * sysdeps/unix/sysv/linux/fork.c: Include <bits/stdio-lock.h>. + Use _IO_lock_init instead of explicit assignment. + + * sysdeps/pthread/bits/libc-lock.h: Define __rtld_lock_* macros. + Define __libc_lock_* and __libc_lock_recursive macros with + lowlevellock macros, not pthread mutexes. + + * flockfile.c: Include <bits/stdio-lock.h>. Use _IO_lock_lock instead + of pthread_mutex_lock. + * funlockfile.c: Include <bits/stdio-lock.h>. Use _IO_lock_unlock + instead of pthread_mutex_unlock. + +2002-12-06 Roland McGrath <roland@redhat.com> + + * allocatestack.c (__stack_user): Use uninitialized defn. + * init.c (__pthread_initialize_minimal): Initialize it here. + +2002-12-05 Roland McGrath <roland@redhat.com> + + * sysdeps/i386/tls.h (TLS_INIT_TP): Make it return zero or an error + string. + * sysdeps/x86_64/tls.h (TLS_INIT_TP): Likewise. + + * sysdeps/unix/sysv/linux/i386/createthread.c (create_thread): Add + missing & here too. + +2002-12-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove + lowlevellock. + * sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S: New file. + * sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S: New file. + * sysdeps/pthread/bits/libc-lock.h: Use lowlevellock implementation + for __libc_lock_* macros. + * Makefile (routines): Add libc-lowlevellock. + +2002-10-09 Roland McGrath <roland@redhat.com> + + * sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call): New macro. + Under [__PIC__], call the function via the pointer fetched for + comparison rather than a call by name that uses the PLT. + (__libc_lock_init, __libc_rwlock_init, __libc_lock_fini) + (__libc_rwlock_fini, __libc_lock_lock, __libc_rwlock_rdlock) + (__libc_rwlock_wrlock, __libc_lock_trylock, __libc_rwlock_tryrdlock) + (__libc_rwlock_trywrlock, __libc_lock_unlock, __libc_rwlock_unlock) + (__libc_key_create, __libc_getspecific, __libc_setspecific): Use it. + +2002-12-04 Roland McGrath <roland@redhat.com> + + * forward.c (pthread_self): Use FORWARD3 macro to correct return type. + + * sysdeps/i386/td_ta_map_lwp2thr.c: Moved from ../nptl_db. + * sysdeps/generic/td_ta_map_lwp2thr.c: New file. + + * pthread_create.c (start_thread): Add missing & on __nptl_last_event. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Make pthread_t + a completely opaque, non-integer type. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + +2002-12-05 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/i386/tls.h: Include stdlib.h. + * sysdeps/x86_64/tls.h: Likewise. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-locale2. + (tests-static): Likewise. + * tst-locale2.c: New file. + + * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Mark asms as + volatile and add memory clobbers to lock operations. + +2002-12-03 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/i686/bits/atomic.h: Use i486 version. + * sysdeps/i386/i486/bits/atomic.h: New file. + * sysdeps/i386/i586/bits/atomic.h: New file. + * sysdeps/i386/i686/pthread_spin_trylock.S: Define HAVE_CMOV and + include i486 version. + * sysdeps/i386/i486/pthread_spin_trylock.S: New file. + * sysdeps/i386/i586/pthread_spin_trylock.S: New file. + Patch by Marijn Ros <marijn@mad.scientist.com>. + + * allocatestack.c (get_cached_stack): Don't crash if we first + found a stack with a larger size then needed. + Reported by Hui Huang <hui.huang@sun.com>. + + * Makefile (tests): Add tst-sysconf. + * tst-sysconf.c: New file. + + * sysdeps/unix/sysv/linux/bits/local_lim.h: Undefine + PTHREAD_THREADS_MAX. + +2002-12-02 Roland McGrath <roland@redhat.com> + + * pthreadP.h (__stack_user, __nptl_create_event, __nptl_death_event): + Declare using hidden_proto instead of attribute_hidden, so there are + non-.hidden static symbols for gdb to find. + (__pthread_keys): Likewise. + * events.c (__nptl_create_event, __nptl_death_event): Add hidden_def. + * allocatestack.c (__stack_user): Likewise. + * pthread_create.c (__pthread_keys): Likewise. + (__nptl_threads_events, __nptl_last_event): Make these static instead + of hidden. + * pthread_key_create.c (__pthread_pthread_keys_max, + __pthread_pthread_key_2ndlevel_size): Renamed from __linuxthreads_*. + +2002-12-02 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-locale1. If buid-static is yes link + statically. + * tst-locale1.c: New file. + + * pthread_cond_timedwait.c: Include <stdlib.h>. + + * Makefile (tests): Add tst-fork2 and tst-fork3. + * tst-fork2.c: New file. + * tst-fork3.c: New file. + +2002-11-28 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h: New file. + + * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define macros which + require it to 200112L. + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Use cmov + instruction only if HAVE_CMOV is defined. + * sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S: Define HAVE_CMOV. + + * sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: New file. + + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: New file. + + * sysdeps/unix/sysv/linux/x86_64/pt-vfork.S: New file. + +2002-11-27 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/x86_64/bits/atomic.h: New file. + + * sysdeps/i386/i686/bits/atomic.h: Fix asm syntax for 8- and + 16-bit operations. + + * sysdeps/unix/sysv/linux/raise.c (raise): Use INTERNAL_SYSCALL if + possible since gettid cannot fail. + + * sysdeps/x86_64/pthreaddef.h: New file. + + * sysdeps/i386/pthreaddef.h (gettid): Removed. + + * sysdeps/x86_64/pthread_spin_init.c: New file. + * sysdeps/x86_64/pthread_spin_lock.c: New file. + * sysdeps/x86_64/pthread_spin_trylock.c: New file. + * sysdeps/x86_64/pthread_spin_unlock.c: New file. + + * sysdeps/i386/i686/pthread_spin_trylock.S (pthread_spin_trylock): + Add missing lock prefix. Minute optimization. + + * tst-spin2.c (main): Also check successful trylock call. + + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Use correct + syscall. Fix typo in case INTERNAL_SYSCALL is not used. + + * sysdeps/i386/pthread_spin_destroy.c: Moved to... + * sysdeps/pthread/pthread_spin_destroy.c: ...here. New file. + + * sysdeps/i386/pthread_sigmask.c: Removed. Use the generic code. + * sysdeps/pthread/pthread_sigmask.c (pthread_sigmask): Return correct + value in case of an error. Add support for INTERNAL_SYSCALL. + + * sysdeps/i386/pthread_sigmask.c (pthread_sigmask): Return correct + value in case of an error. + + * sysdeps/x86_64/tls.h: New file. + +2002-11-26 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/i386/tls.h (THREAD_GETMEM_NC): Change interface. It now + takes the array member name and the index as parameters. + (THREAD_SETMEM_NC): Likewise. + * pthread_getspecific.c: Use new THREAD_GETMEM_NC interface. + * pthread_setspecific.c: Use new THREAD_GETMEM_NC and THREAD_SETMEM_NC + interfaces. + + * sysdeps/i386/tls.h (THREAD_SETMEM): Use size of member element + to decide which code to use. + (THREAD_SETMEM_NC): Likewise. + + * allocatestack.c (queue_stack): Don't remove stack from list here. + Do it in the caller. Correct condition to prematurely terminate + loop to free stacks. + (__deallocate_stack): Remove stack from list here. + +2002-11-26 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-stack1. + * tst-stack1.c: New file. + + * allocatestack.c (allocate_stack): Initialize the TCB on a user + provided stack. + + * pthread_attr_getstack.c: Return bottom of the thread area. + +2002-11-25 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libpthread-routines): Add pt-allocrtsig and + pthread_kill_other_threads. + * pt-allocrtsig.c: New file. + * pthread_kill_other_threads.c: New file. + * sysdeps/unix/sysv/linux/allocrtsig.c: Add additional aliases for + all three functions. + * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Remove + allocrtsig. + * sysdeps/unix/sysv/linux/Versions (libc:GLIBC_PRIVATE): Export + __libc_current_sigrtmin_private, __libc_current_sigrtmax_private, + and __libc_allocate_rtsig_private. + * Versions (libpthread): Export pthread_kill_other_threads_np, + __libc_current_sigrtmin, and __libc_current_sigrtmax. + +2002-11-24 Ulrich Drepper <drepper@redhat.com> + + * allocatestack.c (allocate_stack): stackaddr in attribute points to + the end of the stack. Adjust computations. + When mprotect call fails dequeue stack and free it. + * pthread_attr_setstack.c: Store top of the stack in stackaddr + attribute. + * pthread_getattr_np.c: Likewise. + + * descr.h (IS_DETACHED): Add some more parenthesis to prevent + surprises. + +2002-11-23 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/pthread/pthread.h (pthread_self): __THROW must come before + attribute definitions. Patch by Luca Barbieri <ldb@ldb.ods.org>. + +2002-11-22 Ulrich Drepper <drepper@redhat.com> + + * pthread_getspecific.c: Optimize access to first 2nd-level array. + * pthread_setspecific.c: Likewise. + +2002-11-21 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/createthread.c: Remove CLONE_ flags + definitions. Get them from the official place. + * sysdeps/unix/sysv/linux/i386/fork.c: Likewise. + + * sysdeps/unix/sysv/linux/i386/createthread.c: Update CLONE_* flags. + Use new CLONE_ flags in clone() calls. + + * sysdeps/unix/sysv/linux/fork.c: Use ARCH_FORK to actually fork. + * sysdeps/unix/sysv/linux/i386/fork.c: New file. + + * Versions: Add pthread_* functions for libc. + * forward.c: New file. + + * sysdeps/pthread/Makefile (libpthread-sysdeps_routines): Add + errno-loc. + * herrno.c: New file. + * res.c: New file. + + * Makefile (libpthread-routines): Remove sem_post, sem_wait, + sem_trywait, and sem_timedwait. Add herrno and res. + * sem_init.c: Don't initialize lock and waiters members. + * sem_open.c: Likewise. + * sem_post.c: Removed. + * sem_wait.c: Removed. + * sem_trywait.c: Removed. + * sem_timedwait.c: Removed. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Complete rewrite. + Includes full implementations of sem_post, sem_wait, sem_trywait, + and sem_timedwait. + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Adjust + for new implementation. + * sysdeps/unix/sysv/linux/internaltypes.h (struct sem): Remove lock + and waiters fields. + + * tst-sem3.c: Improve error message. + * tst-signal3.c: Likewise. + + * init.c (__pthread_initialize_minimal): Use set_tid_address syscall + to tell the kernel about the termination futex and to initialize tid + member. Don't initialize main_thread. + * descr.h (struct pthread): Remove main_thread member. + * cancelllation.c (__do_cancel): Remove code handling main thread. + The main thread is not special anymore. + + * allocatestack.c (__reclaim_stacks): Mark stacks as unused. Add + size of the stacks to stack_cache_actsize. + + * pt-readv.c: Add missing "defined". + * pt-sigwait.c: Likewise. + * pt-writev.c: Likewise. + +2002-11-09 Ulrich Drepper <drepper@redhat.com> + + * Versions: Export __connect from libpthread. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * Makefile (libpthread-routines): Add pt-raise. + * sysdeps/unix/sysv/linux/raise.c: New file. + * sysdeps/unix/sysv/linux/pt-raise.c: New file. + * sysdeps/generic/pt-raise.c: New file. + + * pthread_cond_init.c: Initialize all data elements of the condvar + structure. Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * pthread_attr_init.c: Actually implement 2.0 compatibility version. + * pthread_create.c: Likewise. + + * Makefile (tests): Add tst-key1, tst-key2, tst-key3. + * tst-key1.c: New file. + * tst-key2.c: New file. + * tst-key3.c: New file. + + * Versions: Export pthread_detach for version GLIBC_2.0. + Reported by Saurabh Desai <sdesai@austin.ibm.com>. + +2002-11-08 Ulrich Drepper <drepper@redhat.com> + + * pthread_key_create.c: Terminate search after an unused key was found. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + + * sysdeps/unix/sysv/linux/i386/pthread_once.S: Return zero. + Patch by Luca Barbieri <ldb@ldb.ods.org>. + +2002-10-10 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Use slow generic + dynamic lookup for errno in PIC. + + * allocatestack.c (get_cached_stack): Rearrange code slightly to + release the stack lock as soon as possible. + Call _dl_allocate_tls_init for TCB from the cache to re-initialize + the static TLS block. + (allocate_stack): Call _dl_allocate_tls_init for user-provided stack. + + * cancellation.c: Renamed from cancelation.c. + * Makefile: Adjust accordingly. + * pthreadP.h (CANCELLATION_P): Renamed from CANCELATION_P. + * cleanup_defer.c: Use CANCELLATION_P. + * pthread_testcancel.c: Likewise. + * descr.h: Fix spelling in comments. + * init.c: Likewise. + * pthread_getattr_np.c: Likewise. + * pthread_getschedparam.c: Likewise. + * pthread_setschedparam.c: Likewise. + * Versions: Likewise. + + * pt-pselect.c: New file. + * Makefile (libpthread-routines): Add pt-pselect. + * Versions: Add pselect. + + * tst-cancel4.c: New file. + * Makefile (tests): Add tst-cancel4. + +2002-10-09 Ulrich Drepper <drepper@redhat.com> + + * pthread_mutex_lock.c: Always record lock ownership. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Likewise. + + * pt-readv.c: New file. + * pt-writev.c: New file. + * pt-creat.c: New file. + * pt-msgrcv.c: New file. + * pt-msgsnd.c: New file. + * pt-poll.c: New file. + * pt-select.c: New file. + * pt-sigpause.c: New file. + * pt-sigsuspend.c: New file. + * pt-sigwait.c: New file. + * pt-sigwaitinfo.c: New file. + * pt-waitid.c: New file. + * Makefile (libpthread-routines): Add pt-readv, pt-writev, pt-creat, + pt-msgrcv, pt-msgsnd, pt-poll, pt-select, pt-sigpause, pt-sigsuspend, + pt-sigwait, pt-sigwaitinfo, and pt-waitid. + * Versions: Add all the new functions. + + * tst-exit1.c: New file. + * Makefile (tests): Add tst-exit1. + + * sem_timedwait.c: Minor optimization for more optimal fastpath. + +2002-10-08 Ulrich Drepper <drepper@redhat.com> + + * pt-fcntl.c: Only enable asynchronous cancellation for F_SETLKW. + + * pthread_join.c: Enable asynchronous cancellation around lll_wait_tid + call. pthread_join is an official cancellation point. + * pthread_timedjoin.c: Likewise. + + * pthread_cond_wait.c: Revert order in which internal lock are dropped + and the condvar's mutex are retrieved. + * pthread_cond_timedwait.c: Likewise. + Reported by dice@saros.East.Sun.COM. + +2002-10-07 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h: Cut out all type definitions and move them... + * sysdeps/unix/sysv/linux/internaltypes.h: ...here. New file. + * pthreadP.h: Include <internaltypes.h>. + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h (lll_sem_post): Little + performance tweaks. + + * sem_trywait.c: Shuffle #includes around to get right order. + * sem_timedwait.c: Likewise. + * sem_post.c: Likewise. + * sem_wait.c: Likewise. + + * nptl 0.3 released. + + * Makefile (tests): Add tst-signal3. + * tst-signal3.c: New file. + +2002-10-05 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/lowlevelsem.h: Tell the compiler that + the asms modify the sem object. + (__lll_sem_timedwait): Now takes struct sem* as first parameter. + + * sysdeps/unix/sysv/linux/i386/bits/semaphore.h (sem_t): Don't expose + the actual members. + * pthreadP.h (struct sem): New type. Actual semaphore type. + * semaphoreP.h: Include pthreadP.h. + * sem_getvalue.c: Adjust to sem_t change. + * sem_init.c: Likewise. + * sem_open.c: Likewise. + * sem_post.c: Likewise. + * sem_timedwait.c: Likewise. + * sem_trywait.c: Likewise. + * sem_wait.c: Likewise. + +2002-10-04 Ulrich Drepper <drepper@redhat.com> + + * Makefile (tests): Add tst-basic2, tst-exec1, tst-exec3, tst-exec3. + * tst-basic2.c: New file. + * tst-exec1.c: New file. + * tst-exec2.c: New file. + * tst-exec3.c: New file. + + * tst-fork1.c: Remove extra */. + + * nptl 0.2 released. The API for IA-32 is complete. diff --git a/libpthread/nptl/Makefile b/libpthread/nptl/Makefile new file mode 100644 index 000000000..f9100219a --- /dev/null +++ b/libpthread/nptl/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../ +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/Makefile.in b/libpthread/nptl/Makefile.in new file mode 100644 index 000000000..571b1f388 --- /dev/null +++ b/libpthread/nptl/Makefile.in @@ -0,0 +1,332 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005-2006 Steven J. Hill <sjhill@realitydiluted.com> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +subdirs += libpthread/nptl/sysdeps/$(TARGET_ARCH) \ + libpthread/nptl/sysdeps/unix/sysv/linux \ + libpthread/nptl/sysdeps/pthread + +libpthread-routines = init vars events version \ + pthread_create pthread_exit pthread_detach \ + pthread_join pthread_tryjoin pthread_timedjoin \ + pthread_self pthread_equal pthread_yield \ + pthread_getconcurrency pthread_setconcurrency \ + pthread_getschedparam pthread_setschedparam \ + pthread_setschedprio \ + pthread_attr_init pthread_attr_destroy \ + pthread_attr_getdetachstate pthread_attr_setdetachstate \ + pthread_attr_getguardsize pthread_attr_setguardsize \ + pthread_attr_getschedparam pthread_attr_setschedparam \ + pthread_attr_getschedpolicy pthread_attr_setschedpolicy \ + pthread_attr_getinheritsched \ + pthread_attr_setinheritsched \ + pthread_attr_getscope pthread_attr_setscope \ + pthread_attr_getstackaddr pthread_attr_setstackaddr \ + pthread_attr_getstacksize pthread_attr_setstacksize \ + pthread_attr_getstack pthread_attr_setstack \ + pthread_getattr_np \ + pthread_mutex_init pthread_mutex_destroy \ + pthread_mutex_lock pthread_mutex_trylock \ + pthread_mutex_timedlock pthread_mutex_unlock \ + pthread_mutexattr_init pthread_mutexattr_destroy \ + pthread_mutexattr_getpshared \ + pthread_mutexattr_setpshared \ + pthread_mutexattr_gettype pthread_mutexattr_settype \ + pthread_rwlock_init pthread_rwlock_destroy \ + pthread_rwlock_rdlock pthread_rwlock_timedrdlock \ + pthread_rwlock_wrlock pthread_rwlock_timedwrlock \ + pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \ + pthread_rwlock_unlock \ + pthread_rwlockattr_init pthread_rwlockattr_destroy \ + pthread_rwlockattr_getpshared \ + pthread_rwlockattr_setpshared \ + pthread_rwlockattr_getkind_np \ + pthread_rwlockattr_setkind_np \ + pthread_cond_init pthread_cond_destroy \ + pthread_cond_wait pthread_cond_timedwait \ + pthread_cond_signal pthread_cond_broadcast \ + pthread_condattr_init pthread_condattr_destroy \ + pthread_condattr_getpshared pthread_condattr_setpshared \ + pthread_condattr_getclock pthread_condattr_setclock \ + pthread_spin_init pthread_spin_destroy \ + pthread_spin_lock pthread_spin_trylock \ + pthread_spin_unlock \ + pthread_barrier_init pthread_barrier_destroy \ + pthread_barrier_wait \ + pthread_barrierattr_init pthread_barrierattr_destroy \ + pthread_barrierattr_getpshared \ + pthread_barrierattr_setpshared \ + pthread_key_create pthread_key_delete \ + pthread_getspecific pthread_setspecific \ + pthread_sigmask pthread_kill \ + pthread_cancel pthread_testcancel \ + pthread_setcancelstate pthread_setcanceltype \ + pthread_once \ + pthread_atfork \ + pthread_getcpuclockid \ + pthread_clock_gettime pthread_clock_settime \ + sem_init sem_destroy \ + sem_open sem_close sem_unlink \ + sem_getvalue \ + sem_wait sem_trywait sem_timedwait sem_post \ + cleanup cleanup_defer cleanup_compat \ + cleanup_defer_compat unwind \ + pt-longjmp pt-cleanup\ + cancellation \ + lowlevellock \ + pt-vfork \ + ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \ + ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \ + ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek ptw-llseek \ + ptw-msync ptw-nanosleep ptw-open ptw-open64 ptw-pause \ + ptw-pread ptw-pread64 ptw-pwrite ptw-pwrite64 \ + ptw-tcdrain ptw-wait ptw-waitpid ptw-msgrcv ptw-msgsnd \ + ptw-sigwait \ + pt-raise pt-system \ + flockfile ftrylockfile funlockfile \ + sigaction \ + herrno res \ + pthread_kill_other_threads \ + pthread_getaffinity pthread_setaffinity \ + pthread_attr_getaffinity pthread_attr_setaffinity \ + cleanup_routine unwind-forcedunwind + +libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind + +CFLAGS-pthread_atfork.c = -DNOT_IN_libc + +# Since cancellation handling is in large parts handled using exceptions +# we have to compile some files with exception handling enabled, some +# even with asynchronous unwind tables. + +# init.c contains sigcancel_handler(). +CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables +# The unwind code itself, +CFLAGS-unwind.c = -fexceptions +CFLAGS-unwind-forcedunwind.c = -fexceptions -fasynchronous-unwind-tables + +# The following three functions must be async-cancel safe. +CFLAGS-pthread_cancel.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_setcancelstate.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_setcanceltype.c = -fexceptions -fasynchronous-unwind-tables + +# These are internal functions which similar functionality as setcancelstate +# and setcanceltype. +CFLAGS-cancellation.c = -fasynchronous-unwind-tables +CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables + +# Calling pthread_exit() must cause the registered cancel handlers to +# be executed. Therefore exceptions have to be thrown through this +# function. +CFLAGS-pthread_exit.c = -fexceptions + +# Among others, __pthread_unwind is forwarded. This function must handle +# exceptions. +CFLAGS-forward.c = -fexceptions + +# The following are cancellation points. Some of the functions can +# block and therefore temporarily enable asynchronous cancellation. +# Those must be compiled asynchronous unwind tables. +CFLAGS-pthread_testcancel.c = -fexceptions +CFLAGS-pthread_join.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_timedjoin.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_once.c = $(uses-callbacks) -fexceptions \ + -fasynchronous-unwind-tables +CFLAGS-pthread_cond_wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pthread_cond_timedwait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sem_wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sem_timedwait.c = -fexceptions -fasynchronous-unwind-tables + +# These are the function wrappers we have to duplicate here. +CFLAGS-fcntl.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-lockf.c = -fexceptions +CFLAGS-pread.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pread64.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-pwrite64.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-wait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-waitpid.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-sigwait.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-msgrcv.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-msgsnd.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-tcdrain.c = -fexceptions -fasynchronous-unwind-tables + +CFLAGS-pt-system.c = -fexceptions -I./libc/stdlib + +# +# The rest of this file is uClibc specific. +# +CFLAGS-pthread_barrier_init.c = -D_GNU_SOURCE +CFLAGS-pthread_barrier_destroy.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_init.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_destroy.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_getpshared.c = -D_GNU_SOURCE +CFLAGS-pthread_barrierattr_setpshared.c = -D_GNU_SOURCE +CFLAGS-sem_open.c = -D_GNU_SOURCE + +CFLAGS-nptl = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS) + +CFLAGS-OMIT-alloca_cutoff.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-forward.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevelock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-cancellation.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +libpthread-os-routines = pthread_yield +libpthread-misc-routines = pthread_rwlock_rdlock pthread_rwlock_timedrdlock \ + pthread_rwlock_wrlock pthread_rwlock_timedwrlock \ + pthread_rwlock_unlock pthread_cond_wait \ + pthread_cond_timedwait pthread_cond_signal \ + pthread_cond_broadcast pthread_spin_init \ + pthread_spin_destroy pthread_spin_lock \ + pthread_spin_trylock pthread_spin_unlock \ + pthread_barrier_wait pthread_sigmask \ + pthread_kill pthread_once \ + pthread_getcpuclockid sem_wait \ + sem_trywait sem_timedwait \ + sem_post pt-longjmp \ + lowlevellock pt-vfork \ + ptw-close ptw-read ptw-write \ + ptw-fcntl ptw-accept ptw-connect \ + ptw-recv ptw-recvfrom ptw-recvmsg \ + ptw-send ptw-sendmsg ptw-sendto \ + ptw-fsync ptw-lseek ptw-llseek \ + ptw-msync ptw-nanosleep ptw-open \ + ptw-open64 ptw-pause ptw-pread \ + ptw-pread64 ptw-pwrite ptw-pwrite64 \ + ptw-tcdrain ptw-wait ptw-waitpid \ + ptw-msgrcv ptw-msgsnd ptw-sigwait \ + pt-raise flockfile ftrylockfile \ + funlockfile sigaction \ + pthread_getaffinity \ + pthread_setaffinity \ + pthread_attr_getaffinity \ + pthread_attr_setaffinity \ + unwind-forcedunwind + +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) +LDFLAGS-libpthread.so := $(LDFLAGS_NOSTRIP) -Wl,-z,defs +else +LDFLAGS-libpthread.so := $(LDFLAGS) +endif + +LDFLAGS-libpthread.so += $(top_builddir)lib/ld-uClibc-$(VERSION).so $(top_builddir)lib/libdl-$(VERSION).so + +LIBS-libpthread.so := $(LIBS) + +ifneq ($(UCLIBC_CTOR_DTOR),y) +START_FILE-libpthread.so := $(top_builddir)/libpthread/nptl/sysdeps/pthread/crti.o $(SHARED_START_FILES) +END_FILE-libpthread.so := $(SHARED_END_FILES) $(top_builddir)/libpthread/nptl/sysdeps/pthread/crtn.o +endif + +libpthread_FULL_NAME := libpthread-$(VERSION).so + +PTHREAD_DIR := $(top_srcdir)libpthread/nptl +PTHREAD_OUT := $(top_builddir)libpthread/nptl + +libpthread_static_SRC := pthread_atfork + +libpthread_a_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c, \ + $(filter-out $(libpthread-os-routines) \ + $(libpthread-misc-routines) \ + $(libpthread-shared-only-routines), \ + $(libpthread-routines))) +libpthread_so_SRC = $(patsubst %, $(PTHREAD_DIR)/%.c, \ + $(filter-out $(libpthread-os-routines) \ + $(libpthread-misc-routines), $(libpthread-routines))) + +libc-static-y += $(patsubst %.c, $(PTHREAD_OUT)/%.o, alloca_cutoff.c \ + libc-cancellation.c) +libc-shared-y += $(patsubst %.c, $(PTHREAD_OUT)/%.oS, forward.c \ + libc-cancellation.c) +libpthread-nonshared-y += $(patsubst %,$(PTHREAD_OUT)/%.oS,$(libpthread_static_SRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.os,$(libpthread_a_SRC)) +else +libpthread-a-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC)) +endif + +libpthread-so-y := $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.oS,$(libpthread_so_SRC)) +libpthread-static-y += $(patsubst $(PTHREAD_DIR)/%.c,$(PTHREAD_OUT)/%.o,$(libpthread_a_SRC) $(libpthread_static_SRC)) + +objclean-y += libpthread_clean +headers_clean-y += nptl_headers_clean + +-include $(PTHREAD_DIR)/sysdeps/generic/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/pthread/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch +-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/Makefile.in +-include $(PTHREAD_DIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/Makefile.arch + +lib-a-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.a +lib-so-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.so + +$(top_builddir)lib/libpthread.so: $(PTHREAD_OUT)/libpthread_so.a $(libc) $(top_builddir)lib/libpthread_nonshared.a + $(call link.so,$(libpthread_FULL_NAME),$(MAJOR_VERSION)) + $(Q)$(RM) $@ + $(Q)cp $(top_srcdir)extra/scripts/format.lds $@ + $(Q)echo "GROUP ( $(notdir $@).$(MAJOR_VERSION) libpthread_nonshared.a )" >> $@ + +$(PTHREAD_OUT)/libpthread_so.a: $(libpthread-so-y) + $(Q)$(RM) $@ +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) + $(do_strip:-x=-X --strip-debug) +else + $(do_strip) +endif + $(do_ar) + +$(top_builddir)lib/libpthread.a: $(libpthread-a-y) + $(Q)$(INSTALL) -d $(dir $@) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +# +# Create 'pthread-errnos.h' header file. +# +CFLAGS-pthread-errnos.c = -S + +$(PTHREAD_OUT)/pthread-errnos.c: $(PTHREAD_DIR)/pthread-errnos.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_OUT)/pthread-errnos.s: $(PTHREAD_OUT)/pthread-errnos.c + $(compile.c) + +$(PTHREAD_OUT)/pthread-errnos.h: $(PTHREAD_OUT)/pthread-errnos.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + + +headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(nptl_headers_bootstrap) + +$(top_builddir)include/pthread.h: + $(do_ln) ../$(PTDIR)/sysdeps/pthread/$(@F) $(top_builddir)$@ +$(top_builddir)include/semaphore.h: + $(do_ln) ../$(PTDIR)/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/semaphore.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/pthreadtypes.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH)/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/libc-lock.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@ +$(top_builddir)include/bits/stdio-lock.h: | include/bits + $(do_ln) ../../$(PTDIR)/sysdeps/pthread/bits/$(@F) $(top_builddir)$@ + +nptl_headers_bootstrap:= $(top_builddir)include/pthread.h \ + $(top_builddir)include/semaphore.h \ + $(top_builddir)include/bits/semaphore.h \ + $(top_builddir)include/bits/pthreadtypes.h \ + $(top_builddir)include/bits/libc-lock.h \ + $(top_builddir)include/bits/stdio-lock.h + +nptl_headers: $(PTHREAD_OUT)/pthread-errnos.h + +nptl_headers_clean: + $(do_rm) $(nptl_headers_bootstrap) \ + $(addprefix $(PTHREAD_OUT)/pthread-errnos., c h s) + +libpthread_clean: + $(do_rm) $(addprefix $(PTHREAD_OUT)/*., o os oS a) diff --git a/libpthread/nptl/README.NPTL b/libpthread/nptl/README.NPTL new file mode 100644 index 000000000..7e50984cb --- /dev/null +++ b/libpthread/nptl/README.NPTL @@ -0,0 +1,307 @@ +The base NPTL code for uClibc is from the glibc project located at +<http://sourceware.org/glibc/>. The starting version was the HEAD of +the glibc CVS repository dated 2005-05-06. Important changes from +glibc will continue to be brought in as necessary until the version +for uClibc is standing on its own. All of the files were originally +brought over verbatim with no modifications. Obviously, these will +undergo any necessary changes needed for integration into uClibc. +Additionally (or subtractingly), the files and directories below +were removed and not imported. + +-- Steven J. Hill <sjhill@realitydiluted.com> on 2005-05-06 + + +nptl/Makeconfig +nptl/configure +nptl/shlib-versions +nptl/sysdeps/generic +nptl/sysdeps/ia64 +nptl/sysdeps/pthread/Makefile +nptl/sysdeps/pthread/Subdirs +nptl/sysdeps/pthread/allocalim.h +nptl/sysdeps/pthread/configure +nptl/sysdeps/pthread/configure.in +nptl/sysdeps/pthread/createthread.c +nptl/sysdeps/pthread/flockfile.c +nptl/sysdeps/pthread/ftrylockfile.c +nptl/sysdeps/pthread/funlockfile.c +nptl/sysdeps/pthread/librt-cancellation.c +nptl/sysdeps/pthread/list.h +nptl/sysdeps/pthread/malloc-machine.h +nptl/sysdeps/pthread/posix-timer.h +nptl/sysdeps/pthread/pt-initfini.c +nptl/sysdeps/pthread/pt-longjmp.c +nptl/sysdeps/pthread/pthread-functions.h +nptl/sysdeps/pthread/pthread.h +nptl/sysdeps/pthread/pthread_barrier_wait.c +nptl/sysdeps/pthread/pthread_cond_broadcast.c +nptl/sysdeps/pthread/pthread_cond_signal.c +nptl/sysdeps/pthread/pthread_cond_timedwait.c +nptl/sysdeps/pthread/pthread_cond_wait.c +nptl/sysdeps/pthread/pthread_getcpuclockid.c +nptl/sysdeps/pthread/pthread_once.c +nptl/sysdeps/pthread/pthread_rwlock_rdlock.c +nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c +nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c +nptl/sysdeps/pthread/pthread_rwlock_unlock.c +nptl/sysdeps/pthread/pthread_rwlock_wrlock.c +nptl/sysdeps/pthread/pthread_sigmask.c +nptl/sysdeps/pthread/pthread_spin_destroy.c +nptl/sysdeps/pthread/pthread_spin_init.c +nptl/sysdeps/pthread/pthread_spin_unlock.c +nptl/sysdeps/pthread/rt-unwind-resume.c +nptl/sysdeps/pthread/setxid.h +nptl/sysdeps/pthread/sigaction.c +nptl/sysdeps/pthread/sigfillset.c +nptl/sysdeps/pthread/sigprocmask.c +nptl/sysdeps/pthread/tcb-offsets.h +nptl/sysdeps/pthread/timer_create.c +nptl/sysdeps/pthread/timer_delete.c +nptl/sysdeps/pthread/timer_getoverr.c +nptl/sysdeps/pthread/timer_gettime.c +nptl/sysdeps/pthread/timer_routines.c +nptl/sysdeps/pthread/timer_settime.c +nptl/sysdeps/pthread/tst-mqueue8x.c +nptl/sysdeps/pthread/tst-timer.c +nptl/sysdeps/pthread/unwind-forcedunwind.c +nptl/sysdeps/pthread/unwind-resume.c +nptl/sysdeps/s390 +nptl/sysdeps/unix +nptl/tst-_res1.c +nptl/tst-_res1mod1.c +nptl/tst-_res1mod2.c +nptl/tst-align.c +nptl/tst-align2.c +nptl/tst-atfork1.c +nptl/tst-atfork2.c +nptl/tst-atfork2mod.c +nptl/tst-attr1.c +nptl/tst-attr2.c +nptl/tst-attr3.c +nptl/tst-backtrace1.c +nptl/tst-barrier1.c +nptl/tst-barrier2.c +nptl/tst-barrier3.c +nptl/tst-barrier4.c +nptl/tst-basic1.c +nptl/tst-basic2.c +nptl/tst-basic3.c +nptl/tst-basic4.c +nptl/tst-basic5.c +nptl/tst-basic6.c +nptl/tst-cancel-wrappers.sh +nptl/tst-cancel1.c +nptl/tst-cancel10.c +nptl/tst-cancel11.c +nptl/tst-cancel12.c +nptl/tst-cancel13.c +nptl/tst-cancel14.c +nptl/tst-cancel15.c +nptl/tst-cancel16.c +nptl/tst-cancel17.c +nptl/tst-cancel18.c +nptl/tst-cancel19.c +nptl/tst-cancel2.c +nptl/tst-cancel20.c +nptl/tst-cancel21.c +nptl/tst-cancel22.c +nptl/tst-cancel23.c +nptl/tst-cancel3.c +nptl/tst-cancel4.c +nptl/tst-cancel5.c +nptl/tst-cancel6.c +nptl/tst-cancel7.c +nptl/tst-cancel8.c +nptl/tst-cancel9.c +nptl/tst-cancelx1.c +nptl/tst-cancelx10.c +nptl/tst-cancelx11.c +nptl/tst-cancelx12.c +nptl/tst-cancelx13.c +nptl/tst-cancelx14.c +nptl/tst-cancelx15.c +nptl/tst-cancelx16.c +nptl/tst-cancelx17.c +nptl/tst-cancelx18.c +nptl/tst-cancelx2.c +nptl/tst-cancelx20.c +nptl/tst-cancelx21.c +nptl/tst-cancelx3.c +nptl/tst-cancelx4.c +nptl/tst-cancelx5.c +nptl/tst-cancelx6.c +nptl/tst-cancelx7.c +nptl/tst-cancelx8.c +nptl/tst-cancelx9.c +nptl/tst-cleanup0.c +nptl/tst-cleanup0.expect +nptl/tst-cleanup1.c +nptl/tst-cleanup2.c +nptl/tst-cleanup3.c +nptl/tst-cleanup4.c +nptl/tst-cleanup4aux.c +nptl/tst-cleanupx0.c +nptl/tst-cleanupx0.expect +nptl/tst-cleanupx1.c +nptl/tst-cleanupx2.c +nptl/tst-cleanupx3.c +nptl/tst-cleanupx4.c +nptl/tst-clock1.c +nptl/tst-clock2.c +nptl/tst-cond1.c +nptl/tst-cond10.c +nptl/tst-cond11.c +nptl/tst-cond12.c +nptl/tst-cond13.c +nptl/tst-cond14.c +nptl/tst-cond15.c +nptl/tst-cond16.c +nptl/tst-cond17.c +nptl/tst-cond18.c +nptl/tst-cond19.c +nptl/tst-cond2.c +nptl/tst-cond20.c +nptl/tst-cond21.c +nptl/tst-cond3.c +nptl/tst-cond4.c +nptl/tst-cond5.c +nptl/tst-cond6.c +nptl/tst-cond7.c +nptl/tst-cond8.c +nptl/tst-cond9.c +nptl/tst-context1.c +nptl/tst-detach1.c +nptl/tst-dlsym1.c +nptl/tst-eintr1.c +nptl/tst-eintr2.c +nptl/tst-eintr3.c +nptl/tst-eintr4.c +nptl/tst-eintr5.c +nptl/tst-exec1.c +nptl/tst-exec2.c +nptl/tst-exec3.c +nptl/tst-exec4.c +nptl/tst-execstack-mod.c +nptl/tst-execstack.c +nptl/tst-exit1.c +nptl/tst-exit2.c +nptl/tst-exit3.c +nptl/tst-fini1.c +nptl/tst-fini1mod.c +nptl/tst-flock1.c +nptl/tst-flock2.c +nptl/tst-fork1.c +nptl/tst-fork2.c +nptl/tst-fork3.c +nptl/tst-fork4.c +nptl/tst-getpid1.c +nptl/tst-getpid2.c +nptl/tst-join1.c +nptl/tst-join2.c +nptl/tst-join3.c +nptl/tst-join4.c +nptl/tst-join5.c +nptl/tst-key1.c +nptl/tst-key2.c +nptl/tst-key3.c +nptl/tst-key4.c +nptl/tst-kill1.c +nptl/tst-kill2.c +nptl/tst-kill3.c +nptl/tst-kill4.c +nptl/tst-kill5.c +nptl/tst-kill6.c +nptl/tst-locale1.c +nptl/tst-locale2.c +nptl/tst-mutex1.c +nptl/tst-mutex2.c +nptl/tst-mutex3.c +nptl/tst-mutex4.c +nptl/tst-mutex5.c +nptl/tst-mutex5a.c +nptl/tst-mutex6.c +nptl/tst-mutex7.c +nptl/tst-mutex7a.c +nptl/tst-mutex8.c +nptl/tst-mutex9.c +nptl/tst-oddstacklimit.c +nptl/tst-once1.c +nptl/tst-once2.c +nptl/tst-once3.c +nptl/tst-once4.c +nptl/tst-oncex3.c +nptl/tst-oncex4.c +nptl/tst-popen1.c +nptl/tst-raise1.c +nptl/tst-rwlock1.c +nptl/tst-rwlock10.c +nptl/tst-rwlock11.c +nptl/tst-rwlock12.c +nptl/tst-rwlock13.c +nptl/tst-rwlock14.c +nptl/tst-rwlock2.c +nptl/tst-rwlock3.c +nptl/tst-rwlock4.c +nptl/tst-rwlock5.c +nptl/tst-rwlock6.c +nptl/tst-rwlock7.c +nptl/tst-rwlock8.c +nptl/tst-rwlock9.c +nptl/tst-sched1.c +nptl/tst-sem1.c +nptl/tst-sem2.c +nptl/tst-sem3.c +nptl/tst-sem4.c +nptl/tst-sem5.c +nptl/tst-sem6.c +nptl/tst-sem7.c +nptl/tst-sem8.c +nptl/tst-sem9.c +nptl/tst-setuid1-static.c +nptl/tst-setuid1.c +nptl/tst-signal1.c +nptl/tst-signal2.c +nptl/tst-signal3.c +nptl/tst-signal4.c +nptl/tst-signal5.c +nptl/tst-signal6.c +nptl/tst-spin1.c +nptl/tst-spin2.c +nptl/tst-spin3.c +nptl/tst-stack1.c +nptl/tst-stack2.c +nptl/tst-stack3.c +nptl/tst-stdio1.c +nptl/tst-stdio2.c +nptl/tst-sysconf.c +nptl/tst-tls1.c +nptl/tst-tls2.c +nptl/tst-tls3.c +nptl/tst-tls3mod.c +nptl/tst-tls4.c +nptl/tst-tls4moda.c +nptl/tst-tls4modb.c +nptl/tst-tls5.c +nptl/tst-tls5.h +nptl/tst-tls5mod.c +nptl/tst-tls5moda.c +nptl/tst-tls5modb.c +nptl/tst-tls5modc.c +nptl/tst-tls5modd.c +nptl/tst-tls5mode.c +nptl/tst-tls5modf.c +nptl/tst-tls6.sh +nptl/tst-tsd1.c +nptl/tst-tsd2.c +nptl/tst-tsd3.c +nptl/tst-tsd4.c +nptl/tst-tsd5.c +nptl/tst-umask1.c +nptl/tst-unload.c +nptl/tst-vfork1.c +nptl/tst-vfork1x.c +nptl/tst-vfork2.c +nptl/tst-vfork2x.c +nptl/version.c +nptl_db/ChangeLog +nptl_db/shlib-versions diff --git a/libpthread/nptl/alloca_cutoff.c b/libpthread/nptl/alloca_cutoff.c new file mode 100644 index 000000000..ba26ceba3 --- /dev/null +++ b/libpthread/nptl/alloca_cutoff.c @@ -0,0 +1,36 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <alloca.h> +#include <stdlib.h> +#include <sys/param.h> +#include <pthreadP.h> + + +int +__libc_alloca_cutoff (size_t size) +{ + return size <= (MIN (__MAX_ALLOCA_CUTOFF, + THREAD_GETMEM (THREAD_SELF, stackblock_size) / 4 + /* The main thread, before the thread library is + initialized, has zero in the stackblock_size + element. Since it is the main thread we can + assume the maximum available stack space. */ + ?: __MAX_ALLOCA_CUTOFF * 4)); +} diff --git a/libpthread/nptl/allocatestack.c b/libpthread/nptl/allocatestack.c new file mode 100644 index 000000000..dab9f08ed --- /dev/null +++ b/libpthread/nptl/allocatestack.c @@ -0,0 +1,925 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <tls.h> +#include <lowlevellock.h> +#include <link.h> + +#define __getpagesize getpagesize + +#ifndef NEED_SEPARATE_REGISTER_STACK + +/* Most architectures have exactly one stack pointer. Some have more. */ +# define STACK_VARIABLES void *stackaddr = 0 + +/* How to pass the values to the 'create_thread' function. */ +# define STACK_VARIABLES_ARGS stackaddr + +/* How to declare function which gets there parameters. */ +# define STACK_VARIABLES_PARMS void *stackaddr + +/* How to declare allocate_stack. */ +# define ALLOCATE_STACK_PARMS void **stack + +/* This is how the function is called. We do it this way to allow + other variants of the function to have more parameters. */ +# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr) + +#else + +/* We need two stacks. The kernel will place them but we have to tell + the kernel about the size of the reserved address space. */ +# define STACK_VARIABLES void *stackaddr = 0; size_t stacksize + +/* How to pass the values to the 'create_thread' function. */ +# define STACK_VARIABLES_ARGS stackaddr, stacksize + +/* How to declare function which gets there parameters. */ +# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize + +/* How to declare allocate_stack. */ +# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize + +/* This is how the function is called. We do it this way to allow + other variants of the function to have more parameters. */ +# define ALLOCATE_STACK(attr, pd) \ + allocate_stack (attr, pd, &stackaddr, &stacksize) + +#endif + + +/* Default alignment of stack. */ +#ifndef STACK_ALIGN +# define STACK_ALIGN __alignof__ (long double) +#endif + +/* Default value for minimal stack size after allocating thread + descriptor and guard. */ +#ifndef MINIMAL_REST_STACK +# define MINIMAL_REST_STACK 4096 +#endif + + +/* Let the architecture add some flags to the mmap() call used to + allocate stacks. */ +#ifndef ARCH_MAP_FLAGS +# define ARCH_MAP_FLAGS 0 +#endif + +/* This yields the pointer that TLS support code calls the thread pointer. */ +#if defined(TLS_TCB_AT_TP) +# define TLS_TPADJ(pd) (pd) +#elif defined(TLS_DTV_AT_TP) +# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE)) +#endif + +/* Cache handling for not-yet free stacks. */ + +/* Maximum size in kB of cache. */ +static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */ +static size_t stack_cache_actsize; + +/* Mutex protecting this variable. */ +static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER; + +/* List of queued stack frames. */ +static LIST_HEAD (stack_cache); + +/* List of the stacks in use. */ +static LIST_HEAD (stack_used); + +/* List of the threads with user provided stacks in use. No need to + initialize this, since it's done in __pthread_initialize_minimal. */ +list_t __stack_user __attribute__ ((nocommon)); +hidden_def (__stack_user) + +#if COLORING_INCREMENT != 0 +/* Number of threads created. */ +static unsigned int nptl_ncreated; +#endif + + +/* Check whether the stack is still used or not. */ +#define FREE_P(descr) ((descr)->tid <= 0) + + +/* We create a double linked list of all cache entries. Double linked + because this allows removing entries from the end. */ + + +/* Get a stack frame from the cache. We have to match by size since + some blocks might be too small or far too large. */ +static struct pthread * +get_cached_stack (size_t *sizep, void **memp) +{ + size_t size = *sizep; + struct pthread *result = NULL; + list_t *entry; + + lll_lock (stack_cache_lock); + + /* Search the cache for a matching entry. We search for the + smallest stack which has at least the required size. Note that + in normal situations the size of all allocated stacks is the + same. As the very least there are only a few different sizes. + Therefore this loop will exit early most of the time with an + exact match. */ + list_for_each (entry, &stack_cache) + { + struct pthread *curr; + + curr = list_entry (entry, struct pthread, list); + if (FREE_P (curr) && curr->stackblock_size >= size) + { + if (curr->stackblock_size == size) + { + result = curr; + break; + } + + if (result == NULL + || result->stackblock_size > curr->stackblock_size) + result = curr; + } + } + + if (__builtin_expect (result == NULL, 0) + /* Make sure the size difference is not too excessive. In that + case we do not use the block. */ + || __builtin_expect (result->stackblock_size > 4 * size, 0)) + { + /* Release the lock. */ + lll_unlock (stack_cache_lock); + + return NULL; + } + + /* Dequeue the entry. */ + list_del (&result->list); + + /* And add to the list of stacks in use. */ + list_add (&result->list, &stack_used); + + /* And decrease the cache size. */ + stack_cache_actsize -= result->stackblock_size; + + /* Release the lock early. */ + lll_unlock (stack_cache_lock); + + /* Report size and location of the stack to the caller. */ + *sizep = result->stackblock_size; + *memp = result->stackblock; + + /* Cancellation handling is back to the default. */ + result->cancelhandling = 0; + result->cleanup = NULL; + + /* No pending event. */ + result->nextevent = NULL; + + /* Clear the DTV. */ + dtv_t *dtv = GET_DTV (TLS_TPADJ (result)); + memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t)); + + /* Re-initialize the TLS. */ + _dl_allocate_tls_init (TLS_TPADJ (result)); + + return result; +} + + +/* Add a stack frame which is not used anymore to the stack. Must be + called with the cache lock held. */ +static inline void +__attribute ((always_inline)) +queue_stack (struct pthread *stack) +{ + /* We unconditionally add the stack to the list. The memory may + still be in use but it will not be reused until the kernel marks + the stack as not used anymore. */ + list_add (&stack->list, &stack_cache); + + stack_cache_actsize += stack->stackblock_size; + if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0)) + { + /* We reduce the size of the cache. Remove the last entries + until the size is below the limit. */ + list_t *entry; + list_t *prev; + + /* Search from the end of the list. */ + list_for_each_prev_safe (entry, prev, &stack_cache) + { + struct pthread *curr; + + curr = list_entry (entry, struct pthread, list); + if (FREE_P (curr)) + { + /* Unlink the block. */ + list_del (entry); + + /* Account for the freed memory. */ + stack_cache_actsize -= curr->stackblock_size; + + /* Free the memory associated with the ELF TLS. */ + _dl_deallocate_tls (TLS_TPADJ (curr), false); + + /* Remove this block. This should never fail. If it + does something is really wrong. */ + if (munmap (curr->stackblock, curr->stackblock_size) != 0) + abort (); + + /* Maybe we have freed enough. */ + if (stack_cache_actsize <= stack_cache_maxsize) + break; + } + } + } +} + + +static int +internal_function +change_stack_perm (struct pthread *pd +#ifdef NEED_SEPARATE_REGISTER_STACK + , size_t pagemask +#endif + ) +{ +#ifdef NEED_SEPARATE_REGISTER_STACK + void *stack = (pd->stackblock + + (((((pd->stackblock_size - pd->guardsize) / 2) + & pagemask) + pd->guardsize) & pagemask)); + size_t len = pd->stackblock + pd->stackblock_size - stack; +#else + void *stack = pd->stackblock + pd->guardsize; + size_t len = pd->stackblock_size - pd->guardsize; +#endif + if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + return errno; + + return 0; +} + + +static int +allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + ALLOCATE_STACK_PARMS) +{ + struct pthread *pd; + size_t size; + size_t pagesize_m1 = __getpagesize () - 1; + void *stacktop; + + assert (attr != NULL); + assert (powerof2 (pagesize_m1 + 1)); + assert (TCB_ALIGNMENT >= STACK_ALIGN); + + /* Get the stack size from the attribute if it is set. Otherwise we + use the default we determined at start time. */ + size = attr->stacksize ?: __default_stacksize; + + /* Get memory for the stack. */ + if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0)) + { + uintptr_t adj; + + /* If the user also specified the size of the stack make sure it + is large enough. */ + if (attr->stacksize != 0 + && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK)) + return EINVAL; + + /* Adjust stack size for alignment of the TLS block. */ +#if defined(TLS_TCB_AT_TP) + adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE) + & __static_tls_align_m1; + assert (size > adj + TLS_TCB_SIZE); +#elif defined(TLS_DTV_AT_TP) + adj = ((uintptr_t) attr->stackaddr - __static_tls_size) + & __static_tls_align_m1; + assert (size > adj); +#endif + + /* The user provided some memory. Let's hope it matches the + size... We do not allocate guard pages if the user provided + the stack. It is the user's responsibility to do this if it + is wanted. */ +#if defined(TLS_TCB_AT_TP) + pd = (struct pthread *) ((uintptr_t) attr->stackaddr + - TLS_TCB_SIZE - adj); +#elif defined(TLS_DTV_AT_TP) + pd = (struct pthread *) (((uintptr_t) attr->stackaddr + - __static_tls_size - adj) + - TLS_PRE_TCB_SIZE); +#endif + + /* The user provided stack memory needs to be cleared. */ + memset (pd, '\0', sizeof (struct pthread)); + + /* The first TSD block is included in the TCB. */ + pd->specific[0] = pd->specific_1stblock; + + /* Remember the stack-related values. */ + pd->stackblock = (char *) attr->stackaddr - size; + pd->stackblock_size = size; + + /* This is a user-provided stack. It will not be queued in the + stack cache nor will the memory (except the TLS memory) be freed. */ + pd->user_stack = true; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#ifdef NEED_DL_SYSINFO + /* Copy the sysinfo value from the parent. */ + THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO; +#endif + + /* The process ID is also the same as that of the caller. */ + pd->pid = THREAD_GETMEM (THREAD_SELF, pid); + + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { + /* Something went wrong. */ + assert (errno == ENOMEM); + return EAGAIN; + } + + + /* Prepare to modify global data. */ + lll_lock (stack_cache_lock); + + /* And add to the list of stacks in use. */ + list_add (&pd->list, &__stack_user); + + lll_unlock (stack_cache_lock); + } + else + { + /* Allocate some anonymous memory. If possible use the cache. */ + size_t guardsize; + size_t reqsize; + void *mem = 0; + const int prot = (PROT_READ | PROT_WRITE); + +#if COLORING_INCREMENT != 0 + /* Add one more page for stack coloring. Don't do it for stacks + with 16 times pagesize or larger. This might just cause + unnecessary misalignment. */ + if (size <= 16 * pagesize_m1) + size += pagesize_m1 + 1; +#endif + + /* Adjust the stack size for alignment. */ + size &= ~__static_tls_align_m1; + assert (size != 0); + + /* Make sure the size of the stack is enough for the guard and + eventually the thread descriptor. */ + guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1; + if (__builtin_expect (size < (guardsize + __static_tls_size + + MINIMAL_REST_STACK + pagesize_m1 + 1), + 0)) + /* The stack is too small (or the guard too large). */ + return EINVAL; + + /* Try to get a stack from the cache. */ + reqsize = size; + pd = get_cached_stack (&size, &mem); + if (pd == NULL) + { + /* To avoid aliasing effects on a larger scale than pages we + adjust the allocated stack size if necessary. This way + allocations directly following each other will not have + aliasing problems. */ +#if MULTI_PAGE_ALIASING != 0 + if ((size % MULTI_PAGE_ALIASING) == 0) + size += pagesize_m1 + 1; +#endif + + mem = mmap (NULL, size, prot, + MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0); + + if (__builtin_expect (mem == MAP_FAILED, 0)) + { +#ifdef ARCH_RETRY_MMAP + mem = ARCH_RETRY_MMAP (size); + if (__builtin_expect (mem == MAP_FAILED, 0)) +#endif + return errno; + } + + /* SIZE is guaranteed to be greater than zero. + So we can never get a null pointer back from mmap. */ + assert (mem != NULL); + +#if COLORING_INCREMENT != 0 + /* Atomically increment NCREATED. */ + unsigned int ncreated = atomic_increment_val (&nptl_ncreated); + + /* We chose the offset for coloring by incrementing it for + every new thread by a fixed amount. The offset used + module the page size. Even if coloring would be better + relative to higher alignment values it makes no sense to + do it since the mmap() interface does not allow us to + specify any alignment for the returned memory block. */ + size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1; + + /* Make sure the coloring offsets does not disturb the alignment + of the TCB and static TLS block. */ + if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0)) + coloring = (((coloring + __static_tls_align_m1) + & ~(__static_tls_align_m1)) + & ~pagesize_m1); +#else + /* Unless specified we do not make any adjustments. */ +# define coloring 0 +#endif + + /* Place the thread descriptor at the end of the stack. */ +#if defined(TLS_TCB_AT_TP) + pd = (struct pthread *) ((char *) mem + size - coloring) - 1; +#elif defined(TLS_DTV_AT_TP) + pd = (struct pthread *) ((((uintptr_t) mem + size - coloring + - __static_tls_size) + & ~__static_tls_align_m1) + - TLS_PRE_TCB_SIZE); +#endif + + /* Remember the stack-related values. */ + pd->stackblock = mem; + pd->stackblock_size = size; + + /* We allocated the first block thread-specific data array. + This address will not change for the lifetime of this + descriptor. */ + pd->specific[0] = pd->specific_1stblock; + + /* This is at least the second thread. */ + pd->header.multiple_threads = 1; +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1; +#endif + +#ifdef NEED_DL_SYSINFO + /* Copy the sysinfo value from the parent. */ + THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO; +#endif + + /* The process ID is also the same as that of the caller. */ + pd->pid = THREAD_GETMEM (THREAD_SELF, pid); + + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { + /* Something went wrong. */ + assert (errno == ENOMEM); + + /* Free the stack memory we just allocated. */ + (void) munmap (mem, size); + + return EAGAIN; + } + + + /* Prepare to modify global data. */ + lll_lock (stack_cache_lock); + + /* And add to the list of stacks in use. */ + list_add (&pd->list, &stack_used); + + lll_unlock (stack_cache_lock); + + + /* Note that all of the stack and the thread descriptor is + zeroed. This means we do not have to initialize fields + with initial value zero. This is specifically true for + the 'tid' field which is always set back to zero once the + stack is not used anymore and for the 'guardsize' field + which will be read next. */ + } + + /* Create or resize the guard area if necessary. */ + if (__builtin_expect (guardsize > pd->guardsize, 0)) + { +#ifdef NEED_SEPARATE_REGISTER_STACK + char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1); +#else + char *guard = mem; +#endif + if (mprotect (guard, guardsize, PROT_NONE) != 0) + { + int err; + mprot_error: + err = errno; + + lll_lock (stack_cache_lock); + + /* Remove the thread from the list. */ + list_del (&pd->list); + + lll_unlock (stack_cache_lock); + + /* Get rid of the TLS block we allocated. */ + _dl_deallocate_tls (TLS_TPADJ (pd), false); + + /* Free the stack memory regardless of whether the size + of the cache is over the limit or not. If this piece + of memory caused problems we better do not use it + anymore. Uh, and we ignore possible errors. There + is nothing we could do. */ + (void) munmap (mem, size); + + return err; + } + + pd->guardsize = guardsize; + } + else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize, + 0)) + { + /* The old guard area is too large. */ + +#ifdef NEED_SEPARATE_REGISTER_STACK + char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1); + char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1); + + if (oldguard < guard + && mprotect (oldguard, guard - oldguard, prot) != 0) + goto mprot_error; + + if (mprotect (guard + guardsize, + oldguard + pd->guardsize - guard - guardsize, + prot) != 0) + goto mprot_error; +#else + if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize, + prot) != 0) + goto mprot_error; +#endif + + pd->guardsize = guardsize; + } + /* The pthread_getattr_np() calls need to get passed the size + requested in the attribute, regardless of how large the + actually used guardsize is. */ + pd->reported_guardsize = guardsize; + } + + /* Initialize the lock. We have to do this unconditionally since the + stillborn thread could be canceled while the lock is taken. */ + pd->lock = LLL_LOCK_INITIALIZER; + + /* We place the thread descriptor at the end of the stack. */ + *pdp = pd; + +#if defined(TLS_TCB_AT_TP) + /* The stack begins before the TCB and the static TLS block. */ + stacktop = ((char *) (pd + 1) - __static_tls_size); +#elif defined(TLS_DTV_AT_TP) + stacktop = (char *) (pd - 1); +#endif + +#ifdef NEED_SEPARATE_REGISTER_STACK + *stack = pd->stackblock; + *stacksize = stacktop - *stack; +#else + *stack = stacktop; +#endif + + return 0; +} + + +void +internal_function +__deallocate_stack (struct pthread *pd) +{ + lll_lock (stack_cache_lock); + + /* Remove the thread from the list of threads with user defined + stacks. */ + list_del (&pd->list); + + /* Not much to do. Just free the mmap()ed memory. Note that we do + not reset the 'used' flag in the 'tid' field. This is done by + the kernel. If no thread has been created yet this field is + still zero. */ + if (__builtin_expect (! pd->user_stack, 1)) + (void) queue_stack (pd); + else + /* Free the memory associated with the ELF TLS. */ + _dl_deallocate_tls (TLS_TPADJ (pd), false); + + lll_unlock (stack_cache_lock); +} + + +int +internal_function +__make_stacks_executable (void **stack_endp) +{ + /* First the main thread's stack. */ + int err = EPERM; + if (err != 0) + return err; + +#ifdef NEED_SEPARATE_REGISTER_STACK + const size_t pagemask = ~(__getpagesize () - 1); +#endif + + lll_lock (stack_cache_lock); + + list_t *runp; + list_for_each (runp, &stack_used) + { + err = change_stack_perm (list_entry (runp, struct pthread, list) +#ifdef NEED_SEPARATE_REGISTER_STACK + , pagemask +#endif + ); + if (err != 0) + break; + } + + /* Also change the permission for the currently unused stacks. This + might be wasted time but better spend it here than adding a check + in the fast path. */ + if (err == 0) + list_for_each (runp, &stack_cache) + { + err = change_stack_perm (list_entry (runp, struct pthread, list) +#ifdef NEED_SEPARATE_REGISTER_STACK + , pagemask +#endif + ); + if (err != 0) + break; + } + + lll_unlock (stack_cache_lock); + + return err; +} + + +/* In case of a fork() call the memory allocation in the child will be + the same but only one thread is running. All stacks except that of + the one running thread are not used anymore. We have to recycle + them. */ +void +__reclaim_stacks (void) +{ + struct pthread *self = (struct pthread *) THREAD_SELF; + + /* No locking necessary. The caller is the only stack in use. */ + + /* Mark all stacks except the still running one as free. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + if (curp != self) + { + /* This marks the stack as free. */ + curp->tid = 0; + + /* The PID field must be initialized for the new process. */ + curp->pid = self->pid; + + /* Account for the size of the stack. */ + stack_cache_actsize += curp->stackblock_size; + } + } + + /* Add the stack of all running threads to the cache. */ + list_splice (&stack_used, &stack_cache); + + /* Remove the entry for the current thread to from the cache list + and add it to the list of running threads. Which of the two + lists is decided by the user_stack flag. */ + list_del (&self->list); + + /* Re-initialize the lists for all the threads. */ + INIT_LIST_HEAD (&stack_used); + INIT_LIST_HEAD (&__stack_user); + + if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0)) + list_add (&self->list, &__stack_user); + else + list_add (&self->list, &stack_used); + + /* There is one thread running. */ + __nptl_nthreads = 1; + + /* Initialize the lock. */ + stack_cache_lock = LLL_LOCK_INITIALIZER; +} + + +#if HP_TIMING_AVAIL +# undef __find_thread_by_id +/* Find a thread given the thread ID. */ +attribute_hidden +struct pthread * +__find_thread_by_id (pid_t tid) +{ + struct pthread *result = NULL; + + lll_lock (stack_cache_lock); + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + + if (curp->tid == tid) + { + result = curp; + goto out; + } + } + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + { + struct pthread *curp; + + curp = list_entry (runp, struct pthread, list); + + if (curp->tid == tid) + { + result = curp; + goto out; + } + } + + out: + lll_unlock (stack_cache_lock); + + return result; +} +#endif + +int +attribute_hidden +__nptl_setxid (struct xid_command *cmdp) +{ + int result; + lll_lock (stack_cache_lock); + + __xidcmd = cmdp; + cmdp->cntr = 0; + + INTERNAL_SYSCALL_DECL (err); + + struct pthread *self = THREAD_SELF; + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + int cur = cmdp->cntr; + while (cur != 0) + { + lll_futex_wait (&cmdp->cntr, cur); + cur = cmdp->cntr; + } + + /* This must be last, otherwise the current thread might not have + permissions to send SIGSETXID syscall to the other threads. */ + result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3, + cmdp->id[0], cmdp->id[1], cmdp->id[2]); + if (INTERNAL_SYSCALL_ERROR_P (result, err)) + { + __set_errno (INTERNAL_SYSCALL_ERRNO (result, err)); + result = -1; + } + + lll_unlock (stack_cache_lock); + return result; +} + +static inline void __attribute__((always_inline)) +init_one_static_tls (struct pthread *curp, struct link_map *map) +{ + dtv_t *dtv = GET_DTV (TLS_TPADJ (curp)); +# if defined(TLS_TCB_AT_TP) + void *dest = (char *) curp - map->l_tls_offset; +# elif defined(TLS_DTV_AT_TP) + void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Fill in the DTV slot so that a later LD/GD access will find it. */ + dtv[map->l_tls_modid].pointer.val = dest; + dtv[map->l_tls_modid].pointer.is_static = true; + + /* Initialize the memory. */ + memset (mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), + '\0', map->l_tls_blocksize - map->l_tls_initimage_size); +} + +void +attribute_hidden +__pthread_init_static_tls (struct link_map *map) +{ + lll_lock (stack_cache_lock); + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + init_one_static_tls (list_entry (runp, struct pthread, list), map); + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + init_one_static_tls (list_entry (runp, struct pthread, list), map); + + lll_unlock (stack_cache_lock); +} diff --git a/libpthread/nptl/banner.h b/libpthread/nptl/banner.h new file mode 100644 index 000000000..9982f4287 --- /dev/null +++ b/libpthread/nptl/banner.h @@ -0,0 +1 @@ +"Native POSIX Threads Library by Ulrich Drepper et al, uClibc port by Steven Hill\n" diff --git a/libpthread/nptl/cancellation.c b/libpthread/nptl/cancellation.c new file mode 100644 index 000000000..1d28d383f --- /dev/null +++ b/libpthread/nptl/cancellation.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" + + +/* The next two functions are similar to pthread_setcanceltype() but + more specialized for the use in the cancelable functions like write(). + They do not need to check parameters etc. */ +int +attribute_hidden +__pthread_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } + + break; + } + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__pthread_disable_asynccancel (int oldtype) +{ + /* If asynchronous cancellation was enabled before we do not have + anything to do. */ + if (oldtype & CANCELTYPE_BITMASK) + return; + + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} diff --git a/libpthread/nptl/cleanup.c b/libpthread/nptl/cleanup.c new file mode 100644 index 000000000..af828c49f --- /dev/null +++ b/libpthread/nptl/cleanup.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__cleanup_fct_attribute +__pthread_register_cancel (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); +} +hidden_def (__pthread_register_cancel) + + +void +__cleanup_fct_attribute +__pthread_unregister_cancel (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + THREAD_SETMEM (THREAD_SELF, cleanup_jmp_buf, ibuf->priv.data.prev); +} +hidden_def (__pthread_unregister_cancel) diff --git a/libpthread/nptl/cleanup_compat.c b/libpthread/nptl/cleanup_compat.c new file mode 100644 index 000000000..a25b397f9 --- /dev/null +++ b/libpthread/nptl/cleanup_compat.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +_pthread_cleanup_push (buffer, routine, arg) + struct _pthread_cleanup_buffer *buffer; + void (*routine) (void *); + void *arg; +{ + struct pthread *self = THREAD_SELF; + + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM (self, cleanup); + + THREAD_SETMEM (self, cleanup, buffer); +} +strong_alias (_pthread_cleanup_push, __pthread_cleanup_push) + + +void +_pthread_cleanup_pop (buffer, execute) + struct _pthread_cleanup_buffer *buffer; + int execute; +{ + struct pthread *self __attribute ((unused)) = THREAD_SELF; + + THREAD_SETMEM (self, cleanup, buffer->__prev); + + /* If necessary call the cleanup routine after we removed the + current cleanup block from the list. */ + if (execute) + buffer->__routine (buffer->__arg); +} +strong_alias (_pthread_cleanup_pop, __pthread_cleanup_pop) diff --git a/libpthread/nptl/cleanup_defer.c b/libpthread/nptl/cleanup_defer.c new file mode 100644 index 000000000..498d9557d --- /dev/null +++ b/libpthread/nptl/cleanup_defer.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__cleanup_fct_attribute +__pthread_register_cancel_defer (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + int cancelhandling = THREAD_GETMEM (self, cancelhandling); + + /* Disable asynchronous cancellation for now. */ + if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); +} + + +void +__cleanup_fct_attribute +__pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) +{ + struct pthread *self = THREAD_SELF; + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); + + int cancelhandling; + if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED + && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) + & CANCELTYPE_BITMASK) == 0) + { + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + | CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + CANCELLATION_P (self); + } +} diff --git a/libpthread/nptl/cleanup_defer_compat.c b/libpthread/nptl/cleanup_defer_compat.c new file mode 100644 index 000000000..a0ed6da88 --- /dev/null +++ b/libpthread/nptl/cleanup_defer_compat.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +void +_pthread_cleanup_push_defer (buffer, routine, arg) + struct _pthread_cleanup_buffer *buffer; + void (*routine) (void *); + void *arg; +{ + struct pthread *self = THREAD_SELF; + + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM (self, cleanup); + + int cancelhandling = THREAD_GETMEM (self, cancelhandling); + + /* Disable asynchronous cancellation for now. */ + if (__builtin_expect (cancelhandling & CANCELTYPE_BITMASK, 0)) + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + & ~CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + THREAD_SETMEM (self, cleanup, buffer); +} +strong_alias (_pthread_cleanup_push_defer, __pthread_cleanup_push_defer) + + +void +_pthread_cleanup_pop_restore (buffer, execute) + struct _pthread_cleanup_buffer *buffer; + int execute; +{ + struct pthread *self = THREAD_SELF; + + THREAD_SETMEM (self, cleanup, buffer->__prev); + + int cancelhandling; + if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0) + && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) + & CANCELTYPE_BITMASK) == 0) + { + while (1) + { + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + cancelhandling + | CANCELTYPE_BITMASK, + cancelhandling); + if (__builtin_expect (curval == cancelhandling, 1)) + /* Successfully replaced the value. */ + break; + + /* Prepare for the next round. */ + cancelhandling = curval; + } + + CANCELLATION_P (self); + } + + /* If necessary call the cleanup routine after we removed the + current cleanup block from the list. */ + if (execute) + buffer->__routine (buffer->__arg); +} +strong_alias (_pthread_cleanup_pop_restore, __pthread_cleanup_pop_restore) diff --git a/libpthread/nptl/cleanup_routine.c b/libpthread/nptl/cleanup_routine.c new file mode 100644 index 000000000..cbf231834 --- /dev/null +++ b/libpthread/nptl/cleanup_routine.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> + + +void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} diff --git a/libpthread/nptl/descr.h b/libpthread/nptl/descr.h new file mode 100644 index 000000000..1a8d91be8 --- /dev/null +++ b/libpthread/nptl/descr.h @@ -0,0 +1,271 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DESCR_H +#define _DESCR_H 1 + +#include <limits.h> +#include <sched.h> +#include <setjmp.h> +#include <stdbool.h> +#include <sys/types.h> +#include <hp-timing.h> +#include <list.h> +#include <lowlevellock.h> +#include <pthreaddef.h> +#include "../nptl_db/thread_db.h" +#include <tls.h> +#ifdef HAVE_FORCED_UNWIND +# include <unwind.h> +#endif +#define __need_res_state +#include <resolv.h> + +#ifndef TCB_ALIGNMENT +# define TCB_ALIGNMENT sizeof (double) +#endif + + +/* We keep thread specific data in a special data structure, a two-level + array. The top-level array contains pointers to dynamically allocated + arrays of a certain number of data pointers. So we can implement a + sparse array. Each dynamic second-level array has + PTHREAD_KEY_2NDLEVEL_SIZE + entries. This value shouldn't be too large. */ +#define PTHREAD_KEY_2NDLEVEL_SIZE 32 + +/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE + keys in each subarray. */ +#define PTHREAD_KEY_1STLEVEL_SIZE \ + ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \ + / PTHREAD_KEY_2NDLEVEL_SIZE) + + + + +/* Internal version of the buffer to store cancellation handler + information. */ +struct pthread_unwind_buf +{ + struct + { + __jmp_buf jmp_buf; + int mask_was_saved; + } cancel_jmp_buf[1]; + + union + { + /* This is the placeholder of the public version. */ + void *pad[4]; + + struct + { + /* Pointer to the previous cleanup buffer. */ + struct pthread_unwind_buf *prev; + + /* Backward compatibility: state of the old-style cleanup + handler at the time of the previous new-style cleanup handler + installment. */ + struct _pthread_cleanup_buffer *cleanup; + + /* Cancellation type before the push call. */ + int canceltype; + } data; + } priv; +}; + + +/* Opcodes and data types for communication with the signal handler to + change user/group IDs. */ +struct xid_command +{ + int syscall_no; + long int id[3]; + volatile int cntr; +}; + + +/* Thread descriptor data structure. */ +struct pthread +{ + union + { +#if !defined(TLS_DTV_AT_TP) + /* This overlaps the TCB as used for TLS without threads (see tls.h). */ + tcbhead_t header; +#else + struct + { + int multiple_threads; + } header; +#endif + + /* This extra padding has no special purpose, and this structure layout + is private and subject to change without affecting the official ABI. + We just have it here in case it might be convenient for some + implementation-specific instrumentation hack or suchlike. */ + void *__padding[16]; + }; + + /* This descriptor's link on the `stack_used' or `__stack_user' list. */ + list_t list; + + /* Thread ID - which is also a 'is this thread descriptor (and + therefore stack) used' flag. */ + pid_t tid; + + /* Process ID - thread group ID in kernel speak. */ + pid_t pid; + + /* List of cleanup buffers. */ + struct _pthread_cleanup_buffer *cleanup; + + /* Unwind information. */ + struct pthread_unwind_buf *cleanup_jmp_buf; +#define HAVE_CLEANUP_JMP_BUF + + /* Flags determining processing of cancellation. */ + int cancelhandling; + /* Bit set if cancellation is disabled. */ +#define CANCELSTATE_BIT 0 +#define CANCELSTATE_BITMASK 0x01 + /* Bit set if asynchronous cancellation mode is selected. */ +#define CANCELTYPE_BIT 1 +#define CANCELTYPE_BITMASK 0x02 + /* Bit set if canceling has been initiated. */ +#define CANCELING_BIT 2 +#define CANCELING_BITMASK 0x04 + /* Bit set if canceled. */ +#define CANCELED_BIT 3 +#define CANCELED_BITMASK 0x08 + /* Bit set if thread is exiting. */ +#define EXITING_BIT 4 +#define EXITING_BITMASK 0x10 + /* Bit set if thread terminated and TCB is freed. */ +#define TERMINATED_BIT 5 +#define TERMINATED_BITMASK 0x20 + /* Bit set if thread is supposed to change XID. */ +#define SETXID_BIT 6 +#define SETXID_BITMASK 0x40 + /* Mask for the rest. Helps the compiler to optimize. */ +#define CANCEL_RESTMASK 0xffffff80 + +#define CANCEL_ENABLED_AND_CANCELED(value) \ + (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \ + | CANCEL_RESTMASK | TERMINATED_BITMASK)) == CANCELED_BITMASK) +#define CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS(value) \ + (((value) & (CANCELSTATE_BITMASK | CANCELTYPE_BITMASK | CANCELED_BITMASK \ + | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK)) \ + == (CANCELTYPE_BITMASK | CANCELED_BITMASK)) + + /* We allocate one block of references here. This should be enough + to avoid allocating any memory dynamically for most applications. */ + struct pthread_key_data + { + /* Sequence number. We use uintptr_t to not require padding on + 32- and 64-bit machines. On 64-bit machines it helps to avoid + wrapping, too. */ + uintptr_t seq; + + /* Data pointer. */ + void *data; + } specific_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE]; + + /* Flag which is set when specific data is set. */ + bool specific_used; + + /* Two-level array for the thread-specific data. */ + struct pthread_key_data *specific[PTHREAD_KEY_1STLEVEL_SIZE]; + + /* True if events must be reported. */ + bool report_events; + + /* True if the user provided the stack. */ + bool user_stack; + + /* True if thread must stop at startup time. */ + bool stopped_start; + + /* Lock to synchronize access to the descriptor. */ + lll_lock_t lock; + + /* Lock for synchronizing setxid calls. */ + lll_lock_t setxid_futex; + +#if HP_TIMING_AVAIL + /* Offset of the CPU clock at start thread start time. */ + hp_timing_t cpuclock_offset; +#endif + + /* If the thread waits to join another one the ID of the latter is + stored here. + + In case a thread is detached this field contains a pointer of the + TCB if the thread itself. This is something which cannot happen + in normal operation. */ + struct pthread *joinid; + /* Check whether a thread is detached. */ +#define IS_DETACHED(pd) ((pd)->joinid == (pd)) + + /* Flags. Including those copied from the thread attribute. */ + int flags; + + /* The result of the thread function. */ + void *result; + + /* Scheduling parameters for the new thread. */ + struct sched_param schedparam; + int schedpolicy; + + /* Start position of the code to be executed and the argument passed + to the function. */ + void *(*start_routine) (void *); + void *arg; + + /* Debug state. */ + td_eventbuf_t eventbuf; + /* Next descriptor with a pending event. */ + struct pthread *nextevent; + +#ifdef HAVE_FORCED_UNWIND + /* Machine-specific unwind info. */ + struct _Unwind_Exception exc; +#endif + + /* If nonzero pointer to area allocated for the stack and its + size. */ + void *stackblock; + size_t stackblock_size; + /* Size of the included guard area. */ + size_t guardsize; + /* This is what the user specified and what we will report. */ + size_t reported_guardsize; + + /* Resolver state. */ + struct __res_state res; + + /* This member must be last. */ + char end_padding[]; + +#define PTHREAD_STRUCT_END_PADDING \ + (sizeof (struct pthread) - offsetof (struct pthread, end_padding)) +} __attribute ((aligned (TCB_ALIGNMENT))); + + +#endif /* descr.h */ diff --git a/libpthread/nptl/eintr.c b/libpthread/nptl/eintr.c new file mode 100644 index 000000000..933c5d81b --- /dev/null +++ b/libpthread/nptl/eintr.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <unistd.h> + + +static int the_sig; + + +static void +eintr_handler (int sig) +{ + if (sig != the_sig) + { + write (STDOUT_FILENO, "eintr_handler: signal number wrong\n", 35); + _exit (1); + } + write (STDOUT_FILENO, ".", 1); +} + + +static void * +eintr_source (void *arg) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000 }; + + if (arg == NULL) + { + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, the_sig); + pthread_sigmask (SIG_BLOCK, &ss, NULL); + } + + while (1) + { + if (arg != NULL) + pthread_kill (*(pthread_t *) arg, the_sig); + else + kill (getpid (), the_sig); + + nanosleep (&ts, NULL); + } + + /* NOTREACHED */ + return NULL; +} + + +static void +setup_eintr (int sig, pthread_t *thp) +{ + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = eintr_handler; + if (sigaction (sig, &sa, NULL) != 0) + { + puts ("setup_eintr: sigaction failed"); + exit (1); + } + the_sig = sig; + + /* Create the thread which will fire off the signals. */ + pthread_t th; + if (pthread_create (&th, NULL, eintr_source, thp) != 0) + { + puts ("setup_eintr: pthread_create failed"); + exit (1); + } +} diff --git a/libpthread/nptl/events.c b/libpthread/nptl/events.c new file mode 100644 index 000000000..df97e54f6 --- /dev/null +++ b/libpthread/nptl/events.c @@ -0,0 +1,34 @@ +/* Event functions used while debugging. + Copyright (C) 1999, 2000, 2002 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The functions contained here do nothing, they just return. */ + +#include "pthreadP.h" + +void +__nptl_create_event (void) +{ +} +hidden_def (__nptl_create_event) + +void +__nptl_death_event (void) +{ +} +hidden_def (__nptl_death_event) diff --git a/libpthread/nptl/forward.c b/libpthread/nptl/forward.c new file mode 100644 index 000000000..5b71f8e67 --- /dev/null +++ b/libpthread/nptl/forward.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <dlfcn.h> +#include <pthreadP.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <sysdep.h> + + +/* Pointers to the libc functions. */ +struct pthread_functions __libc_pthread_functions attribute_hidden; + + +#define FORWARD2(name, rettype, decl, params, defaction) \ +rettype \ +name decl \ +{ \ + if (__libc_pthread_functions.ptr_##name == NULL) \ + defaction; \ + \ + return __libc_pthread_functions.ptr_##name params; \ +} + +#define FORWARD(name, decl, params, defretval) \ + FORWARD2 (name, int, decl, params, return defretval) + + +FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0) + +FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0) +weak_alias(__pthread_attr_init_2_1, pthread_attr_init) + +FORWARD (pthread_attr_getdetachstate, + (const pthread_attr_t *attr, int *detachstate), (attr, detachstate), + 0) +FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate), + (attr, detachstate), 0) + +FORWARD (pthread_attr_getinheritsched, + (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0) +FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit), + (attr, inherit), 0) + +FORWARD (pthread_attr_getschedparam, + (const pthread_attr_t *attr, struct sched_param *param), + (attr, param), 0) +FORWARD (pthread_attr_setschedparam, + (pthread_attr_t *attr, const struct sched_param *param), + (attr, param), 0) + +FORWARD (pthread_attr_getschedpolicy, + (const pthread_attr_t *attr, int *policy), (attr, policy), 0) +FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy), + (attr, policy), 0) + +FORWARD (pthread_attr_getscope, + (const pthread_attr_t *attr, int *scope), (attr, scope), 0) +FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope), + (attr, scope), 0) + + +FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0) +FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0) + +FORWARD (__pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) + +FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_destroy, pthread_cond_destroy) + +FORWARD (__pthread_cond_init, + (pthread_cond_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), 0) +weak_alias(__pthread_cond_init, pthread_cond_init) + +FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0) +weak_alias(__pthread_cond_signal, pthread_cond_signal) + +FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex), + (cond, mutex), 0) +weak_alias(__pthread_cond_wait, pthread_cond_wait) + +FORWARD (__pthread_cond_timedwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), 0) +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + +FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), + (thread1, thread2), 1) + + +/* Use an alias to avoid warning, as pthread_exit is declared noreturn. */ +FORWARD2 (__pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS)) +strong_alias (__pthread_exit, pthread_exit); + + +FORWARD (pthread_getschedparam, + (pthread_t target_thread, int *policy, struct sched_param *param), + (target_thread, policy, param), 0) +FORWARD (pthread_setschedparam, + (pthread_t target_thread, int policy, + const struct sched_param *param), (target_thread, policy, param), 0) + + +FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0) + +libc_hidden_proto(pthread_mutex_init) +FORWARD (pthread_mutex_init, + (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr), + (mutex, mutexattr), 0) +strong_alias(pthread_mutex_init, __pthread_mutex_init) +libc_hidden_def(pthread_mutex_init) + +libc_hidden_proto(pthread_mutex_trylock) +FORWARD (pthread_mutex_trylock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_trylock, __pthread_mutex_trylock) +libc_hidden_def(pthread_mutex_trylock) + +libc_hidden_proto(pthread_mutex_lock) +FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_lock, __pthread_mutex_lock) +libc_hidden_def(pthread_mutex_lock) + +libc_hidden_proto(pthread_mutex_unlock) +FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0) +strong_alias(pthread_mutex_unlock, __pthread_mutex_unlock) +libc_hidden_def(pthread_mutex_unlock) + +FORWARD (pthread_mutexattr_init, (pthread_mutexattr_t *attr), (attr), 0) + +FORWARD (pthread_mutexattr_destroy, (pthread_mutexattr_t *attr), (attr), 0) + +FORWARD (pthread_mutexattr_settype, (pthread_mutexattr_t *attr, int kind), + (attr, kind), 0) + + +FORWARD2 (pthread_self, pthread_t, (void), (), return 0) + + +FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate), + 0) + +FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0) + +#define return /* value is void */ +FORWARD2(__pthread_unwind, + void attribute_hidden __attribute ((noreturn)) __cleanup_fct_attribute, + (__pthread_unwind_buf_t *buf), (buf), { + /* We cannot call abort() here. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 1, SIGKILL); + }) +#undef return diff --git a/libpthread/nptl/herrno.c b/libpthread/nptl/herrno.c new file mode 100644 index 000000000..6e8339d43 --- /dev/null +++ b/libpthread/nptl/herrno.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1996,97,98,2002 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> +#include <netdb.h> +#undef h_errno + +#include <tls.h> + +/* We need to have the error status variable of the resolver + accessible in the libc. */ +extern __thread int h_errno; + + +/* When threaded, h_errno may be a per-thread variable. */ +int * +__h_errno_location (void) +{ + return &h_errno; +} diff --git a/libpthread/nptl/init.c b/libpthread/nptl/init.c new file mode 100644 index 000000000..0c55bbb8f --- /dev/null +++ b/libpthread/nptl/init.c @@ -0,0 +1,329 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <limits.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <pthreadP.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> +#include <fork.h> +#include <smp.h> +#include <lowlevellock.h> +#include <version.h> + + +#ifndef __NR_set_tid_address +/* XXX For the time being... Once we can rely on the kernel headers + having the definition remove these lines. */ +#if defined __s390__ +# define __NR_set_tid_address 252 +#elif defined __ia64__ +# define __NR_set_tid_address 1233 +#elif defined __i386__ +# define __NR_set_tid_address 258 +#elif defined __x86_64__ +# define __NR_set_tid_address 218 +#elif defined __powerpc__ +# define __NR_set_tid_address 232 +#elif defined __sparc__ +# define __NR_set_tid_address 166 +#else +# error "define __NR_set_tid_address" +#endif +#endif + + +/* Size and alignment of static TLS block. */ +size_t __static_tls_size; +size_t __static_tls_align_m1; + +/* Version of the library, used in libthread_db to detect mismatches. */ +static const char nptl_version[] __attribute_used__ = VERSION; + + +#if defined USE_TLS && !defined SHARED +extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign); +#endif + +int +__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + + +#ifdef SHARED +static const struct pthread_functions pthread_functions = + { + .ptr_pthread_attr_destroy = __pthread_attr_destroy, + .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1, + .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate, + .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate, + .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched, + .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched, + .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam, + .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam, + .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy, + .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy, + .ptr_pthread_attr_getscope = __pthread_attr_getscope, + .ptr_pthread_attr_setscope = __pthread_attr_setscope, + .ptr_pthread_condattr_destroy = __pthread_condattr_destroy, + .ptr_pthread_condattr_init = __pthread_condattr_init, + .ptr___pthread_cond_broadcast = __pthread_cond_broadcast, + .ptr___pthread_cond_destroy = __pthread_cond_destroy, + .ptr___pthread_cond_init = __pthread_cond_init, + .ptr___pthread_cond_signal = __pthread_cond_signal, + .ptr___pthread_cond_wait = __pthread_cond_wait, + .ptr___pthread_cond_timedwait = __pthread_cond_timedwait, + .ptr_pthread_equal = __pthread_equal, + .ptr___pthread_exit = __pthread_exit, + .ptr_pthread_getschedparam = __pthread_getschedparam, + .ptr_pthread_setschedparam = __pthread_setschedparam, + .ptr_pthread_mutex_destroy = __pthread_mutex_destroy, + .ptr_pthread_mutex_init = __pthread_mutex_init, + .ptr_pthread_mutex_lock = __pthread_mutex_lock, + .ptr_pthread_mutex_unlock = __pthread_mutex_unlock, + .ptr_pthread_self = __pthread_self, + .ptr_pthread_setcancelstate = __pthread_setcancelstate, + .ptr_pthread_setcanceltype = __pthread_setcanceltype, + .ptr___pthread_cleanup_upto = __pthread_cleanup_upto, + .ptr___pthread_once = __pthread_once_internal, + .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal, + .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal, + .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal, + .ptr___pthread_key_create = __pthread_key_create_internal, + .ptr___pthread_getspecific = __pthread_getspecific_internal, + .ptr___pthread_setspecific = __pthread_setspecific_internal, + .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer, + .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore, + .ptr_nthreads = &__nptl_nthreads, + .ptr___pthread_unwind = &__pthread_unwind, + .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd, + .ptr__nptl_setxid = __nptl_setxid + }; +# define ptr_pthread_functions &pthread_functions +#else +# define ptr_pthread_functions NULL +#endif + + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sigcancel_handler (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL +#ifdef __ASSUME_CORRECT_SI_PID + /* Kernels before 2.5.75 stored the thread ID and not the process + ID in si_pid so we skip this test. */ + || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid) +#endif + || si->si_code != SI_TKILL) + return; + + struct pthread *self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + /* We are canceled now. When canceled by another thread this flag + is already set but if the signal is directly send (internally or + from another process) is has to be done here. */ + int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; + + if (oldval == newval || (oldval & EXITING_BITMASK) != 0) + /* Already canceled or exiting. */ + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (curval == oldval) + { + /* Set the return value. */ + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + /* Make sure asynchronous cancellation is still enabled. */ + if ((newval & CANCELTYPE_BITMASK) != 0) + /* Run the registered destructors and terminate the thread. */ + __do_cancel (); + + break; + } + + oldval = curval; + } +} + + +struct xid_command *__xidcmd attribute_hidden; + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sighandler_setxid (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGSETXID +#ifdef __ASSUME_CORRECT_SI_PID + /* Kernels before 2.5.75 stored the thread ID and not the process + ID in si_pid so we skip this test. */ + || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid) +#endif + || si->si_code != SI_TKILL) + return; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0], + __xidcmd->id[1], __xidcmd->id[2]); + + if (atomic_decrement_val (&__xidcmd->cntr) == 0) + lll_futex_wake (&__xidcmd->cntr, 1); +} + + +/* When using __thread for this, we do it in libc so as not + to give libpthread its own TLS segment just for this. */ +extern void **__libc_dl_error_tsd (void) __attribute__ ((const)); + + +void +__pthread_initialize_minimal_internal (void) +{ +#ifndef SHARED + /* Unlike in the dynamically linked case the dynamic linker has not + taken care of initializing the TLS data structures. */ + __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN); + + /* We must prevent gcc from being clever and move any of the + following code ahead of the __libc_setup_tls call. This function + will initialize the thread register which is subsequently + used. */ + __asm __volatile (""); +#endif + + /* Minimal initialization of the thread descriptor. */ + struct pthread *pd = THREAD_SELF; + INTERNAL_SYSCALL_DECL (err); + pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); + THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]); + THREAD_SETMEM (pd, user_stack, true); + if (LLL_LOCK_INITIALIZER != 0) + THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER); +#if HP_TIMING_AVAIL + THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset)); +#endif + + /* Set initial thread's stack block from 0 up to __libc_stack_end. + It will be bigger than it actually is, but for unwind.c/pt-longjmp.c + purposes this is good enough. */ + THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end); + + /* Initialize the list of all running threads with the main thread. */ + INIT_LIST_HEAD (&__stack_user); + list_add (&pd->list, &__stack_user); + + + /* Install the cancellation signal handler. If for some reason we + cannot install the handler we do not abort. Maybe we should, but + it is only asynchronous cancellation which is affected. */ + struct sigaction sa; + sa.sa_sigaction = sigcancel_handler; + sa.sa_flags = SA_SIGINFO; + __sigemptyset (&sa.sa_mask); + + (void) __libc_sigaction (SIGCANCEL, &sa, NULL); + + /* Install the handle to change the threads' uid/gid. */ + sa.sa_sigaction = sighandler_setxid; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + + (void) __libc_sigaction (SIGSETXID, &sa, NULL); + + /* The parent process might have left the signals blocked. Just in + case, unblock it. We reuse the signal mask in the sigaction + structure. It is already cleared. */ + __sigaddset (&sa.sa_mask, SIGCANCEL); + __sigaddset (&sa.sa_mask, SIGSETXID); + (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask, + NULL, _NSIG / 8); + + /* Get the size of the static and alignment requirements for the TLS + block. */ + size_t static_tls_align; + _dl_get_tls_static_info (&__static_tls_size, &static_tls_align); + + /* Make sure the size takes all the alignments into account. */ + if (STACK_ALIGN > static_tls_align) + static_tls_align = STACK_ALIGN; + __static_tls_align_m1 = static_tls_align - 1; + + __static_tls_size = roundup (__static_tls_size, static_tls_align); + + /* Determine the default allowed stack size. This is the size used + in case the user does not specify one. */ + struct rlimit limit; + if (getrlimit (RLIMIT_STACK, &limit) != 0 + || limit.rlim_cur == RLIM_INFINITY) + /* The system limit is not usable. Use an architecture-specific + default. */ + limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE; + else if (limit.rlim_cur < PTHREAD_STACK_MIN) + /* The system limit is unusably small. + Use the minimal size acceptable. */ + limit.rlim_cur = PTHREAD_STACK_MIN; + + /* Make sure it meets the minimum size that allocate_stack + (allocatestack.c) will demand, which depends on the page size. */ + const uintptr_t pagesz = sysconf (_SC_PAGESIZE); + const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK; + if (limit.rlim_cur < minstack) + limit.rlim_cur = minstack; + + /* Round the resource limit up to page size. */ + limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz; + __default_stacksize = limit.rlim_cur; + +#ifdef SHARED + /* Transfer the old value from the dynamic linker's internal location. */ + *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) (); + GL(dl_error_catch_tsd) = &__libc_dl_error_tsd; +#endif + + GL(dl_init_static_tls) = &__pthread_init_static_tls; + + /* Register the fork generation counter with the libc. */ +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + __libc_multiple_threads_ptr = +#endif + __libc_pthread_init (&__fork_generation, __reclaim_stacks, + ptr_pthread_functions); + + /* Determine whether the machine is SMP or not. */ + __is_smp = is_smp_system (); +} +strong_alias (__pthread_initialize_minimal_internal, + __pthread_initialize_minimal) diff --git a/libpthread/nptl/libc-cancellation.c b/libpthread/nptl/libc-cancellation.c new file mode 100644 index 000000000..c9237e095 --- /dev/null +++ b/libpthread/nptl/libc-cancellation.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "atomic.h" +#include <bits/libc-lock.h> + + +#ifndef NOT_IN_libc + +/* The next two functions are similar to pthread_setcanceltype() but + more specialized for the use in the cancelable functions like write(). + They do not need to check parameters etc. */ +int +attribute_hidden +__libc_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (__builtin_expect ((oldval & CANCELED_BITMASK) != 0, 0)) + { + /* If we are already exiting or if PTHREAD_CANCEL_DISABLED, + stop right here. */ + if ((oldval & (EXITING_BITMASK | CANCELSTATE_BITMASK)) != 0) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + newval, oldval); + if (__builtin_expect (curval != oldval, 0)) + { + /* Somebody else modified the word, try again. */ + oldval = curval; + continue; + } + + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + __do_cancel (); + + /* NOTREACHED */ + } + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__libc_disable_asynccancel (int oldtype) +{ + /* If asynchronous cancellation was enabled before we do not have + anything to do. */ + if (oldtype & CANCELTYPE_BITMASK) + return; + + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} + + +void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} + +#endif diff --git a/libpthread/nptl/linux_fsinfo.h b/libpthread/nptl/linux_fsinfo.h new file mode 100644 index 000000000..13c385626 --- /dev/null +++ b/libpthread/nptl/linux_fsinfo.h @@ -0,0 +1,153 @@ +/* Constants from kernel header for various FSes. + Copyright (C) 1998,1999,2000,2001,2002,2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_FSINFO_H +#define _LINUX_FSINFO_H 1 + +/* These definitions come from the kernel headers. But we cannot + include the headers here because of type clashes. If new + filesystem types will become available we have to add the + appropriate definitions here.*/ + +/* Constants that identify the `adfs' filesystem. */ +#define ADFS_SUPER_MAGIC 0xadf5 + +/* Constants that identify the `affs' filesystem. */ +#define AFFS_SUPER_MAGIC 0xadff + +/* Constants that identify the `autofs' filesystem. */ +#define AUTOFS_SUPER_MAGIC 0x187 + +/* Constants that identify the `bfs' filesystem. */ +#define BFS_MAGIC 0x1BADFACE + +/* Constants that identify the `coda' filesystem. */ +#define CODA_SUPER_MAGIC 0x73757245 + +/* Constants that identify the `coherent' filesystem. */ +#define COH_SUPER_MAGIC 0x012ff7b7 + +/* Constant that identifies the `ramfs' filesystem. */ +#define CRAMFS_MAGIC 0x28cd3d45 + +/* Constant that identifies the `devfs' filesystem. */ +#define DEVFS_SUPER_MAGIC 0x1373 + +/* Constant that identifies the `devpts' filesystem. */ +#define DEVPTS_SUPER_MAGIC 0x1cd1 + +/* Constant that identifies the `efs' filesystem. */ +#define EFS_SUPER_MAGIC 0x414A53 +#define EFS_MAGIC 0x072959 + +/* Constant that identifies the `ext2' and `ext3' filesystems. */ +#define EXT2_SUPER_MAGIC 0xef53 + +/* Constant that identifies the `hpfs' filesystem. */ +#define HPFS_SUPER_MAGIC 0xf995e849 + +/* Constant that identifies the `iso9660' filesystem. */ +#define ISOFS_SUPER_MAGIC 0x9660 + +/* Constant that identifies the `jffs' filesystem. */ +#define JFFS_SUPER_MAGIC 0x07c0 + +/* Constant that identifies the `jffs2' filesystem. */ +#define JFFS2_SUPER_MAGIC 0x72b6 + +/* Constant that identifies the `jfs' filesystem. */ +#define JFS_SUPER_MAGIC 0x3153464a + +/* Constants that identify the `minix2' filesystem. */ +#define MINIX2_SUPER_MAGIC 0x2468 +#define MINIX2_SUPER_MAGIC2 0x2478 + +/* Constants that identify the `minix' filesystem. */ +#define MINIX_SUPER_MAGIC 0x137f +#define MINIX_SUPER_MAGIC2 0x138F + +/* Constants that identify the `msdos' filesystem. */ +#define MSDOS_SUPER_MAGIC 0x4d44 + +/* Constants that identify the `ncp' filesystem. */ +#define NCP_SUPER_MAGIC 0x564c + +/* Constants that identify the `nfs' filesystem. */ +#define NFS_SUPER_MAGIC 0x6969 + +/* Constants that identify the `ntfs' filesystem. */ +#define NTFS_SUPER_MAGIC 0x5346544e + +/* Constants that identify the `proc' filesystem. */ +#define PROC_SUPER_MAGIC 0x9fa0 + +/* Constant that identifies the `usbdevfs' filesystem. */ +#define USBDEVFS_SUPER_MAGIC 0x9fa2 + +/* Constants that identify the `qnx4' filesystem. */ +#define QNX4_SUPER_MAGIC 0x002f + +/* Constants that identify the `reiser' filesystem. */ +#define REISERFS_SUPER_MAGIC 0x52654973 + +/* Constant that identifies the `romfs' filesystem. */ +#define ROMFS_SUPER_MAGIC 0x7275 + +/* Constants that identify the `smb' filesystem. */ +#define SMB_SUPER_MAGIC 0x517b + +/* Constants that identify the `sysV' filesystem. */ +#define SYSV2_SUPER_MAGIC 0x012ff7b6 +#define SYSV4_SUPER_MAGIC 0x012ff7b5 + +/* Constants that identify the `udf' filesystem. */ +#define UDF_SUPER_MAGIC 0x15013346 + +/* Constants that identify the `ufs' filesystem. */ +#define UFS_MAGIC 0x00011954 +#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ + +/* Constants that identify the `xenix' filesystem. */ +#define XENIX_SUPER_MAGIC 0x012ff7b4 + +/* Constant that identifies the `shm' filesystem. */ +#define SHMFS_SUPER_MAGIC 0x01021994 + +/* Constants that identify the `xfs' filesystem. */ +#define XFS_SUPER_MAGIC 0x58465342 + +/* Constants that identify the `vxfs' filesystem. */ +#define VXFS_SUPER_MAGIC 0xa501fcf5 + +/* Maximum link counts. */ +#define COH_LINK_MAX 10000 +#define EXT2_LINK_MAX 32000 +#define MINIX2_LINK_MAX 65530 +#define MINIX_LINK_MAX 250 +#define REISERFS_LINK_MAX 64535 +#define SYSV_LINK_MAX 126 /* 127? 251? */ +#define UFS_LINK_MAX EXT2_LINK_MAX +#define XENIX_LINK_MAX 126 /* ?? */ +#define XFS_LINK_MAX 2147483647 + +/* The Linux kernel header mentioned this as a kind of generic value. */ +#define LINUX_LINK_MAX 127 + + +#endif /* linux_fsinfo.h */ diff --git a/libpthread/nptl/pt-cleanup.c b/libpthread/nptl/pt-cleanup.c new file mode 100644 index 000000000..f5fdedeb6 --- /dev/null +++ b/libpthread/nptl/pt-cleanup.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "jmpbuf-unwind.h" + +void +__pthread_cleanup_upto (__jmp_buf target, char *targetframe) +{ + struct pthread *self = THREAD_SELF; + struct _pthread_cleanup_buffer *cbuf; + + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; + uintptr_t targetframe_adj = (uintptr_t) targetframe - adj; + + for (cbuf = THREAD_GETMEM (self, cleanup); + cbuf != NULL && _JMPBUF_UNWINDS_ADJ (target, cbuf, adj); + cbuf = cbuf->__prev) + { +#if _STACK_GROWS_DOWN + if ((uintptr_t) cbuf - adj <= targetframe_adj) + { + cbuf = NULL; + break; + } +#elif _STACK_GROWS_UP + if ((uintptr_t) cbuf - adj >= targetframe_adj) + { + cbuf = NULL; + break; + } +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + + /* Call the cleanup code. */ + cbuf->__routine (cbuf->__arg); + } + + THREAD_SETMEM (self, cleanup, cbuf); +} +hidden_def (__pthread_cleanup_upto) diff --git a/libpthread/nptl/pt-system.c b/libpthread/nptl/pt-system.c new file mode 100644 index 000000000..09a08ec24 --- /dev/null +++ b/libpthread/nptl/pt-system.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <sysdep.h> +#include "pthreadP.h" + + +extern __typeof(system) __libc_system; +#include <system.c> + +int +system (const char *line) +{ + return __libc_system (line); +} + +/* __libc_system in libc.so handles cancellation. */ +LIBC_CANCEL_HANDLED (); diff --git a/libpthread/nptl/pthread-errnos.sym b/libpthread/nptl/pthread-errnos.sym new file mode 100644 index 000000000..2bb4d0d3c --- /dev/null +++ b/libpthread/nptl/pthread-errnos.sym @@ -0,0 +1,12 @@ +#include <errno.h> + +-- These errno codes are used by some assembly code. + +EAGAIN EAGAIN +EBUSY EBUSY +EDEADLK EDEADLK +EINTR EINTR +EINVAL EINVAL +ENOSYS ENOSYS +ETIMEDOUT ETIMEDOUT +EWOULDBLOCK EWOULDBLOCK diff --git a/libpthread/nptl/pthreadP.h b/libpthread/nptl/pthreadP.h new file mode 100644 index 000000000..45222f45e --- /dev/null +++ b/libpthread/nptl/pthreadP.h @@ -0,0 +1,466 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREADP_H +#define _PTHREADP_H 1 + +#include <pthread.h> +#include <setjmp.h> +#include <stdbool.h> +#include <sys/syscall.h> +#include "descr.h" +#include <tls.h> +#include <lowlevellock.h> +#include <bits/stackinfo.h> +#include <internaltypes.h> +#include <pthread-functions.h> +#include <atomic.h> + + +/* Atomic operations on TLS memory. */ +#ifndef THREAD_ATOMIC_CMPXCHG_VAL +# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, new, old) \ + atomic_compare_and_exchange_val_acq (&(descr)->member, new, old) +#endif + +#ifndef THREAD_ATOMIC_BIT_SET +# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ + atomic_bit_set (&(descr)->member, bit) +#endif + + +/* Adaptive mutex definitions. */ +#ifndef MAX_ADAPTIVE_COUNT +# define MAX_ADAPTIVE_COUNT 100 +#endif + + +/* Internal variables. */ + + +/* Default stack size. */ +extern size_t __default_stacksize attribute_hidden; + +/* Size and alignment of static TLS block. */ +extern size_t __static_tls_size attribute_hidden; +extern size_t __static_tls_align_m1 attribute_hidden; + +/* Flag whether the machine is SMP or not. */ +extern int __is_smp attribute_hidden; + +/* Thread descriptor handling. */ +extern list_t __stack_user; +hidden_proto (__stack_user) + +/* Attribute handling. */ +extern struct pthread_attr *__attr_list attribute_hidden; +extern lll_lock_t __attr_list_lock attribute_hidden; + +/* First available RT signal. */ +extern int __current_sigrtmin attribute_hidden; +/* Last available RT signal. */ +extern int __current_sigrtmax attribute_hidden; + +/* Concurrency handling. */ +extern int __concurrency_level attribute_hidden; + +/* Thread-local data key handling. */ +extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]; +hidden_proto (__pthread_keys) + +/* Number of threads running. */ +extern unsigned int __nptl_nthreads attribute_hidden; + +/* The library can run in debugging mode where it performs a lot more + tests. */ +extern int __pthread_debug attribute_hidden; +/** For now disable debugging support. */ +#if 0 +# define DEBUGGING_P __builtin_expect (__pthread_debug, 0) +# define INVALID_TD_P(pd) (DEBUGGING_P && __find_in_stack_list (pd) == NULL) +# define INVALID_NOT_TERMINATED_TD_P(pd) INVALID_TD_P (pd) +#else +# define DEBUGGING_P 0 +/* Simplified test. This will not catch all invalid descriptors but + is better than nothing. And if the test triggers the thread + descriptor is guaranteed to be invalid. */ +# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0) +# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0) +#endif + + +/* Cancellation test. */ +#define CANCELLATION_P(self) \ + do { \ + int cancelhandling = THREAD_GETMEM (self, cancelhandling); \ + if (CANCEL_ENABLED_AND_CANCELED (cancelhandling)) \ + { \ + THREAD_SETMEM (self, result, PTHREAD_CANCELED); \ + __do_cancel (); \ + } \ + } while (0) + + +extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +#if !defined SHARED && !defined IS_IN_libpthread + weak_function +#endif + ; +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +#ifndef SHARED + weak_function +#endif + ; +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +#if defined NOT_IN_libc && defined IS_IN_libpthread +hidden_proto (__pthread_unwind) +hidden_proto (__pthread_unwind_next) +hidden_proto (__pthread_register_cancel) +hidden_proto (__pthread_unregister_cancel) +# ifdef SHARED +extern void attribute_hidden pthread_cancel_init (void); +# endif +#endif + + +/* Called when a thread reacts on a cancellation request. */ +static inline void +__attribute ((noreturn, always_inline)) +__do_cancel (void) +{ + struct pthread *self = THREAD_SELF; + + /* Make sure we get no more cancellations. */ + THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT); + + __pthread_unwind ((__pthread_unwind_buf_t *) + THREAD_GETMEM (self, cleanup_jmp_buf)); +} + + +/* Set cancellation mode to asynchronous. */ +#define CANCEL_ASYNC() \ + __pthread_enable_asynccancel () +/* Reset to previous cancellation mode. */ +#define CANCEL_RESET(oldtype) \ + __pthread_disable_asynccancel (oldtype) + +#if !defined NOT_IN_libc +/* Same as CANCEL_ASYNC, but for use in libc.so. */ +# define LIBC_CANCEL_ASYNC() \ + __libc_enable_asynccancel () +/* Same as CANCEL_RESET, but for use in libc.so. */ +# define LIBC_CANCEL_RESET(oldtype) \ + __libc_disable_asynccancel (oldtype) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__libc_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__libc_disable_asynccancel") +#elif defined NOT_IN_libc && defined IS_IN_libpthread +# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC () +# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__pthread_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__pthread_disable_asynccancel") +#elif defined NOT_IN_libc && defined IS_IN_librt +# define LIBC_CANCEL_ASYNC() \ + __librt_enable_asynccancel () +# define LIBC_CANCEL_RESET(val) \ + __librt_disable_asynccancel (val) +# define LIBC_CANCEL_HANDLED() \ + __asm (".globl " __USER_LABEL_PREFIX__ "__librt_enable_asynccancel"); \ + __asm (".globl " __USER_LABEL_PREFIX__ "__librt_disable_asynccancel") +#else +# define LIBC_CANCEL_ASYNC() 0 /* Just a dummy value. */ +# define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it. */ +# define LIBC_CANCEL_HANDLED() /* Nothing. */ +#endif + +/* The signal used for asynchronous cancelation. */ +#define SIGCANCEL __SIGRTMIN + + +/* Signal needed for the kernel-supported POSIX timer implementation. + We can reuse the cancellation signal since we can distinguish + cancellation from timer expirations. */ +#define SIGTIMER SIGCANCEL + + +/* Signal used to implement the setuid et.al. functions. */ +#define SIGSETXID (__SIGRTMIN + 1) + +/* Used to communicate with signal handler. */ +extern struct xid_command *__xidcmd attribute_hidden; + + +/* Internal prototypes. */ + +/* Thread list handling. */ +extern struct pthread *__find_in_stack_list (struct pthread *pd) + attribute_hidden internal_function; + +/* Deallocate a thread's stack after optionally making sure the thread + descriptor is still valid. */ +extern void __free_tcb (struct pthread *pd) attribute_hidden internal_function; + +/* Free allocated stack. */ +extern void __deallocate_stack (struct pthread *pd) + attribute_hidden internal_function; + +/* Mark all the stacks except for the current one as available. This + function also re-initializes the lock for the stack cache. */ +extern void __reclaim_stacks (void) attribute_hidden; + +/* Make all threads's stacks executable. */ +extern int __make_stacks_executable (void **stack_endp) + internal_function attribute_hidden; + +/* longjmp handling. */ +extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe); +#if defined NOT_IN_libc && defined IS_IN_libpthread +hidden_proto (__pthread_cleanup_upto) +#endif + + +/* Functions with versioned interfaces. */ +extern int __pthread_create_2_1 (pthread_t *newthread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); +extern int __pthread_create_2_0 (pthread_t *newthread, + const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); +extern int __pthread_attr_init_2_1 (pthread_attr_t *attr); +extern int __pthread_attr_init_2_0 (pthread_attr_t *attr); + + +/* Event handlers for libthread_db interface. */ +extern void __nptl_create_event (void); +extern void __nptl_death_event (void); +hidden_proto (__nptl_create_event) +hidden_proto (__nptl_death_event) + +/* Register the generation counter in the libpthread with the libc. */ +#ifdef TLS_MULTIPLE_THREADS_IN_TCB +extern void __libc_pthread_init (unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions) + internal_function; +#else +extern int *__libc_pthread_init (unsigned long int *ptr, + void (*reclaim) (void), + const struct pthread_functions *functions) + internal_function; + +/* Variable set to a nonzero value if more than one thread runs or ran. */ +extern int __pthread_multiple_threads attribute_hidden; +/* Pointer to the corresponding variable in libc. */ +extern int *__libc_multiple_threads_ptr attribute_hidden; +#endif + +/* Find a thread given its TID. */ +extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden +#ifdef SHARED +; +#else +weak_function; +#define __find_thread_by_id(tid) \ + (__find_thread_by_id ? (__find_thread_by_id) (tid) : (struct pthread *) NULL) +#endif + +extern void __pthread_init_static_tls (struct link_map *) attribute_hidden; + + +/* Namespace save aliases. */ +extern int __pthread_getschedparam (pthread_t thread_id, int *policy, + struct sched_param *param); +extern int __pthread_setschedparam (pthread_t thread_id, int policy, + const struct sched_param *param); +extern int __pthread_setcancelstate (int state, int *oldstate); +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr); +extern int __pthread_mutex_init_internal (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr) + attribute_hidden; +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); +extern int __pthread_mutex_destroy_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex); +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_lock_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_cond_lock (pthread_mutex_t *__mutex) + attribute_hidden internal_function; +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); +extern int __pthread_mutex_unlock_internal (pthread_mutex_t *__mutex) + attribute_hidden; +extern int __pthread_mutex_unlock_usercnt (pthread_mutex_t *__mutex, + int __decr) + attribute_hidden internal_function; +extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr); +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr); +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind); +extern int __pthread_attr_destroy (pthread_attr_t *attr); +extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, + int *detachstate); +extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); +extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, + int *inherit); +extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); +extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); +extern int __pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); +extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, + int *policy); +extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); +extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); +extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); +extern int __pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr); +extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, + void *__stackaddr); +extern int __pthread_attr_getstacksize (__const pthread_attr_t *__restrict + __attr, + size_t *__restrict __stacksize); +extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, + size_t __stacksize); +extern int __pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, + void **__restrict __stackaddr, + size_t *__restrict __stacksize); +extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize); +extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + __const pthread_rwlockattr_t *__restrict + __attr); +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_rdlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_wrlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +extern int __pthread_rwlock_unlock_internal (pthread_rwlock_t *__rwlock); +extern int __pthread_cond_broadcast (pthread_cond_t *cond); +extern int __pthread_cond_destroy (pthread_cond_t *cond); +extern int __pthread_cond_init (pthread_cond_t *cond, + const pthread_condattr_t *cond_attr); +extern int __pthread_cond_signal (pthread_cond_t *cond); +extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); +extern int __pthread_cond_timedwait (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); +extern int __pthread_condattr_destroy (pthread_condattr_t *attr); +extern int __pthread_condattr_init (pthread_condattr_t *attr); +extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *)); +extern int __pthread_key_create_internal (pthread_key_t *key, + void (*destr) (void *)); +extern void *__pthread_getspecific (pthread_key_t key); +extern void *__pthread_getspecific_internal (pthread_key_t key); +extern int __pthread_setspecific (pthread_key_t key, const void *value); +extern int __pthread_setspecific_internal (pthread_key_t key, + const void *value); +extern int __pthread_once (pthread_once_t *once_control, + void (*init_routine) (void)); +extern int __pthread_once_internal (pthread_once_t *once_control, + void (*init_routine) (void)); +extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void), + void (*child) (void)); +extern pthread_t __pthread_self (void); +extern int __pthread_equal (pthread_t thread1, pthread_t thread2); +extern int __pthread_kill (pthread_t threadid, int signo); +extern void __pthread_exit (void *value); +extern int __pthread_setcanceltype (int type, int *oldtype); +extern int __pthread_enable_asynccancel (void) attribute_hidden; +extern void __pthread_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + +extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond, + const pthread_condattr_t *cond_attr); +extern int __pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond); +extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); +extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond, + pthread_mutex_t *mutex); + +extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize, + cpu_set_t *cpuset); + +/* The two functions are in libc.so and not exported. */ +extern int __libc_enable_asynccancel (void) attribute_hidden; +extern void __libc_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + + +/* The two functions are in librt.so and not exported. */ +extern int __librt_enable_asynccancel (void) attribute_hidden; +extern void __librt_disable_asynccancel (int oldtype) + internal_function attribute_hidden; + +#ifdef IS_IN_libpthread +/* Special versions which use non-exported functions. */ +extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg) + attribute_hidden; +# undef pthread_cleanup_push +# define pthread_cleanup_push(routine,arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + __pthread_cleanup_push (&_buffer, (routine), (arg)); + +extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute) attribute_hidden; +# undef pthread_cleanup_pop +# define pthread_cleanup_pop(execute) \ + __pthread_cleanup_pop (&_buffer, (execute)); } +#endif + +extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +/* Old cleanup interfaces, still used in libc.so. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute); +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +extern void __nptl_deallocate_tsd (void) attribute_hidden; + +extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden; + +#ifdef SHARED +# define PTHREAD_STATIC_FN_REQUIRE(name) +#else +# define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name); +#endif + +#endif /* pthreadP.h */ diff --git a/libpthread/nptl/pthread_atfork.c b/libpthread/nptl/pthread_atfork.c new file mode 100644 index 000000000..491362e19 --- /dev/null +++ b/libpthread/nptl/pthread_atfork.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <fork.h> + +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + + +/* Hide the symbol so that no definition but the one locally in the + executable or DSO is used. */ +int +__pthread_atfork (prepare, parent, child) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); +{ + return __register_atfork (prepare, parent, child, + &__dso_handle == NULL ? NULL : __dso_handle); +} +strong_alias(__pthread_atfork, pthread_atfork) diff --git a/libpthread/nptl/pthread_attr_destroy.c b/libpthread/nptl/pthread_attr_destroy.c new file mode 100644 index 000000000..cae7ca0b1 --- /dev/null +++ b/libpthread/nptl/pthread_attr_destroy.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" + +int +__pthread_attr_destroy (attr) + pthread_attr_t *attr; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* The affinity CPU set might be allocated dynamically. */ + free (iattr->cpuset); + + return 0; +} +strong_alias (__pthread_attr_destroy, pthread_attr_destroy) diff --git a/libpthread/nptl/pthread_attr_getdetachstate.c b/libpthread/nptl/pthread_attr_getdetachstate.c new file mode 100644 index 000000000..502cfa4f1 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getdetachstate.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getdetachstate (attr, detachstate) + const pthread_attr_t *attr; + int *detachstate; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + *detachstate = (iattr->flags & ATTR_FLAG_DETACHSTATE + ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); + + return 0; +} +strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate) diff --git a/libpthread/nptl/pthread_attr_getguardsize.c b/libpthread/nptl/pthread_attr_getguardsize.c new file mode 100644 index 000000000..e1d0ed624 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getguardsize.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_getguardsize (attr, guardsize) + const pthread_attr_t *attr; + size_t *guardsize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + *guardsize = iattr->guardsize; + + return 0; +} diff --git a/libpthread/nptl/pthread_attr_getinheritsched.c b/libpthread/nptl/pthread_attr_getinheritsched.c new file mode 100644 index 000000000..f47bf7147 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getinheritsched.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getinheritsched (attr, inherit) + const pthread_attr_t *attr; + int *inherit; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *inherit = (iattr->flags & ATTR_FLAG_NOTINHERITSCHED + ? PTHREAD_EXPLICIT_SCHED : PTHREAD_INHERIT_SCHED); + + return 0; +} +strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched) diff --git a/libpthread/nptl/pthread_attr_getschedparam.c b/libpthread/nptl/pthread_attr_getschedparam.c new file mode 100644 index 000000000..0ff0c0c4f --- /dev/null +++ b/libpthread/nptl/pthread_attr_getschedparam.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <string.h> +#include "pthreadP.h" + + +int +__pthread_attr_getschedparam (attr, param) + const pthread_attr_t *attr; + struct sched_param *param; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Copy the current values. */ + memcpy (param, &iattr->schedparam, sizeof (struct sched_param)); + + return 0; +} +strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam) diff --git a/libpthread/nptl/pthread_attr_getschedpolicy.c b/libpthread/nptl/pthread_attr_getschedpolicy.c new file mode 100644 index 000000000..8364f3be0 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getschedpolicy.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getschedpolicy (attr, policy) + const pthread_attr_t *attr; + int *policy; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *policy = iattr->schedpolicy; + + return 0; +} +strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy) diff --git a/libpthread/nptl/pthread_attr_getscope.c b/libpthread/nptl/pthread_attr_getscope.c new file mode 100644 index 000000000..b6aa5a213 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getscope.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getscope (attr, scope) + const pthread_attr_t *attr; + int *scope; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the current values. */ + *scope = (iattr->flags & ATTR_FLAG_SCOPEPROCESS + ? PTHREAD_SCOPE_PROCESS : PTHREAD_SCOPE_SYSTEM); + + return 0; +} +strong_alias (__pthread_attr_getscope, pthread_attr_getscope) diff --git a/libpthread/nptl/pthread_attr_getstack.c b/libpthread/nptl/pthread_attr_getstack.c new file mode 100644 index 000000000..1db135e5c --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstack.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstack (attr, stackaddr, stacksize) + const pthread_attr_t *attr; + void **stackaddr; + size_t *stacksize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Store the result. */ + *stackaddr = (char *) iattr->stackaddr - iattr->stacksize; + *stacksize = iattr->stacksize; + + return 0; +} +strong_alias (__pthread_attr_getstack, pthread_attr_getstack) diff --git a/libpthread/nptl/pthread_attr_getstackaddr.c b/libpthread/nptl/pthread_attr_getstackaddr.c new file mode 100644 index 000000000..7656600dd --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstackaddr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstackaddr (attr, stackaddr) + const pthread_attr_t *attr; + void **stackaddr; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Some code assumes this function to work even if no stack address + has been set. Let them figure it out for themselves what the + value means. Simply store the result. */ + *stackaddr = iattr->stackaddr; + + return 0; +} +strong_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) + +link_warning (pthread_attr_getstackaddr, + "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'") diff --git a/libpthread/nptl/pthread_attr_getstacksize.c b/libpthread/nptl/pthread_attr_getstacksize.c new file mode 100644 index 000000000..d4ff54f38 --- /dev/null +++ b/libpthread/nptl/pthread_attr_getstacksize.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +__pthread_attr_getstacksize (attr, stacksize) + const pthread_attr_t *attr; + size_t *stacksize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* If the user has not set a stack size we return what the system + will use as the default. */ + *stacksize = iattr->stacksize ?: __default_stacksize; + + return 0; +} +strong_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) diff --git a/libpthread/nptl/pthread_attr_init.c b/libpthread/nptl/pthread_attr_init.c new file mode 100644 index 000000000..f07dfc7d9 --- /dev/null +++ b/libpthread/nptl/pthread_attr_init.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" + + +struct pthread_attr *__attr_list; +lll_lock_t __attr_list_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_attr_init_2_1 (attr) + pthread_attr_t *attr; +{ + struct pthread_attr *iattr; + + /* Many elements are initialized to zero so let us do it all at + once. This also takes care of clearing the bytes which are not + internally used. */ + memset (attr, '\0', __SIZEOF_PTHREAD_ATTR_T); + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Default guard size specified by the standard. */ + iattr->guardsize = getpagesize (); + + return 0; +} +weak_alias(__pthread_attr_init_2_1, pthread_attr_init) diff --git a/libpthread/nptl/pthread_attr_setdetachstate.c b/libpthread/nptl/pthread_attr_setdetachstate.c new file mode 100644 index 000000000..a0e6c2017 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setdetachstate.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setdetachstate (attr, detachstate) + pthread_attr_t *attr; + int detachstate; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (detachstate != PTHREAD_CREATE_DETACHED + && __builtin_expect (detachstate != PTHREAD_CREATE_JOINABLE, 0)) + return EINVAL; + + /* Set the flag. It is nonzero if threads are created detached. */ + if (detachstate == PTHREAD_CREATE_DETACHED) + iattr->flags |= ATTR_FLAG_DETACHSTATE; + else + iattr->flags &= ~ATTR_FLAG_DETACHSTATE; + + return 0; +} +strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate) diff --git a/libpthread/nptl/pthread_attr_setguardsize.c b/libpthread/nptl/pthread_attr_setguardsize.c new file mode 100644 index 000000000..4c674f4df --- /dev/null +++ b/libpthread/nptl/pthread_attr_setguardsize.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include "pthreadP.h" + + +int +pthread_attr_setguardsize (attr, guardsize) + pthread_attr_t *attr; + size_t guardsize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Note that we don't round the value here. The standard requires + that subsequent pthread_attr_getguardsize calls return the value + set by the user. */ + iattr->guardsize = guardsize; + + return 0; +} diff --git a/libpthread/nptl/pthread_attr_setinheritsched.c b/libpthread/nptl/pthread_attr_setinheritsched.c new file mode 100644 index 000000000..8a77eeb65 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setinheritsched.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setinheritsched (attr, inherit) + pthread_attr_t *attr; + int inherit; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + + /* Store the new values. */ + if (inherit != PTHREAD_INHERIT_SCHED) + iattr->flags |= ATTR_FLAG_NOTINHERITSCHED; + else + iattr->flags &= ~ATTR_FLAG_NOTINHERITSCHED; + + return 0; +} +strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched) diff --git a/libpthread/nptl/pthread_attr_setschedparam.c b/libpthread/nptl/pthread_attr_setschedparam.c new file mode 100644 index 000000000..976ad1387 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setschedparam.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include "pthreadP.h" + + +int +__pthread_attr_setschedparam (attr, param) + pthread_attr_t *attr; + const struct sched_param *param; +{ + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + struct pthread_attr *iattr = (struct pthread_attr *) attr; + + /* Copy the new values. */ + memcpy (&iattr->schedparam, param, sizeof (struct sched_param)); + + /* Remember we set the value. */ + iattr->flags |= ATTR_FLAG_SCHED_SET; + + return 0; +} +strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam) diff --git a/libpthread/nptl/pthread_attr_setschedpolicy.c b/libpthread/nptl/pthread_attr_setschedpolicy.c new file mode 100644 index 000000000..b9710d57a --- /dev/null +++ b/libpthread/nptl/pthread_attr_setschedpolicy.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setschedpolicy (attr, policy) + pthread_attr_t *attr; + int policy; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + /* Store the new values. */ + iattr->schedpolicy = policy; + + /* Remember we set the value. */ + iattr->flags |= ATTR_FLAG_POLICY_SET; + + return 0; +} +strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy) diff --git a/libpthread/nptl/pthread_attr_setscope.c b/libpthread/nptl/pthread_attr_setscope.c new file mode 100644 index 000000000..8b3e1612e --- /dev/null +++ b/libpthread/nptl/pthread_attr_setscope.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setscope (attr, scope) + pthread_attr_t *attr; + int scope; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid values. */ + switch (scope) + { + case PTHREAD_SCOPE_SYSTEM: + iattr->flags &= ~ATTR_FLAG_SCOPEPROCESS; + break; + + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + + default: + return EINVAL; + } + + return 0; +} +strong_alias (__pthread_attr_setscope, pthread_attr_setscope) diff --git a/libpthread/nptl/pthread_attr_setstack.c b/libpthread/nptl/pthread_attr_setstack.c new file mode 100644 index 000000000..ba8fd0e59 --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstack.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstack (attr, stackaddr, stacksize) + pthread_attr_t *attr; + void *stackaddr; + size_t stacksize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid sizes. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + +#ifdef EXTRA_PARAM_CHECKS + EXTRA_PARAM_CHECKS; +#endif + + iattr->stacksize = stacksize; + iattr->stackaddr = (char *) stackaddr + stacksize; + iattr->flags |= ATTR_FLAG_STACKADDR; + + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +strong_alias(__pthread_attr_setstack, pthread_attr_setstack) +#else +weak_alias(__pthread_attr_setstack, pthread_attr_setstack) +#endif diff --git a/libpthread/nptl/pthread_attr_setstackaddr.c b/libpthread/nptl/pthread_attr_setstackaddr.c new file mode 100644 index 000000000..0d7a7c0eb --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstackaddr.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstackaddr (attr, stackaddr) + pthread_attr_t *attr; + void *stackaddr; +{ + struct pthread_attr *iattr; + +#ifdef EXTRA_PARAM_CHECKS + EXTRA_PARAM_CHECKS; +#endif + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + iattr->stackaddr = stackaddr; + iattr->flags |= ATTR_FLAG_STACKADDR; + + return 0; +} +strong_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) + +link_warning (pthread_attr_setstackaddr, + "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'") diff --git a/libpthread/nptl/pthread_attr_setstacksize.c b/libpthread/nptl/pthread_attr_setstacksize.c new file mode 100644 index 000000000..98339b12d --- /dev/null +++ b/libpthread/nptl/pthread_attr_setstacksize.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include "pthreadP.h" + + +int +__pthread_attr_setstacksize (attr, stacksize) + pthread_attr_t *attr; + size_t stacksize; +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + /* Catch invalid sizes. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + + iattr->stacksize = stacksize; + + return 0; +} + +#if PTHREAD_STACK_MIN == 16384 +strong_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize) +#else +weak_alias(__pthread_attr_setstacksize, pthread_attr_setstacksize) +#endif diff --git a/libpthread/nptl/pthread_barrier_destroy.c b/libpthread/nptl/pthread_barrier_destroy.c new file mode 100644 index 000000000..492b29485 --- /dev/null +++ b/libpthread/nptl/pthread_barrier_destroy.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_barrier_destroy (barrier) + pthread_barrier_t *barrier; +{ + struct pthread_barrier *ibarrier; + int result = EBUSY; + + ibarrier = (struct pthread_barrier *) barrier; + + lll_lock (ibarrier->lock); + + if (__builtin_expect (ibarrier->left == ibarrier->init_count, 1)) + /* The barrier is not used anymore. */ + result = 0; + else + /* Still used, return with an error. */ + lll_unlock (ibarrier->lock); + + return result; +} diff --git a/libpthread/nptl/pthread_barrier_init.c b/libpthread/nptl/pthread_barrier_init.c new file mode 100644 index 000000000..19e82fa38 --- /dev/null +++ b/libpthread/nptl/pthread_barrier_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_barrier_init (barrier, attr, count) + pthread_barrier_t *barrier; + const pthread_barrierattr_t *attr; + unsigned int count; +{ + struct pthread_barrier *ibarrier; + + if (__builtin_expect (count == 0, 0)) + return EINVAL; + + if (attr != NULL) + { + struct pthread_barrierattr *iattr; + + iattr = (struct pthread_barrierattr *) attr; + + if (iattr->pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0)) + /* Invalid attribute. */ + return EINVAL; + } + + ibarrier = (struct pthread_barrier *) barrier; + + /* Initialize the individual fields. */ + ibarrier->lock = LLL_LOCK_INITIALIZER; + ibarrier->left = count; + ibarrier->init_count = count; + ibarrier->curr_event = 0; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_destroy.c b/libpthread/nptl/pthread_barrierattr_destroy.c new file mode 100644 index 000000000..f947daf38 --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_destroy (attr) + pthread_barrierattr_t *attr; +{ + /* Nothing to do. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_getpshared.c b/libpthread/nptl/pthread_barrierattr_getpshared.c new file mode 100644 index 000000000..246c8882e --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_getpshared (attr, pshared) + const pthread_barrierattr_t *attr; + int *pshared; +{ + *pshared = ((const struct pthread_barrierattr *) attr)->pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_init.c b/libpthread/nptl/pthread_barrierattr_init.c new file mode 100644 index 000000000..a0be9528b --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_init.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_barrierattr_init (attr) + pthread_barrierattr_t *attr; +{ + ((struct pthread_barrierattr *) attr)->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} diff --git a/libpthread/nptl/pthread_barrierattr_setpshared.c b/libpthread/nptl/pthread_barrierattr_setpshared.c new file mode 100644 index 000000000..b69f23ef1 --- /dev/null +++ b/libpthread/nptl/pthread_barrierattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_barrierattr_setpshared (attr, pshared) + pthread_barrierattr_t *attr; + int pshared; +{ + struct pthread_barrierattr *iattr; + + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + iattr = (struct pthread_barrierattr *) attr; + + iattr->pshared = pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_cancel.c b/libpthread/nptl/pthread_cancel.c new file mode 100644 index 000000000..0ea990693 --- /dev/null +++ b/libpthread/nptl/pthread_cancel.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include "pthreadP.h" +#include "atomic.h" +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +pthread_cancel (th) + pthread_t th; +{ + volatile struct pthread *pd = (volatile struct pthread *) th; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + +#ifdef SHARED + pthread_cancel_init (); +#endif + int result = 0; + int oldval; + int newval; + do + { + oldval = pd->cancelhandling; + newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the bug has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* If the cancellation is handled asynchronously just send a + signal. We avoid this if possible since it's more + expensive. */ + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + /* Mark the cancellation as "in progress". */ + atomic_bit_set (&pd->cancelhandling, CANCELING_BIT); + + /* The cancellation handler will take care of marking the + thread as canceled. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be + changed (in fork). But this must not affect this code + here. Since this function would have to be called while + the thread is executing fork, it would have to happen in + a signal handler. But this is no allowed, pthread_cancel + is not guaranteed to be async-safe. */ + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), pd->tid, + SIGCANCEL); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), pd->tid, + SIGCANCEL); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL); +#endif + + if (INTERNAL_SYSCALL_ERROR_P (val, err)) + result = INTERNAL_SYSCALL_ERRNO (val, err); + + break; + } + } + /* Mark the thread as canceled. This has to be done + atomically since other bits could be modified as well. */ + while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval, + oldval)); + + return result; +} + +PTHREAD_STATIC_FN_REQUIRE (pthread_create) diff --git a/libpthread/nptl/pthread_clock_gettime.c b/libpthread/nptl/pthread_clock_gettime.c new file mode 100644 index 000000000..a71174c9c --- /dev/null +++ b/libpthread/nptl/pthread_clock_gettime.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2001, 2002, 2003 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <libc-internal.h> +#include "pthreadP.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq, + struct timespec *tp) +{ + hp_timing_t tsc; + + /* Get the current counter. */ + HP_TIMING_NOW (tsc); + + /* This is the ID of the thread we are looking for. */ + pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + + /* Compute the offset since the start time of the process. */ + if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) + /* Our own clock. */ + tsc -= THREAD_GETMEM (THREAD_SELF, cpuclock_offset); + else + { + /* This is more complicated. We have to locate the thread based + on the ID. This means walking the list of existing + threads. */ + struct pthread *thread = __find_thread_by_id (tid); + if (thread == NULL) + { + __set_errno (EINVAL); + return -1; + } + + /* There is a race here. The thread might terminate and the stack + become unusable. But this is the user's problem. */ + tsc -= thread->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) * 1000000000ull) / freq; + + return 0; +} +#endif diff --git a/libpthread/nptl/pthread_clock_settime.c b/libpthread/nptl/pthread_clock_settime.c new file mode 100644 index 000000000..61002a8f7 --- /dev/null +++ b/libpthread/nptl/pthread_clock_settime.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2001, 2002, 2003 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <libc-internal.h> +#include "pthreadP.h" + + +#if HP_TIMING_AVAIL +int +__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) +{ + /* This is the ID of the thread we are looking for. */ + pid_t tid = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE; + + /* Compute the offset since the start time of the process. */ + if (tid == 0 || tid == THREAD_GETMEM (THREAD_SELF, tid)) + /* Our own clock. */ + THREAD_SETMEM (THREAD_SELF, cpuclock_offset, offset); + else + { + /* This is more complicated. We have to locate the thread based + on the ID. This means walking the list of existing + threads. */ + struct pthread *thread = __find_thread_by_id (tid); + if (thread == NULL) + { + __set_errno (EINVAL); + return -1; + } + + /* There is a race here. The thread might terminate and the stack + become unusable. But this is the user's problem. */ + thread->cpuclock_offset = offset; + } + + return 0; +} +#endif diff --git a/libpthread/nptl/pthread_cond_destroy.c b/libpthread/nptl/pthread_cond_destroy.c new file mode 100644 index 000000000..b7842d258 --- /dev/null +++ b/libpthread/nptl/pthread_cond_destroy.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_cond_destroy (cond) + pthread_cond_t *cond; +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + if (cond->__data.__total_seq > cond->__data.__wakeup_seq) + { + /* If there are still some waiters which have not been + woken up, this is an application bug. */ + lll_mutex_unlock (cond->__data.__lock); + return EBUSY; + } + + /* Tell pthread_cond_*wait that this condvar is being destroyed. */ + cond->__data.__total_seq = -1ULL; + + /* If there are waiters which have been already signalled or + broadcasted, but still are using the pthread_cond_t structure, + pthread_cond_destroy needs to wait for them. */ + unsigned int nwaiters = cond->__data.__nwaiters; + while (nwaiters >= (1 << COND_CLOCK_BITS)) + { + lll_mutex_unlock (cond->__data.__lock); + + lll_futex_wait (&cond->__data.__nwaiters, nwaiters); + + lll_mutex_lock (cond->__data.__lock); + + nwaiters = cond->__data.__nwaiters; + } + + return 0; +} +weak_alias(__pthread_cond_destroy, pthread_cond_destroy) diff --git a/libpthread/nptl/pthread_cond_init.c b/libpthread/nptl/pthread_cond_init.c new file mode 100644 index 000000000..5c3fd6853 --- /dev/null +++ b/libpthread/nptl/pthread_cond_init.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_cond_init (cond, cond_attr) + pthread_cond_t *cond; + const pthread_condattr_t *cond_attr; +{ + struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr; + + cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER; + cond->__data.__futex = 0; + cond->__data.__nwaiters = (icond_attr != NULL + && ((icond_attr->value & (COND_CLOCK_BITS << 1)) + >> 1)); + cond->__data.__total_seq = 0; + cond->__data.__wakeup_seq = 0; + cond->__data.__woken_seq = 0; + cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0 + ? NULL : (void *) ~0l); + cond->__data.__broadcast_seq = 0; + + return 0; +} +weak_alias(__pthread_cond_init, pthread_cond_init) diff --git a/libpthread/nptl/pthread_condattr_destroy.c b/libpthread/nptl/pthread_condattr_destroy.c new file mode 100644 index 000000000..e6d069e40 --- /dev/null +++ b/libpthread/nptl/pthread_condattr_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_condattr_destroy (attr) + pthread_condattr_t *attr; +{ + /* Nothing to be done. */ + return 0; +} +strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy) diff --git a/libpthread/nptl/pthread_condattr_getclock.c b/libpthread/nptl/pthread_condattr_getclock.c new file mode 100644 index 000000000..84de918a5 --- /dev/null +++ b/libpthread/nptl/pthread_condattr_getclock.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_condattr_getclock (attr, clock_id) + const pthread_condattr_t *attr; + clockid_t *clock_id; +{ + *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1) + & ((1 << COND_CLOCK_BITS) - 1)); + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_getpshared.c b/libpthread/nptl/pthread_condattr_getpshared.c new file mode 100644 index 000000000..b44eac94e --- /dev/null +++ b/libpthread/nptl/pthread_condattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_condattr_getpshared (attr, pshared) + const pthread_condattr_t *attr; + int *pshared; +{ + *pshared = ((const struct pthread_condattr *) attr)->value & 1; + + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_init.c b/libpthread/nptl/pthread_condattr_init.c new file mode 100644 index 000000000..738deb489 --- /dev/null +++ b/libpthread/nptl/pthread_condattr_init.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include "pthreadP.h" + + +int +__pthread_condattr_init (attr) + pthread_condattr_t *attr; +{ + memset (attr, '\0', sizeof (*attr)); + + return 0; +} +strong_alias (__pthread_condattr_init, pthread_condattr_init) diff --git a/libpthread/nptl/pthread_condattr_setclock.c b/libpthread/nptl/pthread_condattr_setclock.c new file mode 100644 index 000000000..6dc25636a --- /dev/null +++ b/libpthread/nptl/pthread_condattr_setclock.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <time.h> +#include <sysdep.h> +#include "pthreadP.h" +#include <bits/kernel-features.h> + + +int +pthread_condattr_setclock (attr, clock_id) + pthread_condattr_t *attr; + clockid_t clock_id; +{ + /* Only a few clocks are allowed. CLOCK_REALTIME is always allowed. + CLOCK_MONOTONIC only if the kernel has the necessary support. */ + if (clock_id == CLOCK_MONOTONIC) + { +#ifndef __ASSUME_POSIX_TIMERS +# ifdef __NR_clock_getres + /* Check whether the clock is available. */ + static int avail; + + if (avail == 0) + { + struct timespec ts; + + INTERNAL_SYSCALL_DECL (err); + int val; + val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); + avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1; + } + + if (avail < 0) +# endif + /* Not available. */ + return EINVAL; +#endif + } + else if (clock_id != CLOCK_REALTIME) + /* If more clocks are allowed some day the storing of the clock ID + in the pthread_cond_t structure needs to be adjusted. */ + return EINVAL; + + /* Make sure the value fits in the bits we reserved. */ + assert (clock_id < (1 << COND_CLOCK_BITS)); + + int *valuep = &((struct pthread_condattr *) attr)->value; + + *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1); + + return 0; +} diff --git a/libpthread/nptl/pthread_condattr_setpshared.c b/libpthread/nptl/pthread_condattr_setpshared.c new file mode 100644 index 000000000..f00858780 --- /dev/null +++ b/libpthread/nptl/pthread_condattr_setpshared.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + +int +pthread_condattr_setpshared (attr, pshared) + pthread_condattr_t *attr; + int pshared; +{ + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + int *valuep = &((struct pthread_condattr *) attr)->value; + + *valuep = (*valuep & ~1) | (pshared != PTHREAD_PROCESS_PRIVATE); + + return 0; +} diff --git a/libpthread/nptl/pthread_create.c b/libpthread/nptl/pthread_create.c new file mode 100644 index 000000000..81da5b93a --- /dev/null +++ b/libpthread/nptl/pthread_create.c @@ -0,0 +1,484 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include "pthreadP.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <libc-internal.h> +#include <resolv.h> + + +/* Local function to start thread and handle cleanup. */ +static int start_thread (void *arg); + + +/* Nozero if debugging mode is enabled. */ +int __pthread_debug; + +/* Globally enabled events. */ +static td_thr_events_t __nptl_threads_events; + +/* Pointer to descriptor with the last event. */ +static struct pthread *__nptl_last_event; + +/* Number of threads running. */ +unsigned int __nptl_nthreads = 1; + + +/* Code to allocate and deallocate a stack. */ +#include "allocatestack.c" + +/* Code to create the thread. */ +#include "createthread.c" + + +struct pthread * +internal_function +__find_in_stack_list (pd) + struct pthread *pd; +{ + list_t *entry; + struct pthread *result = NULL; + + lll_lock (stack_cache_lock); + + list_for_each (entry, &stack_used) + { + struct pthread *curp; + + curp = list_entry (entry, struct pthread, list); + if (curp == pd) + { + result = curp; + break; + } + } + + if (result == NULL) + list_for_each (entry, &__stack_user) + { + struct pthread *curp; + + curp = list_entry (entry, struct pthread, list); + if (curp == pd) + { + result = curp; + break; + } + } + + lll_unlock (stack_cache_lock); + + return result; +} + + +/* Deallocate POSIX thread-local-storage. */ +void +attribute_hidden +__nptl_deallocate_tsd (void) +{ + struct pthread *self = THREAD_SELF; + + /* Maybe no data was ever allocated. This happens often so we have + a flag for this. */ + if (THREAD_GETMEM (self, specific_used)) + { + size_t round; + size_t cnt; + + round = 0; + do + { + size_t idx; + + /* So far no new nonzero data entry. */ + THREAD_SETMEM (self, specific_used, false); + + for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt) + { + struct pthread_key_data *level2; + + level2 = THREAD_GETMEM_NC (self, specific, cnt); + + if (level2 != NULL) + { + size_t inner; + + for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE; + ++inner, ++idx) + { + void *data = level2[inner].data; + + if (data != NULL) + { + /* Always clear the data. */ + level2[inner].data = NULL; + + /* Make sure the data corresponds to a valid + key. This test fails if the key was + deallocated and also if it was + re-allocated. It is the user's + responsibility to free the memory in this + case. */ + if (level2[inner].seq + == __pthread_keys[idx].seq + /* It is not necessary to register a destructor + function. */ + && __pthread_keys[idx].destr != NULL) + /* Call the user-provided destructor. */ + __pthread_keys[idx].destr (data); + } + } + } + else + idx += PTHREAD_KEY_1STLEVEL_SIZE; + } + + if (THREAD_GETMEM (self, specific_used) == 0) + /* No data has been modified. */ + goto just_free; + } + /* We only repeat the process a fixed number of times. */ + while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0)); + + /* Just clear the memory of the first block for reuse. */ + memset (&THREAD_SELF->specific_1stblock, '\0', + sizeof (self->specific_1stblock)); + + just_free: + /* Free the memory for the other blocks. */ + for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt) + { + struct pthread_key_data *level2; + + level2 = THREAD_GETMEM_NC (self, specific, cnt); + if (level2 != NULL) + { + /* The first block is allocated as part of the thread + descriptor. */ + free (level2); + THREAD_SETMEM_NC (self, specific, cnt, NULL); + } + } + + THREAD_SETMEM (self, specific_used, false); + } +} + + +/* Deallocate a thread's stack after optionally making sure the thread + descriptor is still valid. */ +void +internal_function +__free_tcb (struct pthread *pd) +{ + /* The thread is exiting now. */ + if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling, + TERMINATED_BIT) == 0, 1)) + { + /* Remove the descriptor from the list. */ + if (DEBUGGING_P && __find_in_stack_list (pd) == NULL) + /* Something is really wrong. The descriptor for a still + running thread is gone. */ + abort (); + + /* Queue the stack memory block for reuse and exit the process. The + kernel will signal via writing to the address returned by + QUEUE-STACK when the stack is available. */ + __deallocate_stack (pd); + } +} + + +static int +start_thread (void *arg) +{ + struct pthread *pd = (struct pthread *) arg; + +#if HP_TIMING_AVAIL + /* Remember the time when the thread was started. */ + hp_timing_t now; + HP_TIMING_NOW (now); + THREAD_SETMEM (pd, cpuclock_offset, now); +#endif + + /* Initialize resolver state pointer. */ + __resp = &pd->res; + + /* This is where the try/finally block should be created. For + compilers without that support we do use setjmp. */ + struct pthread_unwind_buf unwind_buf; + + /* No previous handlers. */ + unwind_buf.priv.data.prev = NULL; + unwind_buf.priv.data.cleanup = NULL; + + int not_first_call; + not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + if (__builtin_expect (! not_first_call, 1)) + { + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + + if (__builtin_expect (pd->stopped_start, 0)) + { + int oldtype = CANCEL_ASYNC (); + + /* Get the lock the parent locked to force synchronization. */ + lll_lock (pd->lock); + /* And give it up right away. */ + lll_unlock (pd->lock); + + CANCEL_RESET (oldtype); + } + + /* Run the code the user provided. */ +#ifdef CALL_THREAD_FCT + THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd)); +#else + THREAD_SETMEM (pd, result, pd->start_routine (pd->arg)); +#endif + } + + /* Run the destructor for the thread-local data. */ + __nptl_deallocate_tsd (); + + /* If this is the last thread we terminate the process now. We + do not notify the debugger, it might just irritate it if there + is no thread left. */ + if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0)) + /* This was the last thread. */ + exit (0); + + /* Report the death of the thread if this is wanted. */ + if (__builtin_expect (pd->report_events, 0)) + { + /* See whether TD_DEATH is in any of the mask. */ + const int idx = __td_eventword (TD_DEATH); + const uint32_t mask = __td_eventmask (TD_DEATH); + + if ((mask & (__nptl_threads_events.event_bits[idx] + | pd->eventbuf.eventmask.event_bits[idx])) != 0) + { + /* Yep, we have to signal the death. Add the descriptor to + the list but only if it is not already on it. */ + if (pd->nextevent == NULL) + { + pd->eventbuf.eventnum = TD_DEATH; + pd->eventbuf.eventdata = pd; + + do + pd->nextevent = __nptl_last_event; + while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, + pd, pd->nextevent)); + } + + /* Now call the function to signal the event. */ + __nptl_death_event (); + } + } + + /* The thread is exiting now. Don't set this bit until after we've hit + the event-reporting breakpoint, so that td_thr_get_info on us while at + the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */ + atomic_bit_set (&pd->cancelhandling, EXITING_BIT); + + /* If the thread is detached free the TCB. */ + if (IS_DETACHED (pd)) + /* Free the TCB. */ + __free_tcb (pd); + + /* We cannot call '_exit' here. '_exit' will terminate the process. + + The 'exit' implementation in the kernel will signal when the + process is really dead since 'clone' got passed the CLONE_CLEARTID + flag. The 'tid' field in the TCB will be set to zero. + + The exit code is zero since in case all threads exit by calling + 'pthread_exit' the exit status must be 0 (zero). */ + __exit_thread_inline (0); + + /* NOTREACHED */ + return 0; +} + + +/* Default thread attributes for the case when the user does not + provide any. */ +static const struct pthread_attr default_attr = + { + /* Just some value > 0 which gets rounded to the nearest page size. */ + .guardsize = 1, + }; + + +int +__pthread_create_2_1 (newthread, attr, start_routine, arg) + pthread_t *newthread; + const pthread_attr_t *attr; + void *(*start_routine) (void *); + void *arg; +{ + STACK_VARIABLES; + + const struct pthread_attr *iattr = (struct pthread_attr *) attr; + if (iattr == NULL) + /* Is this the best idea? On NUMA machines this could mean + accessing far-away memory. */ + iattr = &default_attr; + + struct pthread *pd = 0; + int err = ALLOCATE_STACK (iattr, &pd); + if (__builtin_expect (err != 0, 0)) + /* Something went wrong. Maybe a parameter of the attributes is + invalid or we could not allocate memory. */ + return err; + + + /* Initialize the TCB. All initializations with zero should be + performed in 'get_cached_stack'. This way we avoid doing this if + the stack freshly allocated with 'mmap'. */ + +#ifdef TLS_TCB_AT_TP + /* Reference to the TCB itself. */ + pd->header.self = pd; + + /* Self-reference for TLS. */ + pd->header.tcb = pd; +#endif + + /* Store the address of the start routine and the parameter. Since + we do not start the function directly the stillborn thread will + get the information from its thread descriptor. */ + pd->start_routine = start_routine; + pd->arg = arg; + + /* Copy the thread attribute flags. */ + struct pthread *self = THREAD_SELF; + pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) + | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))); + + /* Initialize the field for the ID of the thread which is waiting + for us. This is a self-reference in case the thread is created + detached. */ + pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL; + + /* The debug events are inherited from the parent. */ + pd->eventbuf = self->eventbuf; + + + /* Copy the parent's scheduling parameters. The flags will say what + is valid and what is not. */ + pd->schedpolicy = self->schedpolicy; + pd->schedparam = self->schedparam; + + /* Copy the stack guard canary. */ +#ifdef THREAD_COPY_STACK_GUARD + THREAD_COPY_STACK_GUARD (pd); +#endif + + /* Determine scheduling parameters for the thread. */ + if (attr != NULL + && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0) + && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0) + { + INTERNAL_SYSCALL_DECL (scerr); + + /* Use the scheduling parameters the user provided. */ + if (iattr->flags & ATTR_FLAG_POLICY_SET) + pd->schedpolicy = iattr->schedpolicy; + else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0) + { + pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, scerr, 1, 0); + pd->flags |= ATTR_FLAG_POLICY_SET; + } + + if (iattr->flags & ATTR_FLAG_SCHED_SET) + memcpy (&pd->schedparam, &iattr->schedparam, + sizeof (struct sched_param)); + else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0) + { + INTERNAL_SYSCALL (sched_getparam, scerr, 2, 0, &pd->schedparam); + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + /* Check for valid priorities. */ + int minprio = INTERNAL_SYSCALL (sched_get_priority_min, scerr, 1, + iattr->schedpolicy); + int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, scerr, 1, + iattr->schedpolicy); + if (pd->schedparam.sched_priority < minprio + || pd->schedparam.sched_priority > maxprio) + { + err = EINVAL; + goto errout; + } + } + + /* Pass the descriptor to the caller. */ + *newthread = (pthread_t) pd; + + /* Remember whether the thread is detached or not. In case of an + error we have to free the stacks of non-detached stillborn + threads. */ + bool is_detached = IS_DETACHED (pd); + + /* Start the thread. */ + err = create_thread (pd, iattr, STACK_VARIABLES_ARGS); + if (err != 0) + { + /* Something went wrong. Free the resources. */ + if (!is_detached) + { + errout: + __deallocate_stack (pd); + } + return err; + } + + return 0; +} +weak_alias(__pthread_create_2_1, pthread_create) + +/* Information for libthread_db. */ + +#include "../nptl_db/db_info.c" + +/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread + functions to be present as well. */ +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock) +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock) + +PTHREAD_STATIC_FN_REQUIRE (pthread_once) +PTHREAD_STATIC_FN_REQUIRE (pthread_cancel) + +PTHREAD_STATIC_FN_REQUIRE (pthread_key_create) +PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific) +PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific) + +/* UCLIBC_MUTEX_xxx macros expects to have these as well */ +PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_init) +PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_push_defer) +PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_pop_restore) diff --git a/libpthread/nptl/pthread_detach.c b/libpthread/nptl/pthread_detach.c new file mode 100644 index 000000000..1f0c2fe7c --- /dev/null +++ b/libpthread/nptl/pthread_detach.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +pthread_detach (th) + pthread_t th; +{ + struct pthread *pd = (struct pthread *) th; + + /* Make sure the descriptor is valid. */ + if (INVALID_NOT_TERMINATED_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + int result = 0; + + /* Mark the thread as detached. */ + if (atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, NULL)) + { + /* There are two possibilities here. First, the thread might + already be detached. In this case we return EINVAL. + Otherwise there might already be a waiter. The standard does + not mention what happens in this case. */ + if (IS_DETACHED (pd)) + result = EINVAL; + } + else + /* Check whether the thread terminated meanwhile. In this case we + will just free the TCB. */ + if ((pd->cancelhandling & EXITING_BITMASK) != 0) + /* Note that the code in __free_tcb makes sure each thread + control block is freed only once. */ + __free_tcb (pd); + + return result; +} diff --git a/libpthread/nptl/pthread_equal.c b/libpthread/nptl/pthread_equal.c new file mode 100644 index 000000000..c9986096f --- /dev/null +++ b/libpthread/nptl/pthread_equal.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_equal (thread1, thread2) + pthread_t thread1; + pthread_t thread2; +{ + return thread1 == thread2; +} +strong_alias (__pthread_equal, pthread_equal) diff --git a/libpthread/nptl/pthread_exit.c b/libpthread/nptl/pthread_exit.c new file mode 100644 index 000000000..85d8fd456 --- /dev/null +++ b/libpthread/nptl/pthread_exit.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +__pthread_exit (value) + void *value; +{ + THREAD_SETMEM (THREAD_SELF, result, value); + + __do_cancel (); +} +strong_alias (__pthread_exit, pthread_exit) diff --git a/libpthread/nptl/pthread_getattr_np.c b/libpthread/nptl/pthread_getattr_np.c new file mode 100644 index 000000000..8819731ab --- /dev/null +++ b/libpthread/nptl/pthread_getattr_np.c @@ -0,0 +1,171 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <sys/resource.h> +#include "pthreadP.h" +#include <lowlevellock.h> +#include <ldsodefs.h> + + +int +pthread_getattr_np (thread_id, attr) + pthread_t thread_id; + pthread_attr_t *attr; +{ + struct pthread *thread = (struct pthread *) thread_id; + struct pthread_attr *iattr = (struct pthread_attr *) attr; + int ret = 0; + + lll_lock (thread->lock); + + /* The thread library is responsible for keeping the values in the + thread desriptor up-to-date in case the user changes them. */ + memcpy (&iattr->schedparam, &thread->schedparam, + sizeof (struct sched_param)); + iattr->schedpolicy = thread->schedpolicy; + + /* Clear the flags work. */ + iattr->flags = thread->flags; + + /* The thread might be detached by now. */ + if (IS_DETACHED (thread)) + iattr->flags |= ATTR_FLAG_DETACHSTATE; + + /* This is the guardsize after adjusting it. */ + iattr->guardsize = thread->reported_guardsize; + + /* The sizes are subject to alignment. */ + if (__builtin_expect (thread->stackblock != NULL, 1)) + { + iattr->stacksize = thread->stackblock_size; + iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize; + } + else + { + /* No stack information available. This must be for the initial + thread. Get the info in some magical way. */ + assert (abs (thread->pid) == thread->tid); + + /* Stack size limit. */ + struct rlimit rl; + + /* The safest way to get the top of the stack is to read + /proc/self/maps and locate the line into which + __libc_stack_end falls. */ + FILE *fp = fopen ("/proc/self/maps", "rc"); + if (fp == NULL) + ret = errno; + /* We need the limit of the stack in any case. */ + else if (getrlimit (RLIMIT_STACK, &rl) != 0) + ret = errno; + else + { + /* We need no locking. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + /* Until we found an entry (which should always be the case) + mark the result as a failure. */ + ret = ENOENT; + + char *line = NULL; + size_t linelen = 0; + uintptr_t last_to = 0; + + while (! feof_unlocked (fp)) + { + if (getdelim (&line, &linelen, '\n', fp) <= 0) + break; + + uintptr_t from; + uintptr_t to; + if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2) + continue; + if (from <= (uintptr_t) __libc_stack_end + && (uintptr_t) __libc_stack_end < to) + { + /* Found the entry. Now we have the info we need. */ + iattr->stacksize = rl.rlim_cur; + iattr->stackaddr = (void *) to; + + /* The limit might be too high. */ + if ((size_t) iattr->stacksize + > (size_t) iattr->stackaddr - last_to) + iattr->stacksize = (size_t) iattr->stackaddr - last_to; + + /* We succeed and no need to look further. */ + ret = 0; + break; + } + last_to = to; + } + + fclose (fp); + free (line); + } + } + + iattr->flags |= ATTR_FLAG_STACKADDR; + + if (ret == 0) + { + size_t size = 16; + cpu_set_t *cpuset = NULL; + + do + { + size <<= 1; + + void *newp = realloc (cpuset, size); + if (newp == NULL) + { + ret = ENOMEM; + break; + } + cpuset = (cpu_set_t *) newp; + + ret = __pthread_getaffinity_np (thread_id, size, cpuset); + } + /* Pick some ridiculous upper limit. Is 8 million CPUs enough? */ + while (ret == EINVAL && size < 1024 * 1024); + + if (ret == 0) + { + iattr->cpuset = cpuset; + iattr->cpusetsize = size; + } + else + { + free (cpuset); + if (ret == ENOSYS) + /* There is no such functionality. */ + ret = 0; + } + } + + lll_unlock (thread->lock); + + return ret; +} diff --git a/libpthread/nptl/pthread_getconcurrency.c b/libpthread/nptl/pthread_getconcurrency.c new file mode 100644 index 000000000..52c0c7cbe --- /dev/null +++ b/libpthread/nptl/pthread_getconcurrency.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_getconcurrency (void) +{ + return __concurrency_level; +} diff --git a/libpthread/nptl/pthread_getschedparam.c b/libpthread/nptl/pthread_getschedparam.c new file mode 100644 index 000000000..10ad27142 --- /dev/null +++ b/libpthread/nptl/pthread_getschedparam.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <string.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_getschedparam (threadid, policy, param) + pthread_t threadid; + int *policy; + struct sched_param *param; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + int result = 0; + + lll_lock (pd->lock); + + /* The library is responsible for maintaining the values at all + times. If the user uses a interface other than + pthread_setschedparam to modify the scheduler setting it is not + the library's problem. In case the descriptor's values have + not yet been retrieved do it now. */ + if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0) + { + if (sched_getparam (pd->tid, &pd->schedparam) != 0) + result = 1; + else + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0) + { + pd->schedpolicy = sched_getscheduler (pd->tid); + if (pd->schedpolicy == -1) + result = 1; + else + pd->flags |= ATTR_FLAG_POLICY_SET; + } + + if (result == 0) + { + *policy = pd->schedpolicy; + memcpy (param, &pd->schedparam, sizeof (struct sched_param)); + } + + lll_unlock (pd->lock); + + return result; +} +strong_alias (__pthread_getschedparam, pthread_getschedparam) diff --git a/libpthread/nptl/pthread_getspecific.c b/libpthread/nptl/pthread_getspecific.c new file mode 100644 index 000000000..afb4d26ff --- /dev/null +++ b/libpthread/nptl/pthread_getspecific.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void * +__pthread_getspecific (key) + pthread_key_t key; +{ + struct pthread_key_data *data; + + /* Special case access to the first 2nd-level block. This is the + usual case. */ + if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1)) + data = &THREAD_SELF->specific_1stblock[key]; + else + { + /* Verify the key is sane. */ + if (key >= PTHREAD_KEYS_MAX) + /* Not valid. */ + return NULL; + + unsigned int idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + unsigned int idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + + /* If the sequence number doesn't match or the key cannot be defined + for this thread since the second level array is not allocated + return NULL, too. */ + struct pthread_key_data *level2 = THREAD_GETMEM_NC (THREAD_SELF, + specific, idx1st); + if (level2 == NULL) + /* Not allocated, therefore no data. */ + return NULL; + + /* There is data. */ + data = &level2[idx2nd]; + } + + void *result = data->data; + if (result != NULL) + { + uintptr_t seq = data->seq; + + if (__builtin_expect (seq != __pthread_keys[key].seq, 0)) + result = data->data = NULL; + } + + return result; +} +strong_alias (__pthread_getspecific, pthread_getspecific) +strong_alias (__pthread_getspecific, __pthread_getspecific_internal) diff --git a/libpthread/nptl/pthread_join.c b/libpthread/nptl/pthread_join.c new file mode 100644 index 000000000..f94128dd9 --- /dev/null +++ b/libpthread/nptl/pthread_join.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> + +#include "atomic.h" +#include "pthreadP.h" + + +static void +cleanup (void *arg) +{ + *(void **) arg = NULL; +} + + +int +pthread_join (threadid, thread_return) + pthread_t threadid; + void **thread_return; +{ + struct pthread *self; + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_NOT_TERMINATED_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Is the thread joinable?. */ + if (IS_DETACHED (pd)) + /* We cannot wait for the thread. */ + return EINVAL; + + self = THREAD_SELF; + if (pd == self + || (self->joinid == pd + && (pd->cancelhandling + & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK + | TERMINATED_BITMASK)) == 0)) + /* This is a deadlock situation. The threads are waiting for each + other to finish. Note that this is a "may" error. To be 100% + sure we catch this error we would have to lock the data + structures but it is not necessary. In the unlikely case that + two threads are really caught in this situation they will + deadlock. It is the programmer's problem to figure this + out. */ + return EDEADLK; + + /* Wait for the thread to finish. If it is already locked something + is wrong. There can only be one waiter. */ + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, + self, + NULL), 0)) + /* There is already somebody waiting for the thread. */ + return EINVAL; + + + /* During the wait we change to asynchronous cancellation. If we + are cancelled the thread we are waiting for must be marked as + un-wait-ed for again. */ + pthread_cleanup_push (cleanup, &pd->joinid); + + /* Switch to asynchronous cancellation. */ + int oldtype = CANCEL_ASYNC (); + + + /* Wait for the child. */ + lll_wait_tid (pd->tid); + + + /* Restore cancellation mode. */ + CANCEL_RESET (oldtype); + + /* Remove the handler. */ + pthread_cleanup_pop (0); + + + /* We mark the thread as terminated and as joined. */ + pd->tid = -1; + + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; + + + /* Free the TCB. */ + __free_tcb (pd); + + return 0; +} diff --git a/libpthread/nptl/pthread_key_create.c b/libpthread/nptl/pthread_key_create.c new file mode 100644 index 000000000..cf35bc877 --- /dev/null +++ b/libpthread/nptl/pthread_key_create.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +/* Internal mutex for __pthread_keys table handling. */ +lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER; + +int +__pthread_key_create (key, destr) + pthread_key_t *key; + void (*destr) (void *); +{ + int result = EAGAIN; + size_t cnt; + + lll_lock (__pthread_keys_lock); + + /* Find a slot in __pthread_kyes which is unused. */ + for (cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt) + if (KEY_UNUSED (__pthread_keys[cnt].seq) + && KEY_USABLE (__pthread_keys[cnt].seq)) + { + /* We found an unused slot. */ + ++__pthread_keys[cnt].seq; + + /* Remember the destructor. */ + __pthread_keys[cnt].destr = destr; + + /* Return the key to the caller. */ + *key = cnt; + + /* The call succeeded. */ + result = 0; + + /* We found a key and can stop now. */ + break; + } + + lll_unlock (__pthread_keys_lock); + + return result; +} +strong_alias (__pthread_key_create, pthread_key_create) +strong_alias (__pthread_key_create, __pthread_key_create_internal) diff --git a/libpthread/nptl/pthread_key_delete.c b/libpthread/nptl/pthread_key_delete.c new file mode 100644 index 000000000..ae7d7c459 --- /dev/null +++ b/libpthread/nptl/pthread_key_delete.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +pthread_key_delete (key) + pthread_key_t key; +{ + int result = EINVAL; + + if (__builtin_expect (key < PTHREAD_KEYS_MAX, 1)) + { + unsigned int seq = __pthread_keys[key].seq; + + if (__builtin_expect (! KEY_UNUSED (seq), 1) + && ! atomic_compare_and_exchange_bool_acq (&__pthread_keys[key].seq, + seq + 1, seq)) + /* We deleted a valid key. */ + result = 0; + } + + return result; +} diff --git a/libpthread/nptl/pthread_kill_other_threads.c b/libpthread/nptl/pthread_kill_other_threads.c new file mode 100644 index 000000000..09401aab5 --- /dev/null +++ b/libpthread/nptl/pthread_kill_other_threads.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef SHARED +/* This function does not serve a useful purpose in the thread library + implementation anymore. It used to be necessary when then kernel + could not shut down "processes" but this is not the case anymore. + + We could theoretically provide an equivalent implementation but + this is not necessary since the kernel already does a much better + job than we ever could. */ +void +__pthread_kill_other_threads_np (void) +{ +} +#endif diff --git a/libpthread/nptl/pthread_mutex_destroy.c b/libpthread/nptl/pthread_mutex_destroy.c new file mode 100644 index 000000000..9e63ba263 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_destroy.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +__pthread_mutex_destroy (mutex) + pthread_mutex_t *mutex; +{ + if (mutex->__data.__nusers != 0) + return EBUSY; + + return 0; +} +strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy) diff --git a/libpthread/nptl/pthread_mutex_init.c b/libpthread/nptl/pthread_mutex_init.c new file mode 100644 index 000000000..5058fcc5f --- /dev/null +++ b/libpthread/nptl/pthread_mutex_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <string.h> +#include "pthreadP.h" + + +static const struct pthread_mutexattr default_attr = + { + /* Default is a normal mutex, not shared between processes. */ + .mutexkind = PTHREAD_MUTEX_NORMAL + }; + + +int +__pthread_mutex_init (mutex, mutexattr) + pthread_mutex_t *mutex; + const pthread_mutexattr_t *mutexattr; +{ + const struct pthread_mutexattr *imutexattr; + + assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T); + + imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; + + /* Clear the whole variable. */ + memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); + + /* Copy the values from the attribute. */ + mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000; + + /* Default values: mutex not used yet. */ + // mutex->__count = 0; already done by memset + // mutex->__owner = 0; already done by memset + // mutex->__nusers = 0; already done by memset + // mutex->__spins = 0; already done by memset + + return 0; +} +strong_alias (__pthread_mutex_init, pthread_mutex_init) diff --git a/libpthread/nptl/pthread_mutex_lock.c b/libpthread/nptl/pthread_mutex_lock.c new file mode 100644 index 000000000..ee39f2082 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_lock.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +#ifndef LLL_MUTEX_LOCK +# define LLL_MUTEX_LOCK(mutex) lll_mutex_lock (mutex) +# define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_trylock (mutex) +#endif + + +int +__pthread_mutex_lock (mutex) + pthread_mutex_t *mutex; +{ + assert (sizeof (mutex->__size) >= sizeof (mutex->__data)); + + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + + /* We have to get the mutex. */ + LLL_MUTEX_LOCK (mutex->__data.__lock); + + mutex->__data.__count = 1; + break; + + /* Error checking mutex. */ + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + return EDEADLK; + + /* FALLTHROUGH */ + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + simple: + /* Normal mutex. */ + LLL_MUTEX_LOCK (mutex->__data.__lock); + break; + + case PTHREAD_MUTEX_ADAPTIVE_NP: + if (! __is_smp) + goto simple; + + if (LLL_MUTEX_TRYLOCK (mutex->__data.__lock) != 0) + { + int cnt = 0; + int max_cnt = MIN (MAX_ADAPTIVE_COUNT, + mutex->__data.__spins * 2 + 10); + do + { + if (cnt++ >= max_cnt) + { + LLL_MUTEX_LOCK (mutex->__data.__lock); + break; + } + +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + } + while (LLL_MUTEX_TRYLOCK (mutex->__data.__lock) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } + break; + } + + /* Record the ownership. */ + assert (mutex->__data.__owner == 0); + mutex->__data.__owner = id; +#ifndef NO_INCR + ++mutex->__data.__nusers; +#endif + + return 0; +} +#ifndef __pthread_mutex_lock +strong_alias (__pthread_mutex_lock, pthread_mutex_lock) +strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_internal) +#endif diff --git a/libpthread/nptl/pthread_mutex_timedlock.c b/libpthread/nptl/pthread_mutex_timedlock.c new file mode 100644 index 000000000..1cd2c7e60 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_timedlock.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_mutex_timedlock (mutex, abstime) + pthread_mutex_t *mutex; + const struct timespec *abstime; +{ + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + int result = 0; + + /* We must not check ABSTIME here. If the thread does not block + abstime must not be checked for a valid value. */ + + switch (mutex->__data.__kind) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + goto out; + } + else + { + /* We have to get the mutex. */ + result = lll_mutex_timedlock (mutex->__data.__lock, abstime); + + if (result != 0) + goto out; + + /* Only locked once so far. */ + mutex->__data.__count = 1; + } + break; + + /* Error checking mutex. */ + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + return EDEADLK; + + /* FALLTHROUGH */ + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + simple: + /* Normal mutex. */ + result = lll_mutex_timedlock (mutex->__data.__lock, abstime); + break; + + case PTHREAD_MUTEX_ADAPTIVE_NP: + if (! __is_smp) + goto simple; + + if (lll_mutex_trylock (mutex->__data.__lock) != 0) + { + int cnt = 0; + int max_cnt = MIN (MAX_ADAPTIVE_COUNT, + mutex->__data.__spins * 2 + 10); + do + { + if (cnt++ >= max_cnt) + { + result = lll_mutex_timedlock (mutex->__data.__lock, abstime); + break; + } + +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + } + while (lll_mutex_trylock (mutex->__data.__lock) != 0); + + mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; + } + break; + } + + if (result == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + } + + out: + return result; +} diff --git a/libpthread/nptl/pthread_mutex_trylock.c b/libpthread/nptl/pthread_mutex_trylock.c new file mode 100644 index 000000000..7008af3d9 --- /dev/null +++ b/libpthread/nptl/pthread_mutex_trylock.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_mutex_trylock (mutex) + pthread_mutex_t *mutex; +{ + pid_t id; + + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + /* Recursive mutex. */ + case PTHREAD_MUTEX_RECURSIVE_NP: + id = THREAD_GETMEM (THREAD_SELF, tid); + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + return 0; + } + + if (lll_mutex_trylock (mutex->__data.__lock) == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = id; + mutex->__data.__count = 1; + ++mutex->__data.__nusers; + return 0; + } + break; + + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Error checking mutex. We do not check for deadlocks. */ + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + case PTHREAD_MUTEX_ADAPTIVE_NP: + /* Normal mutex. */ + if (lll_mutex_trylock (mutex->__data.__lock) == 0) + { + /* Record the ownership. */ + mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid); + ++mutex->__data.__nusers; + + return 0; + } + } + + return EBUSY; +} +strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) diff --git a/libpthread/nptl/pthread_mutex_unlock.c b/libpthread/nptl/pthread_mutex_unlock.c new file mode 100644 index 000000000..32bc2a4bc --- /dev/null +++ b/libpthread/nptl/pthread_mutex_unlock.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +internal_function attribute_hidden +__pthread_mutex_unlock_usercnt (mutex, decr) + pthread_mutex_t *mutex; + int decr; +{ + switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) + { + case PTHREAD_MUTEX_RECURSIVE_NP: + /* Recursive mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) + return EPERM; + + if (--mutex->__data.__count != 0) + /* We still hold the mutex. */ + return 0; + break; + + case PTHREAD_MUTEX_ERRORCHECK_NP: + /* Error checking mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) + || ! lll_mutex_islocked (mutex->__data.__lock)) + return EPERM; + break; + + default: + /* Correct code cannot set any other type. */ + case PTHREAD_MUTEX_TIMED_NP: + case PTHREAD_MUTEX_ADAPTIVE_NP: + /* Normal mutex. Nothing special to do. */ + break; + } + + /* Always reset the owner field. */ + mutex->__data.__owner = 0; + if (decr) + /* One less user. */ + --mutex->__data.__nusers; + + /* Unlock. */ + lll_mutex_unlock (mutex->__data.__lock); + + return 0; +} + + +int +__pthread_mutex_unlock (mutex) + pthread_mutex_t *mutex; +{ + return __pthread_mutex_unlock_usercnt (mutex, 1); +} +strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) +strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal) diff --git a/libpthread/nptl/pthread_mutexattr_destroy.c b/libpthread/nptl/pthread_mutexattr_destroy.c new file mode 100644 index 000000000..eab27d351 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +__pthread_mutexattr_destroy (attr) + pthread_mutexattr_t *attr; +{ + return 0; +} +strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) diff --git a/libpthread/nptl/pthread_mutexattr_getpshared.c b/libpthread/nptl/pthread_mutexattr_getpshared.c new file mode 100644 index 000000000..4bd4ea18d --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_getpshared.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_getpshared (attr, pshared) + const pthread_mutexattr_t *attr; + int *pshared; +{ + const struct pthread_mutexattr *iattr; + + iattr = (const struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + *pshared = ((iattr->mutexkind & 0x80000000) != 0 + ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE); + + return 0; +} diff --git a/libpthread/nptl/pthread_mutexattr_gettype.c b/libpthread/nptl/pthread_mutexattr_gettype.c new file mode 100644 index 000000000..5c32b2c6f --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_gettype.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + + +int +pthread_mutexattr_gettype (attr, kind) + const pthread_mutexattr_t *attr; + int *kind; +{ + const struct pthread_mutexattr *iattr; + + iattr = (const struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + *kind = iattr->mutexkind & ~0x80000000; + + return 0; +} +weak_alias (pthread_mutexattr_gettype, pthread_mutexattr_getkind_np) diff --git a/libpthread/nptl/pthread_mutexattr_init.c b/libpthread/nptl/pthread_mutexattr_init.c new file mode 100644 index 000000000..ee026c654 --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_init.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <pthreadP.h> + + +int +__pthread_mutexattr_init (attr) + pthread_mutexattr_t *attr; +{ + if (sizeof (struct pthread_mutexattr) != sizeof (pthread_mutexattr_t)) + memset (attr, '\0', sizeof (*attr)); + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. By default it is zero, i.e., the mutex is + not process-shared. */ + ((struct pthread_mutexattr *) attr)->mutexkind = PTHREAD_MUTEX_NORMAL; + + return 0; +} +strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init) diff --git a/libpthread/nptl/pthread_mutexattr_setpshared.c b/libpthread/nptl/pthread_mutexattr_setpshared.c new file mode 100644 index 000000000..5f2cf417e --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_setpshared.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +pthread_mutexattr_setpshared (attr, pshared) + pthread_mutexattr_t *attr; + int pshared; +{ + struct pthread_mutexattr *iattr; + + if (pshared != PTHREAD_PROCESS_PRIVATE + && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0)) + return EINVAL; + + iattr = (struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + if (pshared == PTHREAD_PROCESS_PRIVATE) + iattr->mutexkind &= ~0x80000000; + else + iattr->mutexkind |= 0x80000000; + + return 0; +} diff --git a/libpthread/nptl/pthread_mutexattr_settype.c b/libpthread/nptl/pthread_mutexattr_settype.c new file mode 100644 index 000000000..c77fe79df --- /dev/null +++ b/libpthread/nptl/pthread_mutexattr_settype.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthreadP.h> + + +int +__pthread_mutexattr_settype (attr, kind) + pthread_mutexattr_t *attr; + int kind; +{ + struct pthread_mutexattr *iattr; + + if (kind < PTHREAD_MUTEX_NORMAL || kind > PTHREAD_MUTEX_ADAPTIVE_NP) + return EINVAL; + + iattr = (struct pthread_mutexattr *) attr; + + /* We use bit 31 to signal whether the mutex is going to be + process-shared or not. */ + iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind; + + return 0; +} +weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_setkind_np) +strong_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype) diff --git a/libpthread/nptl/pthread_rwlock_destroy.c b/libpthread/nptl/pthread_rwlock_destroy.c new file mode 100644 index 000000000..28fd24b55 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +__pthread_rwlock_destroy (rwlock) + pthread_rwlock_t *rwlock; +{ + /* Nothing to be done. For now. */ + return 0; +} +strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy) diff --git a/libpthread/nptl/pthread_rwlock_init.c b/libpthread/nptl/pthread_rwlock_init.c new file mode 100644 index 000000000..f664dd810 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_init.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +static const struct pthread_rwlockattr default_attr = + { + .lockkind = PTHREAD_RWLOCK_DEFAULT_NP, + .pshared = PTHREAD_PROCESS_PRIVATE + }; + + +int +__pthread_rwlock_init (rwlock, attr) + pthread_rwlock_t *rwlock; + const pthread_rwlockattr_t *attr; +{ + const struct pthread_rwlockattr *iattr; + + iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr; + + rwlock->__data.__lock = 0; + rwlock->__data.__flags + = iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP; + rwlock->__data.__nr_readers = 0; + rwlock->__data.__writer = 0; + rwlock->__data.__readers_wakeup = 0; + rwlock->__data.__writer_wakeup = 0; + rwlock->__data.__nr_readers_queued = 0; + rwlock->__data.__nr_writers_queued = 0; + + return 0; +} +strong_alias (__pthread_rwlock_init, pthread_rwlock_init) diff --git a/libpthread/nptl/pthread_rwlock_tryrdlock.c b/libpthread/nptl/pthread_rwlock_tryrdlock.c new file mode 100644 index 000000000..446af0596 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_tryrdlock.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_rwlock_tryrdlock (rwlock) + pthread_rwlock_t *rwlock; +{ + int result = EBUSY; + + lll_mutex_lock (rwlock->__data.__lock); + + if (rwlock->__data.__writer == 0 + && (rwlock->__data.__nr_writers_queued == 0 + || rwlock->__data.__flags == 0)) + { + if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) + { + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + else + result = 0; + } + + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} +strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock) diff --git a/libpthread/nptl/pthread_rwlock_trywrlock.c b/libpthread/nptl/pthread_rwlock_trywrlock.c new file mode 100644 index 000000000..b754a1956 --- /dev/null +++ b/libpthread/nptl/pthread_rwlock_trywrlock.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_rwlock_trywrlock (rwlock) + pthread_rwlock_t *rwlock; +{ + int result = EBUSY; + + lll_mutex_lock (rwlock->__data.__lock); + + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + result = 0; + } + + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} +strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock) diff --git a/libpthread/nptl/pthread_rwlockattr_destroy.c b/libpthread/nptl/pthread_rwlockattr_destroy.c new file mode 100644 index 000000000..4f0c2c4fe --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_destroy.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_destroy (attr) + pthread_rwlockattr_t *attr; +{ + /* Nothing to do. For now. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_getkind_np.c b/libpthread/nptl/pthread_rwlockattr_getkind_np.c new file mode 100644 index 000000000..aad9468fd --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_getkind_np.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getkind_np (attr, pref) + const pthread_rwlockattr_t *attr; + int *pref; +{ + *pref = ((const struct pthread_rwlockattr *) attr)->lockkind; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_getpshared.c b/libpthread/nptl/pthread_rwlockattr_getpshared.c new file mode 100644 index 000000000..3a776835a --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_getpshared.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_getpshared (attr, pshared) + const pthread_rwlockattr_t *attr; + int *pshared; +{ + *pshared = ((const struct pthread_rwlockattr *) attr)->pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_init.c b/libpthread/nptl/pthread_rwlockattr_init.c new file mode 100644 index 000000000..b29953455 --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_init.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_rwlockattr_init (attr) + pthread_rwlockattr_t *attr; +{ + struct pthread_rwlockattr *iattr; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->lockkind = PTHREAD_RWLOCK_DEFAULT_NP; + iattr->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_setkind_np.c b/libpthread/nptl/pthread_rwlockattr_setkind_np.c new file mode 100644 index 000000000..0311f1b50 --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_setkind_np.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setkind_np (attr, pref) + pthread_rwlockattr_t *attr; + int pref; +{ + struct pthread_rwlockattr *iattr; + + if (pref != PTHREAD_RWLOCK_PREFER_READER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + && __builtin_expect (pref != PTHREAD_RWLOCK_PREFER_WRITER_NP, 0)) + return EINVAL; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->lockkind = pref; + + return 0; +} diff --git a/libpthread/nptl/pthread_rwlockattr_setpshared.c b/libpthread/nptl/pthread_rwlockattr_setpshared.c new file mode 100644 index 000000000..9438d2931 --- /dev/null +++ b/libpthread/nptl/pthread_rwlockattr_setpshared.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +int +pthread_rwlockattr_setpshared (attr, pshared) + pthread_rwlockattr_t *attr; + int pshared; +{ + struct pthread_rwlockattr *iattr; + + if (pshared != PTHREAD_PROCESS_SHARED + && __builtin_expect (pshared != PTHREAD_PROCESS_PRIVATE, 0)) + return EINVAL; + + iattr = (struct pthread_rwlockattr *) attr; + + iattr->pshared = pshared; + + return 0; +} diff --git a/libpthread/nptl/pthread_self.c b/libpthread/nptl/pthread_self.c new file mode 100644 index 000000000..f0e3b3f98 --- /dev/null +++ b/libpthread/nptl/pthread_self.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <tls.h> + + +pthread_t +__pthread_self (void) +{ + return (pthread_t) THREAD_SELF; +} +strong_alias (__pthread_self, pthread_self) diff --git a/libpthread/nptl/pthread_setcancelstate.c b/libpthread/nptl/pthread_setcancelstate.c new file mode 100644 index 000000000..a452c2ec4 --- /dev/null +++ b/libpthread/nptl/pthread_setcancelstate.c @@ -0,0 +1,73 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +__pthread_setcancelstate (state, oldstate) + int state; + int *oldstate; +{ + volatile struct pthread *self; + + if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) + return EINVAL; + + self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + int newval = (state == PTHREAD_CANCEL_DISABLE + ? oldval | CANCELSTATE_BITMASK + : oldval & ~CANCELSTATE_BITMASK); + + /* Store the old value. */ + if (oldstate != NULL) + *oldstate = ((oldval & CANCELSTATE_BITMASK) + ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE); + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the memory has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* Update the cancel handling word. This has to be done + atomically since other bits could be modified as well. */ + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + __do_cancel (); + + break; + } + + /* Prepare for the next round. */ + oldval = curval; + } + + return 0; +} +strong_alias (__pthread_setcancelstate, pthread_setcancelstate) diff --git a/libpthread/nptl/pthread_setcanceltype.c b/libpthread/nptl/pthread_setcanceltype.c new file mode 100644 index 000000000..bbe87ba64 --- /dev/null +++ b/libpthread/nptl/pthread_setcanceltype.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" +#include <atomic.h> + + +int +__pthread_setcanceltype (type, oldtype) + int type; + int *oldtype; +{ + volatile struct pthread *self; + + if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + + self = THREAD_SELF; + + int oldval = THREAD_GETMEM (self, cancelhandling); + while (1) + { + int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS + ? oldval | CANCELTYPE_BITMASK + : oldval & ~CANCELTYPE_BITMASK); + + /* Store the old value. */ + if (oldtype != NULL) + *oldtype = ((oldval & CANCELTYPE_BITMASK) + ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED); + + /* Avoid doing unnecessary work. The atomic operation can + potentially be expensive if the memory has to be locked and + remote cache lines have to be invalidated. */ + if (oldval == newval) + break; + + /* Update the cancel handling word. This has to be done + atomically since other bits could be modified as well. */ + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + { + if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } + + break; + } + + /* Prepare for the next round. */ + oldval = curval; + } + + return 0; +} +strong_alias (__pthread_setcanceltype, pthread_setcanceltype) diff --git a/libpthread/nptl/pthread_setconcurrency.c b/libpthread/nptl/pthread_setconcurrency.c new file mode 100644 index 000000000..8cf150713 --- /dev/null +++ b/libpthread/nptl/pthread_setconcurrency.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + + +/* Global definition. Needed in pthread_getconcurrency as well. */ +int __concurrency_level; + + +int +pthread_setconcurrency (level) + int level; +{ + if (level < 0) + return EINVAL; + + __concurrency_level = level; + + /* XXX For ports which actually need to handle the concurrency level + some more code is probably needed here. */ + + return 0; +} diff --git a/libpthread/nptl/pthread_setegid.c b/libpthread/nptl/pthread_setegid.c new file mode 100644 index 000000000..9252dfac7 --- /dev/null +++ b/libpthread/nptl/pthread_setegid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define setegid pthread_setegid_np +#include <setegid.c> diff --git a/libpthread/nptl/pthread_seteuid.c b/libpthread/nptl/pthread_seteuid.c new file mode 100644 index 000000000..47bb69802 --- /dev/null +++ b/libpthread/nptl/pthread_seteuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define seteuid pthread_seteuid_np +#include <seteuid.c> diff --git a/libpthread/nptl/pthread_setgid.c b/libpthread/nptl/pthread_setgid.c new file mode 100644 index 000000000..b06bffbf3 --- /dev/null +++ b/libpthread/nptl/pthread_setgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setgid pthread_setgid_np +#include <setgid.c> diff --git a/libpthread/nptl/pthread_setregid.c b/libpthread/nptl/pthread_setregid.c new file mode 100644 index 000000000..7461d2b7f --- /dev/null +++ b/libpthread/nptl/pthread_setregid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setregid pthread_setregid_np +#include <setregid.c> diff --git a/libpthread/nptl/pthread_setresgid.c b/libpthread/nptl/pthread_setresgid.c new file mode 100644 index 000000000..369fae267 --- /dev/null +++ b/libpthread/nptl/pthread_setresgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresgid pthread_setresgid_np +#include <setresgid.c> diff --git a/libpthread/nptl/pthread_setresuid.c b/libpthread/nptl/pthread_setresuid.c new file mode 100644 index 000000000..ac57c0fa8 --- /dev/null +++ b/libpthread/nptl/pthread_setresuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresuid pthread_setresuid_np +#include <setresuid.c> diff --git a/libpthread/nptl/pthread_setreuid.c b/libpthread/nptl/pthread_setreuid.c new file mode 100644 index 000000000..aa804ab01 --- /dev/null +++ b/libpthread/nptl/pthread_setreuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setreuid pthread_setreuid_np +#include <setreuid.c> diff --git a/libpthread/nptl/pthread_setschedparam.c b/libpthread/nptl/pthread_setschedparam.c new file mode 100644 index 000000000..71c2f9b77 --- /dev/null +++ b/libpthread/nptl/pthread_setschedparam.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <string.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +__pthread_setschedparam (threadid, policy, param) + pthread_t threadid; + int policy; + const struct sched_param *param; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + int result = 0; + + lll_lock (pd->lock); + + /* Try to set the scheduler information. */ + if (__builtin_expect (sched_setscheduler (pd->tid, policy, + param) == -1, 0)) + result = errno; + else + { + /* We succeeded changing the kernel information. Reflect this + change in the thread descriptor. */ + pd->schedpolicy = policy; + memcpy (&pd->schedparam, param, sizeof (struct sched_param)); + pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET; + } + + lll_unlock (pd->lock); + + return result; +} +strong_alias (__pthread_setschedparam, pthread_setschedparam) diff --git a/libpthread/nptl/pthread_setschedprio.c b/libpthread/nptl/pthread_setschedprio.c new file mode 100644 index 000000000..e7ea4b76f --- /dev/null +++ b/libpthread/nptl/pthread_setschedprio.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sched.h> +#include <string.h> +#include <sched.h> +#include "pthreadP.h" +#include <lowlevellock.h> + + +int +pthread_setschedprio (threadid, prio) + pthread_t threadid; + int prio; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + int result = 0; + struct sched_param param; + param.sched_priority = prio; + + lll_lock (pd->lock); + + /* Try to set the scheduler information. */ + if (__builtin_expect (sched_setparam (pd->tid, ¶m) == -1, 0)) + result = errno; + else + { + /* We succeeded changing the kernel information. Reflect this + change in the thread descriptor. */ + memcpy (&pd->schedparam, ¶m, sizeof (struct sched_param)); + pd->flags |= ATTR_FLAG_SCHED_SET; + } + + lll_unlock (pd->lock); + + return result; +} diff --git a/libpthread/nptl/pthread_setspecific.c b/libpthread/nptl/pthread_setspecific.c new file mode 100644 index 000000000..b6e66b5f2 --- /dev/null +++ b/libpthread/nptl/pthread_setspecific.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "pthreadP.h" + + +int +__pthread_setspecific (key, value) + pthread_key_t key; + const void *value; +{ + struct pthread *self; + unsigned int idx1st; + unsigned int idx2nd; + struct pthread_key_data *level2; + unsigned int seq; + + self = THREAD_SELF; + + /* Special case access to the first 2nd-level block. This is the + usual case. */ + if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1)) + { + /* Verify the key is sane. */ + if (KEY_UNUSED ((seq = __pthread_keys[key].seq))) + /* Not valid. */ + return EINVAL; + + level2 = &self->specific_1stblock[key]; + + /* Remember that we stored at least one set of data. */ + if (value != NULL) + THREAD_SETMEM (self, specific_used, true); + } + else + { + if (KEY_UNUSED ((seq = __pthread_keys[key].seq)) + || key >= PTHREAD_KEYS_MAX) + /* Not valid. */ + return EINVAL; + + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + + /* This is the second level array. Allocate it if necessary. */ + level2 = THREAD_GETMEM_NC (self, specific, idx1st); + if (level2 == NULL) + { + if (value == NULL) + /* We don't have to do anything. The value would in any case + be NULL. We can save the memory allocation. */ + return 0; + + level2 + = (struct pthread_key_data *) calloc (PTHREAD_KEY_2NDLEVEL_SIZE, + sizeof (*level2)); + if (level2 == NULL) + return ENOMEM; + + THREAD_SETMEM_NC (self, specific, idx1st, level2); + } + + /* Pointer to the right array element. */ + level2 = &level2[idx2nd]; + + /* Remember that we stored at least one set of data. */ + THREAD_SETMEM (self, specific_used, true); + } + + /* Store the data and the sequence number so that we can recognize + stale data. */ + level2->seq = seq; + level2->data = (void *) value; + + return 0; +} +strong_alias (__pthread_setspecific, pthread_setspecific) +strong_alias (__pthread_setspecific, __pthread_setspecific_internal) diff --git a/libpthread/nptl/pthread_setuid.c b/libpthread/nptl/pthread_setuid.c new file mode 100644 index 000000000..ff949c850 --- /dev/null +++ b/libpthread/nptl/pthread_setuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setuid pthread_setuid_np +#include <setuid.c> diff --git a/libpthread/nptl/pthread_testcancel.c b/libpthread/nptl/pthread_testcancel.c new file mode 100644 index 000000000..e9b17b493 --- /dev/null +++ b/libpthread/nptl/pthread_testcancel.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> +#include "pthreadP.h" + + +void +pthread_testcancel (void) +{ + CANCELLATION_P (THREAD_SELF); +} diff --git a/libpthread/nptl/pthread_timedjoin.c b/libpthread/nptl/pthread_timedjoin.c new file mode 100644 index 000000000..1cc07213c --- /dev/null +++ b/libpthread/nptl/pthread_timedjoin.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "atomic.h" +#include "pthreadP.h" + + +static void +cleanup (void *arg) +{ + *(void **) arg = NULL; +} + + +int +pthread_timedjoin_np (threadid, thread_return, abstime) + pthread_t threadid; + void **thread_return; + const struct timespec *abstime; +{ + struct pthread *self; + struct pthread *pd = (struct pthread *) threadid; + int result; + + /* Make sure the descriptor is valid. */ + if (INVALID_NOT_TERMINATED_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Is the thread joinable?. */ + if (IS_DETACHED (pd)) + /* We cannot wait for the thread. */ + return EINVAL; + + self = THREAD_SELF; + if (pd == self || self->joinid == pd) + /* This is a deadlock situation. The threads are waiting for each + other to finish. Note that this is a "may" error. To be 100% + sure we catch this error we would have to lock the data + structures but it is not necessary. In the unlikely case that + two threads are really caught in this situation they will + deadlock. It is the programmer's problem to figure this + out. */ + return EDEADLK; + + /* Wait for the thread to finish. If it is already locked something + is wrong. There can only be one waiter. */ + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, + self, NULL), 0)) + /* There is already somebody waiting for the thread. */ + return EINVAL; + + + /* During the wait we change to asynchronous cancellation. If we + are cancelled the thread we are waiting for must be marked as + un-wait-ed for again. */ + pthread_cleanup_push (cleanup, &pd->joinid); + + /* Switch to asynchronous cancellation. */ + int oldtype = CANCEL_ASYNC (); + + + /* Wait for the child. */ + result = lll_timedwait_tid (pd->tid, abstime); + + + /* Restore cancellation mode. */ + CANCEL_RESET (oldtype); + + /* Remove the handler. */ + pthread_cleanup_pop (0); + + + /* We might have timed out. */ + if (result == 0) + { + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; + + + /* Free the TCB. */ + __free_tcb (pd); + } + else + pd->joinid = NULL; + + return result; +} diff --git a/libpthread/nptl/pthread_tryjoin.c b/libpthread/nptl/pthread_tryjoin.c new file mode 100644 index 000000000..904cb5280 --- /dev/null +++ b/libpthread/nptl/pthread_tryjoin.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> + +#include "atomic.h" +#include "pthreadP.h" + + +int +pthread_tryjoin_np (threadid, thread_return) + pthread_t threadid; + void **thread_return; +{ + struct pthread *self; + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (DEBUGGING_P && __find_in_stack_list (pd) == NULL) + /* Not a valid thread handle. */ + return ESRCH; + + /* Is the thread joinable?. */ + if (IS_DETACHED (pd)) + /* We cannot wait for the thread. */ + return EINVAL; + + self = THREAD_SELF; + if (pd == self || self->joinid == pd) + /* This is a deadlock situation. The threads are waiting for each + other to finish. Note that this is a "may" error. To be 100% + sure we catch this error we would have to lock the data + structures but it is not necessary. In the unlikely case that + two threads are really caught in this situation they will + deadlock. It is the programmer's problem to figure this + out. */ + return EDEADLK; + + /* Return right away if the thread hasn't terminated yet. */ + if (pd->tid != 0) + return EBUSY; + + /* Wait for the thread to finish. If it is already locked something + is wrong. There can only be one waiter. */ + if (atomic_compare_and_exchange_bool_acq (&pd->joinid, self, NULL)) + /* There is already somebody waiting for the thread. */ + return EINVAL; + + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; + + + /* Free the TCB. */ + __free_tcb (pd); + + return 0; +} diff --git a/libpthread/nptl/res.c b/libpthread/nptl/res.c new file mode 100644 index 000000000..37529899e --- /dev/null +++ b/libpthread/nptl/res.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2002, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> + +#include <tls.h> +#include <resolv.h> + +struct __res_state * +__res_state (void) +{ + return __resp; +} diff --git a/libpthread/nptl/sem_close.c b/libpthread/nptl/sem_close.c new file mode 100644 index 000000000..279522d08 --- /dev/null +++ b/libpthread/nptl/sem_close.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <search.h> +#include <sys/mman.h> +#include "semaphoreP.h" + + +/* Global variables to parametrize the walk function. This works + since we always have to use locks. And we have to use the twalk + function since the entries are not sorted wrt the mapping + address. */ +static sem_t *the_sem; +static struct inuse_sem *rec; + +static void +walker (const void *inodep, const VISIT which, const int depth) +{ + struct inuse_sem *nodep = *(struct inuse_sem **) inodep; + + if (nodep->sem == the_sem) + rec = nodep; +} + + +int +sem_close (sem) + sem_t *sem; +{ + int result = 0; + + /* Get the lock. */ + lll_lock (__sem_mappings_lock); + + /* Locate the entry for the mapping the caller provided. */ + rec = NULL; + the_sem = sem; + twalk (__sem_mappings, walker); + if (rec != NULL) + { + /* Check the reference counter. If it is going to be zero, free + all the resources. */ + if (--rec->refcnt == 0) + { + /* Remove the record from the tree. */ + (void) tdelete (rec, &__sem_mappings, __sem_search); + + result = munmap (rec->sem, sizeof (sem_t)); + + free (rec); + } + } + else + { + /* This is no valid semaphore. */ + result = -1; + __set_errno (EINVAL); + } + + /* Release the lock. */ + lll_unlock (__sem_mappings_lock); + + return result; +} diff --git a/libpthread/nptl/sem_destroy.c b/libpthread/nptl/sem_destroy.c new file mode 100644 index 000000000..1fdb7b5b7 --- /dev/null +++ b/libpthread/nptl/sem_destroy.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "semaphoreP.h" + + +int +__new_sem_destroy (sem) + sem_t *sem; +{ + /* XXX Check for valid parameter. */ + + /* Nothing to do. */ + return 0; +} +weak_alias(__new_sem_destroy, sem_destroy) diff --git a/libpthread/nptl/sem_getvalue.c b/libpthread/nptl/sem_getvalue.c new file mode 100644 index 000000000..c03827b00 --- /dev/null +++ b/libpthread/nptl/sem_getvalue.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "semaphoreP.h" + + +int +__new_sem_getvalue (sem, sval) + sem_t *sem; + int *sval; +{ + struct sem *isem = (struct sem *) sem; + + /* XXX Check for valid SEM parameter. */ + + *sval = isem->count; + + return 0; +} +weak_alias(__new_sem_getvalue, sem_getvalue) diff --git a/libpthread/nptl/sem_init.c b/libpthread/nptl/sem_init.c new file mode 100644 index 000000000..0fbdf594e --- /dev/null +++ b/libpthread/nptl/sem_init.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <lowlevellock.h> +#include "semaphoreP.h" + + +int +__new_sem_init (sem, pshared, value) + sem_t *sem; + int pshared; + unsigned int value; +{ + /* Parameter sanity check. */ + if (__builtin_expect (value > SEM_VALUE_MAX, 0)) + { + __set_errno (EINVAL); + return -1; + } + + /* Map to the internal type. */ + struct sem *isem = (struct sem *) sem; + + /* Use the value the user provided. */ + isem->count = value; + + /* We can completely ignore the PSHARED parameter since inter-process + use needs no special preparation. */ + + return 0; +} +weak_alias(__new_sem_init, sem_init) diff --git a/libpthread/nptl/sem_open.c b/libpthread/nptl/sem_open.c new file mode 100644 index 000000000..25389f0cd --- /dev/null +++ b/libpthread/nptl/sem_open.c @@ -0,0 +1,391 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mntent.h> +#include <paths.h> +#include <pthread.h> +#include <search.h> +#include <semaphore.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <linux_fsinfo.h> +#include "semaphoreP.h" +#include "../../libc/misc/internals/tempname.h" + + +/* Compatibility defines. */ +#define __endmntent endmntent +#define __fxstat64(vers, fd, buf) fstat64(fd, buf) +#define __getmntent_r getmntent_r +#define __setmntent setmntent +#define __statfs statfs +#define __libc_close close +#define __libc_open open +#define __libc_write write + +/* Information about the mount point. */ +struct mountpoint_info mountpoint attribute_hidden; + +/* This is the default mount point. */ +static const char defaultmount[] = "/dev/shm"; +/* This is the default directory. */ +static const char defaultdir[] = "/dev/shm/sem."; + +/* Protect the `mountpoint' variable above. */ +pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT; + + +/* Determine where the shmfs is mounted (if at all). */ +void +attribute_hidden +__where_is_shmfs (void) +{ + char buf[512]; + struct statfs f; + struct mntent resmem; + struct mntent *mp; + FILE *fp; + + /* The canonical place is /dev/shm. This is at least what the + documentation tells everybody to do. */ + if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC) + { + /* It is in the normal place. */ + mountpoint.dir = (char *) defaultdir; + mountpoint.dirlen = sizeof (defaultdir) - 1; + + return; + } + + /* OK, do it the hard way. Look through the /proc/mounts file and if + this does not exist through /etc/fstab to find the mount point. */ + fp = __setmntent ("/proc/mounts", "r"); + if (__builtin_expect (fp == NULL, 0)) + { + fp = __setmntent (_PATH_MNTTAB, "r"); + if (__builtin_expect (fp == NULL, 0)) + /* There is nothing we can do. Blind guesses are not helpful. */ + return; + } + + /* Now read the entries. */ + while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL) + /* The original name is "shm" but this got changed in early Linux + 2.4.x to "tmpfs". */ + if (strcmp (mp->mnt_type, "tmpfs") == 0 + || strcmp (mp->mnt_type, "shm") == 0) + { + /* Found it. There might be more than one place where the + filesystem is mounted but one is enough for us. */ + size_t namelen; + + /* First make sure this really is the correct entry. At least + some versions of the kernel give wrong information because + of the implicit mount of the shmfs for SysV IPC. */ + if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC) + continue; + + namelen = strlen (mp->mnt_dir); + + if (namelen == 0) + /* Hum, maybe some crippled entry. Keep on searching. */ + continue; + + mountpoint.dir = (char *) malloc (namelen + 4 + 2); + if (mountpoint.dir != NULL) + { + char *cp = mempcpy (mountpoint.dir, mp->mnt_dir, namelen); + if (cp[-1] != '/') + *cp++ = '/'; + cp = stpcpy (cp, "sem."); + mountpoint.dirlen = cp - mountpoint.dir; + } + + break; + } + + /* Close the stream. */ + __endmntent (fp); +} + + +/* Comparison function for search of existing mapping. */ +int +attribute_hidden +__sem_search (const void *a, const void *b) +{ + const struct inuse_sem *as = (const struct inuse_sem *) a; + const struct inuse_sem *bs = (const struct inuse_sem *) b; + + if (as->ino != bs->ino) + /* Cannot return the difference the type is larger than int. */ + return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1); + + if (as->dev != bs->dev) + /* Cannot return the difference the type is larger than int. */ + return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1); + + return strcmp (as->name, bs->name); +} + + +/* The search tree for existing mappings. */ +void *__sem_mappings attribute_hidden; + +/* Lock to protect the search tree. */ +lll_lock_t __sem_mappings_lock = LLL_LOCK_INITIALIZER; + + +/* Search for existing mapping and if possible add the one provided. */ +static sem_t * +check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing) +{ + sem_t *result = SEM_FAILED; + + /* Get the information about the file. */ +#ifdef __UCLIBC_HAS_LFS__ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) == 0) +#else + struct stat st; + if (fstat (fd, &st) == 0) +#endif + { + /* Get the lock. */ + lll_lock (__sem_mappings_lock); + + /* Search for an existing mapping given the information we have. */ + struct inuse_sem *fake; + fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen); + memcpy (fake->name, name, namelen); + fake->dev = st.st_dev; + fake->ino = st.st_ino; + + struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search); + if (foundp != NULL) + { + /* There is already a mapping. Use it. */ + result = (*foundp)->sem; + ++(*foundp)->refcnt; + } + else + { + /* We haven't found a mapping. Install ione. */ + struct inuse_sem *newp; + + newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen); + if (newp != NULL) + { + /* If the caller hasn't provided any map it now. */ + if (existing == SEM_FAILED) + existing = (sem_t *) mmap (NULL, sizeof (sem_t), + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + + newp->dev = st.st_dev; + newp->ino = st.st_ino; + newp->refcnt = 1; + newp->sem = existing; + memcpy (newp->name, name, namelen); + + /* Insert the new value. */ + if (existing != MAP_FAILED + && tsearch (newp, &__sem_mappings, __sem_search) != NULL) + /* Successful. */ + result = existing; + else + /* Something went wrong while inserting the new + value. We fail completely. */ + free (newp); + } + } + + /* Release the lock. */ + lll_unlock (__sem_mappings_lock); + } + + if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED) + { + /* Do not disturb errno. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t)); + } + + return result; +} + + +sem_t * +sem_open (const char *name, int oflag, ...) +{ + char *finalname; + sem_t *result = SEM_FAILED; + int fd; + + /* Determine where the shmfs is mounted. */ + __pthread_once (&__namedsem_once, __where_is_shmfs); + + /* If we don't know the mount points there is nothing we can do. Ever. */ + if (mountpoint.dir == NULL) + { + __set_errno (ENOSYS); + return SEM_FAILED; + } + + /* Construct the filename. */ + while (name[0] == '/') + ++name; + + if (name[0] == '\0') + { + /* The name "/" is not supported. */ + __set_errno (EINVAL); + return SEM_FAILED; + } + size_t namelen = strlen (name) + 1; + + /* Create the name of the final file. */ + finalname = (char *) alloca (mountpoint.dirlen + namelen); + mempcpy (mempcpy (finalname, mountpoint.dir, mountpoint.dirlen), + name, namelen); + + /* If the semaphore object has to exist simply open it. */ + if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0) + { + try_again: + fd = __libc_open (finalname, + (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR); + + if (fd == -1) + { + /* If we are supposed to create the file try this next. */ + if ((oflag & O_CREAT) != 0 && errno == ENOENT) + goto try_create; + + /* Return. errno is already set. */ + } + else + /* Check whether we already have this semaphore mapped and + create one if necessary. */ + result = check_add_mapping (name, namelen, fd, SEM_FAILED); + } + else + { + /* We have to open a temporary file first since it must have the + correct form before we can start using it. */ + char *tmpfname; + mode_t mode; + unsigned int value; + va_list ap; + + try_create: + va_start (ap, oflag); + + mode = va_arg (ap, mode_t); + value = va_arg (ap, unsigned int); + + va_end (ap); + + if (value > SEM_VALUE_MAX) + { + __set_errno (EINVAL); + return SEM_FAILED; + } + + /* Create the initial file content. */ + sem_t initsem; + + struct sem *iinitsem = (struct sem *) &initsem; + iinitsem->count = value; + + /* Initialize the remaining bytes as well. */ + memset ((char *) &initsem + sizeof (struct sem), '\0', + sizeof (sem_t) - sizeof (struct sem)); + + tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1); + char *xxxxxx = mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen); + strcpy (xxxxxx, "XXXXXX"); + + fd = __gen_tempname (tmpfname, __GT_FILE, mode); + if (fd == -1) + return SEM_FAILED; + + if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t))) + == sizeof (sem_t) + /* Map the sem_t structure from the file. */ + && (result = (sem_t *) mmap (NULL, sizeof (sem_t), + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0)) != MAP_FAILED) + { + /* Create the file. Don't overwrite an existing file. */ + if (link (tmpfname, finalname) != 0) + { + /* Undo the mapping. */ + (void) munmap (result, sizeof (sem_t)); + + /* Reinitialize 'result'. */ + result = SEM_FAILED; + + /* This failed. If O_EXCL is not set and the problem was + that the file exists, try again. */ + if ((oflag & O_EXCL) == 0 && errno == EEXIST) + { + /* Remove the file. */ + (void) unlink (tmpfname); + + /* Close the file. */ + (void) __libc_close (fd); + + goto try_again; + } + } + else + /* Insert the mapping into the search tree. This also + determines whether another thread sneaked by and already + added such a mapping despite the fact that we created it. */ + result = check_add_mapping (name, namelen, fd, result); + } + + /* Now remove the temporary name. This should never fail. If + it fails we leak a file name. Better fix the kernel. */ + (void) unlink (tmpfname); + } + + /* Map the mmap error to the error we need. */ + if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED) + result = SEM_FAILED; + + /* We don't need the file descriptor anymore. */ + if (fd != -1) + { + /* Do not disturb errno. */ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (close, err, 1, fd); + } + + return result; +} diff --git a/libpthread/nptl/sem_unlink.c b/libpthread/nptl/sem_unlink.c new file mode 100644 index 000000000..5f24fd35b --- /dev/null +++ b/libpthread/nptl/sem_unlink.c @@ -0,0 +1,67 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "semaphoreP.h" + + +int +sem_unlink (name) + const char *name; +{ + char *fname; + size_t namelen; + + /* Determine where the shmfs is mounted. */ + __pthread_once (&__namedsem_once, __where_is_shmfs); + + /* If we don't know the mount points there is nothing we can do. Ever. */ + if (mountpoint.dir == NULL) + { + __set_errno (ENOSYS); + return -1; + } + + /* Construct the filename. */ + while (name[0] == '/') + ++name; + + if (name[0] == '\0') + { + /* The name "/" is not supported. */ + __set_errno (ENOENT); + return -1; + } + namelen = strlen (name); + + /* Create the name of the file. */ + fname = (char *) alloca (mountpoint.dirlen + namelen + 1); + mempcpy (mempcpy (fname, mountpoint.dir, mountpoint.dirlen), + name, namelen + 1); + + /* Now try removing it. */ + int ret = unlink (fname); + if (ret < 0 && errno == EPERM) + __set_errno (EACCES); + return ret; +} diff --git a/libpthread/nptl/semaphore.h b/libpthread/nptl/semaphore.h new file mode 100644 index 000000000..4f13725b3 --- /dev/null +++ b/libpthread/nptl/semaphore.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2002, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H 1 + +#include <features.h> +#include <sys/types.h> +#ifdef __USE_XOPEN2K +# define __need_timespec +# include <time.h> +#endif + +/* Get the definition for sem_t. */ +#include <bits/semaphore.h> + + +__BEGIN_DECLS + +/* Initialize semaphore object SEM to VALUE. If PSHARED then share it + with other processes. */ +extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) + __THROW; +/* Free resources associated with semaphore object SEM. */ +extern int sem_destroy (sem_t *__sem) __THROW; + +/* Open a named semaphore NAME with open flags OFLAG. */ +extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; + +/* Close descriptor for named semaphore SEM. */ +extern int sem_close (sem_t *__sem) __THROW; + +/* Remove named semaphore NAME. */ +extern int sem_unlink (__const char *__name) __THROW; + +/* Wait for SEM being posted. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int sem_wait (sem_t *__sem); + +#ifdef __USE_XOPEN2K +/* Similar to `sem_wait' but wait only until ABSTIME. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int sem_timedwait (sem_t *__restrict __sem, + __const struct timespec *__restrict __abstime); +#endif + +/* Test whether SEM is posted. */ +extern int sem_trywait (sem_t *__sem) __THROW; + +/* Post SEM. */ +extern int sem_post (sem_t *__sem) __THROW; + +/* Get current value of SEM and store it in *SVAL. */ +extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval) + __THROW; + + +__END_DECLS + +#endif /* semaphore.h */ diff --git a/libpthread/nptl/semaphoreP.h b/libpthread/nptl/semaphoreP.h new file mode 100644 index 000000000..d14ea92c7 --- /dev/null +++ b/libpthread/nptl/semaphoreP.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <semaphore.h> +#include "pthreadP.h" + + +/* Mount point of the shared memory filesystem. */ +struct mountpoint_info +{ + char *dir; + size_t dirlen; +}; + +/* Keeping track of currently used mappings. */ +struct inuse_sem +{ + dev_t dev; + ino_t ino; + int refcnt; + sem_t *sem; + char name[0]; +}; + + +/* Variables used in multiple interfaces. */ +extern struct mountpoint_info mountpoint attribute_hidden; + +extern pthread_once_t __namedsem_once attribute_hidden; + +/* The search tree for existing mappings. */ +extern void *__sem_mappings attribute_hidden; + +/* Lock to protect the search tree. */ +extern lll_lock_t __sem_mappings_lock; + + +/* Initializer for mountpoint. */ +extern void __where_is_shmfs (void) attribute_hidden; + +/* Comparison function for search in tree with existing mappings. */ +extern int __sem_search (const void *a, const void *b) attribute_hidden; + + +/* Prototypes of functions with multiple interfaces. */ +extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value); +extern int __new_sem_destroy (sem_t *sem); +extern int __new_sem_post (sem_t *sem); +extern int __new_sem_wait (sem_t *sem); +extern int __new_sem_trywait (sem_t *sem); +extern int __new_sem_getvalue (sem_t *sem, int *sval); diff --git a/libpthread/nptl/sysdeps/alpha/Makefile b/libpthread/nptl/sysdeps/alpha/Makefile new file mode 100644 index 000000000..88c106bbb --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/Makefile @@ -0,0 +1,21 @@ +# Copyright (C) 2003 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, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/alpha/dl-tls.h b/libpthread/nptl/sysdeps/alpha/dl-tls.h new file mode 100644 index 000000000..f81f95d75 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. Alpha version. + Copyright (C) 2002 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c new file mode 100644 index 000000000..ba2e419d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c @@ -0,0 +1,89 @@ +/* Special .init and .fini section support for Alpha. NPTL version. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the .init and .fini + sections and defines global symbols for those addresses, so they can be + called as functions. + + * crtn.s puts the corresponding function epilogues in the .init and .fini + sections. + + This differs from what would be generated by the generic code in that + we save and restore the GP within the function. In order for linker + relaxation to work, the value in the GP register on exit from a function + must be valid for the function entry point. Normally, a function is + contained within one object file and this is not an issue, provided + that the function reloads the gp after making any function calls. + However, _init and _fini are constructed from pieces of many object + files, all of which may have different GP values. So we must reload + the GP value from crti.o in crtn.o. */ + +__asm__ (" \n\ +#include \"defs.h\" \n\ + \n\ +/*@HEADER_ENDS*/ \n\ + \n\ +/*@_init_PROLOG_BEGINS*/ \n\ + .section .init, \"ax\", @progbits \n\ + .globl _init \n\ + .type _init,@function \n\ + .usepv _init,std \n\ +_init: \n\ + ldgp $29, 0($27) \n\ + subq $30, 16, $30 \n\ + stq $26, 0($30) \n\ + stq $29, 8($30) \n\ + bsr $26, __pthread_initialize_minimal_internal !samegp \n\ + .align 3 \n\ +/*@_init_PROLOG_ENDS*/ \n\ + \n\ +/*@_init_EPILOG_BEGINS*/ \n\ + .section .init, \"ax\", @progbits \n\ + ldq $26, 0($30) \n\ + ldq $29, 8($30) \n\ + addq $30, 16, $30 \n\ + ret \n\ +/*@_init_EPILOG_ENDS*/ \n\ + \n\ +/*@_fini_PROLOG_BEGINS*/ \n\ + .section .fini, \"ax\", @progbits \n\ + .globl _fini \n\ + .type _fini,@function \n\ + .usepv _fini,std \n\ +_fini: \n\ + ldgp $29, 0($27) \n\ + subq $30, 16, $30 \n\ + stq $26, 0($30) \n\ + stq $29, 8($30) \n\ + .align 3 \n\ +/*@_fini_PROLOG_ENDS*/ \n\ + \n\ +/*@_fini_EPILOG_BEGINS*/ \n\ + .section .fini, \"ax\", @progbits \n\ + ldq $26, 0($30) \n\ + ldq $29, 8($30) \n\ + addq $30, 16, $30 \n\ + ret \n\ +/*@_fini_EPILOG_ENDS*/ \n\ + \n\ +/*@TRAILER_BEGINS*/ \n\ +"); diff --git a/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/alpha/libc-tls.c b/libpthread/nptl/sysdeps/alpha/libc-tls.c new file mode 100644 index 000000000..a3b68e928 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker. Alpha version. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On Alpha, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + ti->ti_offset; +} + +#endif diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S new file mode 100644 index 000000000..ce6cd41a4 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@twiddle.net>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + + .text + .align 4 + + .globl pthread_spin_lock + .ent pthread_spin_lock +pthread_spin_lock: + .frame $sp, 0, $26, 0 + .prologue 0 + +0: ldl_l $1, 0($16) + lda $2, 1 + lda $0, 0 + bne $1, 1f + + stl_c $2, 0($16) + beq $2, 1f + mb + ret + +1: ldl $1, 0($16) + bne $1, 1b + unop + br 0b + + .end pthread_spin_lock diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S new file mode 100644 index 000000000..0948da698 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson <rth@twiddle.net>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +#define _ERRNO_H 1 +#include <bits/errno.h> + + .text + .align 4 + + .globl pthread_spin_trylock + .ent pthread_spin_trylock +pthread_spin_trylock: + .frame $sp, 0, $26, 0 + .prologue 0 + +0: ldl_l $1, 0($16) + lda $2, 1 + lda $0, EBUSY + bne $1, 1f + + stl_c $2, 0($16) + beq $2, 2f + mb + lda $0, 0 + +1: ret +2: br 0b + + .end pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/alpha/pthreaddef.h b/libpthread/nptl/sysdeps/alpha/pthreaddef.h new file mode 100644 index 000000000..26c4daf7b --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthreaddef.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. The ABI requires 16. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym new file mode 100644 index 000000000..c21a79104 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym @@ -0,0 +1,14 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +-- # define __builtin_thread_pointer() ((void *) 0) +-- # define thread_offsetof(mem) ((void *) &THREAD_SELF->mem - (void *) 0) +-- Ho hum, this doesn't work in gcc4, so Know Things about THREAD_SELF +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/alpha/tls.h b/libpthread/nptl/sysdeps/alpha/tls.h new file mode 100644 index 000000000..99cd27a03 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tls.h @@ -0,0 +1,127 @@ +/* Definition for thread-local data handling. NPTL/Alpha version. + Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <nptl/descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN 16 + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN 16 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + (__builtin_set_thread_pointer ((void *)(tcbp)), NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (64, 64, 32 * 8, -sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/arm/Makefile.arch b/libpthread/nptl/sysdeps/arm/Makefile.arch new file mode 100644 index 000000000..6d16ae3fd --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/Makefile.arch @@ -0,0 +1,69 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# Portions Copyright (C) 2006 CodeSourcery +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S aeabi_read_tp.S \ + thumb_atomics.S +libpthread_CSRC = aeabi_unwind_cpp_pr1.c + +librt_SSRC = aeabi_read_tp.S thumb_atomics.S +librt_CSRC = aeabi_unwind_cpp_pr1.c + +libc_a_CSRC = + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-aeabi_read_tp.S = -DNOT_IN_libc=1 + +CFLAGS-arm = $(SSP_ALL_CFLAGS) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) +LIBRT_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(librt_SSRC)) +LIBRT_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(librt_CSRC)) + + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +librt-a-y += $(LIBRT_ARCH_OBJ) +librt-so-y += $(LIBRT_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.s \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: + $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S new file mode 100644 index 000000000..af640d625 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..84683627b --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <../../../../libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/arm/dl-tls.h b/libpthread/nptl/sysdeps/arm/dl-tls.h new file mode 100644 index 000000000..e0324a7b6 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. ARM version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h new file mode 100644 index 000000000..6e8f01d10 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2005,2006 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ +#undef _JMPBUF_UNWINDS +#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \ + ((void *) (address) < (void *) demangle (jmpbuf[__JMP_BUF_SP])) + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S new file mode 100644 index 000000000..bd6adf794 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + + .text + .align 4 + +ENTRY (pthread_spin_lock) + mov r1, #1 +1: swp r2, r1, [r0] + teq r2, #0 + bne 1b + mov r0, #0 + PSEUDO_RET_NOERRNO +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S new file mode 100644 index 000000000..85931507a --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S @@ -0,0 +1,34 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define _ERRNO_H 1 +#include <bits/errno.h> + +#include <sysdep.h> + + .text + .align 4 + +ENTRY (pthread_spin_trylock) + mov r1, #1 + swp r2, r1, [r0] + teq r2, #0 + moveq r0, #0 + movne r0, #EBUSY + PSEUDO_RET_NOERRNO +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/arm/pthreaddef.h b/libpthread/nptl/sysdeps/arm/pthreaddef.h new file mode 100644 index 000000000..783828a40 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/arm/sysdep.h b/libpthread/nptl/sysdeps/arm/sysdep.h new file mode 100644 index 000000000..19bd3c3f7 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/sysdep.h @@ -0,0 +1,91 @@ +/* Assembler macros for ARM. + Copyright (C) 1997, 1998, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* In ELF C symbols are asm symbols. */ +#undef NO_UNDERSCORES +#define NO_UNDERSCORES + +#define PLTJMP(_x) _x##(PLT) + +/* APCS-32 doesn't preserve the condition codes across function call. */ +#ifdef __APCS_32__ +#define LOADREGS(cond, base, reglist...)\ + ldm##cond base,reglist +#ifdef __USE_BX__ +#define RETINSTR(cond, reg) \ + bx##cond reg +#define DO_RET(_reg) \ + bx _reg +#else +#define RETINSTR(cond, reg) \ + mov##cond pc, reg +#define DO_RET(_reg) \ + mov pc, _reg +#endif +#else /* APCS-26 */ +#define LOADREGS(cond, base, reglist...)\ + ldm##cond base,reglist^ +#define RETINSTR(cond, reg) \ + mov##cond##s pc, reg +#define DO_RET(_reg) \ + movs pc, _reg +#endif + +/* Define an entry point visible from C. */ +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \ + .align ALIGNARG(4); \ + name##: \ + CALL_MCOUNT + +#undef END +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +#define CALL_MCOUNT \ + str lr,[sp, #-4]! ; \ + bl PLTJMP(mcount) ; \ + ldr lr, [sp], #4 ; +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/arm/tcb-offsets.sym b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym new file mode 100644 index 000000000..92cc441d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Derive offsets relative to the thread register. +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/arm/thumb_atomics.S b/libpthread/nptl/sysdeps/arm/thumb_atomics.S new file mode 100644 index 000000000..aaa7a3d8f --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/thumb_atomics.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/thumb_atomics.S> diff --git a/libpthread/nptl/sysdeps/arm/tls.h b/libpthread/nptl/sysdeps/arm/tls.h new file mode 100644 index 000000000..b8efd59b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tls.h @@ -0,0 +1,140 @@ +/* Definition for thread-local data handling. NPTL/ARM version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +#include <dl-sysdep.h> + +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +#define HAVE___THREAD 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Like all other modern NPTL ports, ARM uses forced unwinding. */ +#define HAVE_FORCED_UNWIND + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <../../descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN 16 + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN 16 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (tcbp)); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* Initializing the thread pointer will generate a SIGILL if the syscall + is not available. */ +#define TLS_INIT_TP_EXPENSIVE 1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/generic/Makefile b/libpthread/nptl/sysdeps/generic/Makefile new file mode 100644 index 000000000..582661fde --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/generic/Makefile.in b/libpthread/nptl/sysdeps/generic/Makefile.in new file mode 100644 index 000000000..1079a5fd9 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile.in @@ -0,0 +1,30 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# +# NOTE: Alpha and MIPS have their own versions of 'libc-tls.c' in +# their architecture specific directory which will override +# the one here. +# +libc_a_CSRC = dl-tls.c libc-tls.c + + +CFLAGS-generic = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_GENERIC_OUT:=$(top_builddir)libpthread/nptl/sysdeps/generic + +LIBC_GENERIC_OBJ:=$(patsubst %.c,$(PTHREAD_GENERIC_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_GENERIC_OBJ) + +libc-nomulti-y+=$(LIBC_GENERIC_OBJ) + +objclean-y+=nptl_pthread_generic_clean + +nptl_pthread_generic_clean: + $(do_rm) $(addprefix $(PTHREAD_GENERIC_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.c b/libpthread/nptl/sysdeps/generic/dl-tls.c new file mode 100644 index 000000000..da6ebbddb --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.c @@ -0,0 +1,895 @@ +/* Thread-local storage handling in the ELF dynamic linker. Generic version. + Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <libintl.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/param.h> +#include <tls.h> +#include <dl-tls.h> +#include <ldsodefs.h> +#include <dl-elf.h> +#include <dl-hash.h> + +#include <assert.h> +#include <link.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#define _dl_malloc malloc +#define _dl_memset memset +#define _dl_mempcpy mempcpy +#define _dl_dprintf fprintf +#define _dl_debug_file stderr +#define _dl_exit exit + +/* Amount of excess space to allocate in the static TLS area + to allow dynamic loading of modules defining IE-model TLS data. */ +# define TLS_STATIC_SURPLUS 64 + DL_NNS * 100 + +/* Value used for dtv entries for which the allocation is delayed. */ +# define TLS_DTV_UNALLOCATED ((void *) -1l) + + +/* Out-of-memory handler. */ +# ifdef SHARED +static void +__attribute__ ((__noreturn__)) +oom (void) +{ + do { + _dl_dprintf (_dl_debug_file, + "cannot allocate thread-local memory: ABORT\n"); + _dl_exit (127); + } while (1); +} +# endif + + +void *_dl_memalign(size_t alignment, size_t bytes) +{ + return _dl_malloc(bytes); +} + + +/* + * We are trying to perform a static TLS relocation in MAP, but it was + * dynamically loaded. This can only work if there is enough surplus in + * the static TLS area already allocated for each running thread. If this + * object's TLS segment is too big to fit, we fail. If it fits, + * we set MAP->l_tls_offset and return. + * This function intentionally does not return any value but signals error + * directly, as static TLS should be rare and code handling it should + * not be inlined as much as possible. + */ + + +void +internal_function __attribute_noinline__ +_dl_allocate_static_tls (struct link_map *map) +{ + /* If the alignment requirements are too high fail. */ + if (map->l_tls_align > _dl_tls_static_align) + { +fail: + _dl_dprintf(_dl_debug_file, "cannot allocate memory in static TLS block"); + _dl_exit(30); + } + +# if defined(TLS_TCB_AT_TP) + size_t freebytes; + size_t n; + size_t blsize; + + freebytes = _dl_tls_static_size - _dl_tls_static_used - TLS_TCB_SIZE; + + blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset; + if (freebytes < blsize) + goto fail; + + n = (freebytes - blsize) / map->l_tls_align; + + size_t offset = _dl_tls_static_used + (freebytes - n * map->l_tls_align + - map->l_tls_firstbyte_offset); + + map->l_tls_offset = _dl_tls_static_used = offset; +# elif defined(TLS_DTV_AT_TP) + size_t used; + size_t check; + + size_t offset = roundup (_dl_tls_static_used, map->l_tls_align); + used = offset + map->l_tls_blocksize; + check = used; + + /* dl_tls_static_used includes the TCB at the beginning. */ + if (check > _dl_tls_static_size) + goto fail; + + map->l_tls_offset = offset; + _dl_tls_static_used = used; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* + * If the object is not yet relocated we cannot initialize the + * static TLS region. Delay it. + */ + if (((struct elf_resolve *) map)->init_flag & RELOCS_DONE) + { +#ifdef SHARED + /* + * Update the slot information data for at least the generation of + * the DSO we are allocating data for. + */ + if (__builtin_expect (THREAD_DTV()[0].counter != _dl_tls_generation, 0)) + (void) _dl_update_slotinfo (map->l_tls_modid); +#endif + _dl_init_static_tls (map); + } + else + map->l_need_tls_init = 1; +} + +size_t +internal_function +_dl_next_tls_modid (void) +{ + size_t result; + + if (__builtin_expect (GL(dl_tls_dtv_gaps), false)) + { + size_t disp = 0; + struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list); + + /* Note that this branch will never be executed during program + start since there are no gaps at that time. Therefore it + does not matter that the dl_tls_dtv_slotinfo is not allocated + yet when the function is called for the first times. + + NB: the offset +1 is due to the fact that DTV[0] is used + for something else. */ + result = GL(dl_tls_static_nelem) + 1; + if (result <= GL(dl_tls_max_dtv_idx)) + do + { + while (result - disp < runp->len) + { + if (runp->slotinfo[result - disp].map == NULL) + break; + + ++result; + assert (result <= GL(dl_tls_max_dtv_idx) + 1); + } + + if (result - disp < runp->len) + break; + + disp += runp->len; + } + while ((runp = runp->next) != NULL); + + if (result > GL(dl_tls_max_dtv_idx)) + { + /* The new index must indeed be exactly one higher than the + previous high. */ + assert (result == GL(dl_tls_max_dtv_idx) + 1); + /* There is no gap anymore. */ + GL(dl_tls_dtv_gaps) = false; + + goto nogaps; + } + } + else + { + /* No gaps, allocate a new entry. */ + nogaps: + + result = ++GL(dl_tls_max_dtv_idx); + } + + return result; +} + + +# ifdef SHARED +void +internal_function +_dl_determine_tlsoffset (void) +{ + size_t max_align = TLS_TCB_ALIGN; + size_t freetop = 0; + size_t freebottom = 0; + + /* The first element of the dtv slot info list is allocated. */ + assert (GL(dl_tls_dtv_slotinfo_list) != NULL); + /* There is at this point only one element in the + dl_tls_dtv_slotinfo_list list. */ + assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL); + + struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo; + + /* Determining the offset of the various parts of the static TLS + block has several dependencies. In addition we have to work + around bugs in some toolchains. + + Each TLS block from the objects available at link time has a size + and an alignment requirement. The GNU ld computes the alignment + requirements for the data at the positions *in the file*, though. + I.e, it is not simply possible to allocate a block with the size + of the TLS program header entry. The data is layed out assuming + that the first byte of the TLS block fulfills + + p_vaddr mod p_align == &TLS_BLOCK mod p_align + + This means we have to add artificial padding at the beginning of + the TLS block. These bytes are never used for the TLS data in + this module but the first byte allocated must be aligned + according to mod p_align == 0 so that the first byte of the TLS + block is aligned according to p_vaddr mod p_align. This is ugly + and the linker can help by computing the offsets in the TLS block + assuming the first byte of the TLS block is aligned according to + p_align. + + The extra space which might be allocated before the first byte of + the TLS block need not go unused. The code below tries to use + that memory for the next TLS block. This can work if the total + memory requirement for the next TLS block is smaller than the + gap. */ + +# if defined(TLS_TCB_AT_TP) + /* We simply start with zero. */ + size_t offset = 0; + + for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt) + { + assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + + size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset + & (slotinfo[cnt].map->l_tls_align - 1)); + size_t off; + max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + + if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize) + { + off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize + - firstbyte, slotinfo[cnt].map->l_tls_align) + + firstbyte; + if (off <= freebottom) + { + freetop = off; + + /* XXX For some architectures we perhaps should store the + negative offset. */ + slotinfo[cnt].map->l_tls_offset = off; + continue; + } + } + + off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte, + slotinfo[cnt].map->l_tls_align) + firstbyte; + if (off > offset + slotinfo[cnt].map->l_tls_blocksize + + (freebottom - freetop)) + { + freetop = offset; + freebottom = off - slotinfo[cnt].map->l_tls_blocksize; + } + offset = off; + + /* XXX For some architectures we perhaps should store the + negative offset. */ + slotinfo[cnt].map->l_tls_offset = off; + } + + GL(dl_tls_static_used) = offset; + GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align) + + TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) + /* The TLS blocks start right after the TCB. */ + size_t offset = TLS_TCB_SIZE; + size_t cnt; + + for (cnt = 0; slotinfo[cnt].map != NULL; ++cnt) + { + assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + + size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset + & (slotinfo[cnt].map->l_tls_align - 1)); + size_t off; + max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + + if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom) + { + off = roundup (freebottom, slotinfo[cnt].map->l_tls_align); + if (off - freebottom < firstbyte) + off += slotinfo[cnt].map->l_tls_align; + if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop) + { + slotinfo[cnt].map->l_tls_offset = off - firstbyte; + freebottom = (off + slotinfo[cnt].map->l_tls_blocksize + - firstbyte); + continue; + } + } + + off = roundup (offset, slotinfo[cnt].map->l_tls_align); + if (off - offset < firstbyte) + off += slotinfo[cnt].map->l_tls_align; + + slotinfo[cnt].map->l_tls_offset = off - firstbyte; + if (off - firstbyte - offset > freetop - freebottom) + { + freebottom = offset; + freetop = off - firstbyte; + } + + offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte; + } + + GL(dl_tls_static_used) = offset; + GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS, + TLS_TCB_ALIGN); +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* The alignment requirement for the static TLS block. */ + GL(dl_tls_static_align) = max_align; +} + + +/* This is called only when the data structure setup was skipped at startup, + when there was no need for it then. Now we have dynamically loaded + something needing TLS, or libpthread needs it. */ +int +internal_function +_dl_tls_setup (void) +{ + assert (GL(dl_tls_dtv_slotinfo_list) == NULL); + assert (GL(dl_tls_max_dtv_idx) == 0); + + const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS; + + GL(dl_tls_dtv_slotinfo_list) + = calloc (1, (sizeof (struct dtv_slotinfo_list) + + nelem * sizeof (struct dtv_slotinfo))); + if (GL(dl_tls_dtv_slotinfo_list) == NULL) + return -1; + + GL(dl_tls_dtv_slotinfo_list)->len = nelem; + + /* Number of elements in the static TLS block. It can't be zero + because of various assumptions. The one element is null. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1; + + /* This initializes more variables for us. */ + _dl_determine_tlsoffset (); + + return 0; +} +# endif + +static void * +internal_function +allocate_dtv (void *result) +{ + dtv_t *dtv; + size_t dtv_length; + + /* We allocate a few more elements in the dtv than are needed for the + initial set of modules. This should avoid in most cases expansions + of the dtv. */ + dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; + dtv = calloc (dtv_length + 2, sizeof (dtv_t)); + if (dtv != NULL) + { + /* This is the initial length of the dtv. */ + dtv[0].counter = dtv_length; + + /* The rest of the dtv (including the generation counter) is + Initialize with zero to indicate nothing there. */ + + /* Add the dtv to the thread data structures. */ + INSTALL_DTV (result, dtv); + } + else + result = NULL; + + return result; +} + + +/* Get size and alignment requirements of the static TLS block. */ +void +internal_function +_dl_get_tls_static_info (size_t *sizep, size_t *alignp) +{ + *sizep = GL(dl_tls_static_size); + *alignp = GL(dl_tls_static_align); +} + + +void * +internal_function +_dl_allocate_tls_storage (void) +{ + void *result; + size_t size = GL(dl_tls_static_size); + +# if defined(TLS_DTV_AT_TP) + /* Memory layout is: + [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ] + ^ This should be returned. */ + size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) + & ~(GL(dl_tls_static_align) - 1); +# endif + + /* Allocate a correctly aligned chunk of memory. */ + result = _dl_memalign (GL(dl_tls_static_align), size); + if (__builtin_expect (result != NULL, 1)) + { + /* Allocate the DTV. */ + void *allocated = result; + +# if defined(TLS_TCB_AT_TP) + /* The TCB follows the TLS blocks. */ + result = (char *) result + size - TLS_TCB_SIZE; + + /* Clear the TCB data structure. We can't ask the caller (i.e. + libpthread) to do it, because we will initialize the DTV et al. */ + _dl_memset (result, '\0', TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) + result = (char *) result + size - GL(dl_tls_static_size); + + /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it. + We can't ask the caller (i.e. libpthread) to do it, because we will + initialize the DTV et al. */ + _dl_memset ((char *) result - TLS_PRE_TCB_SIZE, '\0', + TLS_PRE_TCB_SIZE + TLS_TCB_SIZE); +# endif + + result = allocate_dtv (result); + if (result == NULL) + free (allocated); + } + + return result; +} + + +void * +internal_function +_dl_allocate_tls_init (void *result) +{ + if (result == NULL) + /* The memory allocation failed. */ + return NULL; + + dtv_t *dtv = GET_DTV (result); + struct dtv_slotinfo_list *listp; + size_t total = 0; + size_t maxgen = 0; + + /* We have to prepare the dtv for all currently loaded modules using + TLS. For those which are dynamically loaded we add the values + indicating deferred allocation. */ + listp = GL(dl_tls_dtv_slotinfo_list); + while (1) + { + size_t cnt; + + for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) + { + struct link_map *map; + void *dest; + + /* Check for the total number of used slots. */ + if (total + cnt > GL(dl_tls_max_dtv_idx)) + break; + + map = listp->slotinfo[cnt].map; + if (map == NULL) + /* Unused entry. */ + continue; + + /* Keep track of the maximum generation number. This might + not be the generation counter. */ + maxgen = MAX (maxgen, listp->slotinfo[cnt].gen); + + if (map->l_tls_offset == NO_TLS_OFFSET) + { + /* For dynamically loaded modules we simply store + the value indicating deferred allocation. */ + dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED; + dtv[map->l_tls_modid].pointer.is_static = false; + continue; + } + + assert (map->l_tls_modid == cnt); + assert (map->l_tls_blocksize >= map->l_tls_initimage_size); +# if defined(TLS_TCB_AT_TP) + assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize); + dest = (char *) result - map->l_tls_offset; +# elif defined(TLS_DTV_AT_TP) + dest = (char *) result + map->l_tls_offset; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Copy the initialization image and clear the BSS part. */ + dtv[map->l_tls_modid].pointer.val = dest; + dtv[map->l_tls_modid].pointer.is_static = true; + _dl_memset (_dl_mempcpy (dest, map->l_tls_initimage, + map->l_tls_initimage_size), '\0', + map->l_tls_blocksize - map->l_tls_initimage_size); + } + + total += cnt; + if (total >= GL(dl_tls_max_dtv_idx)) + break; + + listp = listp->next; + assert (listp != NULL); + } + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; + + return result; +} + +void * +internal_function +_dl_allocate_tls (void *mem) +{ + return _dl_allocate_tls_init (mem == NULL + ? _dl_allocate_tls_storage () + : allocate_dtv (mem)); +} + + +void +internal_function +_dl_deallocate_tls (void *tcb, bool dealloc_tcb) +{ + dtv_t *dtv = GET_DTV (tcb); + size_t cnt; + + /* We need to free the memory allocated for non-static TLS. */ + for (cnt = 0; cnt < dtv[-1].counter; ++cnt) + if (! dtv[1 + cnt].pointer.is_static + && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED) + free (dtv[1 + cnt].pointer.val); + + /* The array starts with dtv[-1]. */ +#ifdef SHARED + if (dtv != GL(dl_initial_dtv)) +#endif + free (dtv - 1); + + if (dealloc_tcb) + { +# if defined(TLS_TCB_AT_TP) + /* The TCB follows the TLS blocks. Back up to free the whole block. */ + tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE; +# elif defined(TLS_DTV_AT_TP) + /* Back up the TLS_PRE_TCB_SIZE bytes. */ + tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) + & ~(GL(dl_tls_static_align) - 1); +# endif + free (tcb); + } +} + + +# ifdef SHARED +/* The __tls_get_addr function has two basic forms which differ in the + arguments. The IA-64 form takes two parameters, the module ID and + offset. The form used, among others, on IA-32 takes a reference to + a special structure which contain the same information. The second + form seems to be more often used (in the moment) so we default to + it. Users of the IA-64 form have to provide adequate definitions + of the following macros. */ +# ifndef GET_ADDR_ARGS +# define GET_ADDR_ARGS tls_index *ti +# endif +# ifndef GET_ADDR_MODULE +# define GET_ADDR_MODULE ti->ti_module +# endif +# ifndef GET_ADDR_OFFSET +# define GET_ADDR_OFFSET ti->ti_offset +# endif + + +static void * +allocate_and_init (struct link_map *map) +{ + void *newp; + + newp = _dl_memalign (map->l_tls_align, map->l_tls_blocksize); + if (newp == NULL) + oom (); + + /* Initialize the memory. */ + _dl_memset (_dl_mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size), + '\0', map->l_tls_blocksize - map->l_tls_initimage_size); + + return newp; +} + + +struct link_map * +_dl_update_slotinfo (unsigned long int req_modid) +{ + struct link_map *the_map = NULL; + dtv_t *dtv = THREAD_DTV (); + + /* The global dl_tls_dtv_slotinfo array contains for each module + index the generation counter current when the entry was created. + This array never shrinks so that all module indices which were + valid at some time can be used to access it. Before the first + use of a new module index in this function the array was extended + appropriately. Access also does not have to be guarded against + modifications of the array. It is assumed that pointer-size + values can be read atomically even in SMP environments. It is + possible that other threads at the same time dynamically load + code and therefore add to the slotinfo list. This is a problem + since we must not pick up any information about incomplete work. + The solution to this is to ignore all dtv slots which were + created after the one we are currently interested. We know that + dynamic loading for this module is completed and this is the last + load operation we know finished. */ + unsigned long int idx = req_modid; + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + + while (idx >= listp->len) + { + idx -= listp->len; + listp = listp->next; + } + + if (dtv[0].counter < listp->slotinfo[idx].gen) + { + /* The generation counter for the slot is higher than what the + current dtv implements. We have to update the whole dtv but + only those entries with a generation counter <= the one for + the entry we need. */ + size_t new_gen = listp->slotinfo[idx].gen; + size_t total = 0; + + /* We have to look through the entire dtv slotinfo list. */ + listp = GL(dl_tls_dtv_slotinfo_list); + do + { + size_t cnt; + + for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) + { + size_t gen = listp->slotinfo[cnt].gen; + + if (gen > new_gen) + /* This is a slot for a generation younger than the + one we are handling now. It might be incompletely + set up so ignore it. */ + continue; + + /* If the entry is older than the current dtv layout we + know we don't have to handle it. */ + if (gen <= dtv[0].counter) + continue; + + /* If there is no map this means the entry is empty. */ + struct link_map *map = listp->slotinfo[cnt].map; + if (map == NULL) + { + /* If this modid was used at some point the memory + might still be allocated. */ + if (! dtv[total + cnt].pointer.is_static + && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED) + { + free (dtv[total + cnt].pointer.val); + dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; + } + + continue; + } + + /* Check whether the current dtv array is large enough. */ + size_t modid = map->l_tls_modid; + assert (total + cnt == modid); + if (dtv[-1].counter < modid) + { + /* Reallocate the dtv. */ + dtv_t *newp; + size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; + size_t oldsize = dtv[-1].counter; + + assert (map->l_tls_modid <= newsize); + + if (dtv == GL(dl_initial_dtv)) + { + /* This is the initial dtv that was allocated + during rtld startup using the dl-minimal.c + malloc instead of the real malloc. We can't + free it, we have to abandon the old storage. */ + + newp = malloc ((2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + _dl_memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t)); + } + else + { + newp = realloc (&dtv[-1], + (2 + newsize) * sizeof (dtv_t)); + if (newp == NULL) + oom (); + } + + newp[0].counter = newsize; + + /* Clear the newly allocated part. */ + _dl_memset (newp + 2 + oldsize, '\0', + (newsize - oldsize) * sizeof (dtv_t)); + + /* Point dtv to the generation counter. */ + dtv = &newp[1]; + + /* Install this new dtv in the thread data + structures. */ + INSTALL_NEW_DTV (dtv); + } + + /* If there is currently memory allocate for this + dtv entry free it. */ + /* XXX Ideally we will at some point create a memory + pool. */ + if (! dtv[modid].pointer.is_static + && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED) + /* Note that free is called for NULL is well. We + deallocate even if it is this dtv entry we are + supposed to load. The reason is that we call + memalign and not malloc. */ + free (dtv[modid].pointer.val); + + /* This module is loaded dynamically- We defer memory + allocation. */ + dtv[modid].pointer.is_static = false; + dtv[modid].pointer.val = TLS_DTV_UNALLOCATED; + + if (modid == req_modid) + the_map = map; + } + + total += listp->len; + } + while ((listp = listp->next) != NULL); + + /* This will be the new maximum generation counter. */ + dtv[0].counter = new_gen; + } + + return the_map; +} + + +/* The generic dynamic and local dynamic model cannot be used in + statically linked applications. */ +void * +__tls_get_addr (GET_ADDR_ARGS) +{ + dtv_t *dtv = THREAD_DTV (); + struct link_map *the_map = NULL; + void *p; + + if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0)) + the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + + p = dtv[GET_ADDR_MODULE].pointer.val; + + if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0)) + { + /* The allocation was deferred. Do it now. */ + if (the_map == NULL) + { + /* Find the link map for this module. */ + size_t idx = GET_ADDR_MODULE; + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + + while (idx >= listp->len) + { + idx -= listp->len; + listp = listp->next; + } + + the_map = listp->slotinfo[idx].map; + } + + p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map); + dtv[GET_ADDR_MODULE].pointer.is_static = false; + } + + return (char *) p + GET_ADDR_OFFSET; +} +# endif + + + +void +_dl_add_to_slotinfo (struct link_map *l) +{ + /* Now that we know the object is loaded successfully add + modules containing TLS data to the dtv info table. We + might have to increase its size. */ + struct dtv_slotinfo_list *listp; + struct dtv_slotinfo_list *prevp; + size_t idx = l->l_tls_modid; + + /* Find the place in the dtv slotinfo list. */ + listp = GL(dl_tls_dtv_slotinfo_list); + prevp = NULL; /* Needed to shut up gcc. */ + do + { + /* Does it fit in the array of this list element? */ + if (idx < listp->len) + break; + idx -= listp->len; + prevp = listp; + listp = listp->next; + } + while (listp != NULL); + + if (listp == NULL) + { + /* When we come here it means we have to add a new element + to the slotinfo list. And the new module must be in + the first slot. */ + assert (idx == 0); + + listp = prevp->next = (struct dtv_slotinfo_list *) + malloc (sizeof (struct dtv_slotinfo_list) + + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + if (listp == NULL) + { + /* We ran out of memory. We will simply fail this + call but don't undo anything we did so far. The + application will crash or be terminated anyway very + soon. */ + + /* We have to do this since some entries in the dtv + slotinfo array might already point to this + generation. */ + ++GL(dl_tls_generation); + + _dl_dprintf (_dl_debug_file, + "cannot create TLS data structures: ABORT\n"); + _dl_exit (127); + } + + listp->len = TLS_SLOTINFO_SURPLUS; + listp->next = NULL; + _dl_memset (listp->slotinfo, '\0', + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); + } + + /* Add the information into the slotinfo data structure. */ + listp->slotinfo[idx].map = l; + listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; +} diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.h b/libpthread/nptl/sysdeps/generic/dl-tls.h new file mode 100644 index 000000000..7703a9752 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.h @@ -0,0 +1,2 @@ +/* There has to be an architecture specific version of this file. */ +#error "architecture-specific version of <dl-tls.h> missing" diff --git a/libpthread/nptl/sysdeps/generic/libc-tls.c b/libpthread/nptl/sysdeps/generic/libc-tls.c new file mode 100644 index 000000000..b78d96483 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/libc-tls.c @@ -0,0 +1,265 @@ +/* Initialization code for TLS in statically linked application. + Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <ldsodefs.h> +#include <tls.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/param.h> +#include <elf.h> +#include <link.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef SHARED + #error makefile bug, this file is for static only +#endif + +#if USE_TLS +extern ElfW(Phdr) *_dl_phdr; +extern size_t _dl_phnum; + + +static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS]; + + +static struct +{ + struct dtv_slotinfo_list si; + /* The dtv_slotinfo_list data structure does not include the actual + information since it is defined as an array of size zero. We define + here the necessary entries. Note that it is not important whether + there is padding or not since we will always access the information + through the 'si' element. */ + struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS]; +} static_slotinfo; + +/* Fake link map for the application. */ +static struct link_map static_map; + + +/* Highest dtv index currently needed. */ +size_t _dl_tls_max_dtv_idx; +/* Flag signalling whether there are gaps in the module ID allocation. */ +bool _dl_tls_dtv_gaps; +/* Information about the dtv slots. */ +struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* Number of modules in the static TLS block. */ +size_t _dl_tls_static_nelem; +/* Size of the static TLS block. */ +size_t _dl_tls_static_size; +/* Size actually allocated in the static TLS block. */ +size_t _dl_tls_static_used; +/* Alignment requirement of the static TLS block. */ +size_t _dl_tls_static_align; + +/* Generation counter for the dtv. */ +size_t _dl_tls_generation; + + +/* Additional definitions needed by TLS initialization. */ +#ifdef TLS_INIT_HELPER +TLS_INIT_HELPER +#endif + +static inline void +init_slotinfo (void) +{ + /* Create the slotinfo list. */ + static_slotinfo.si.len = (((char *) (&static_slotinfo + 1) + - (char *) &static_slotinfo.si.slotinfo[0]) + / sizeof static_slotinfo.si.slotinfo[0]); + // static_slotinfo.si.next = NULL; already zero + + /* The slotinfo list. Will be extended by the code doing dynamic + linking. */ + GL(dl_tls_max_dtv_idx) = 1; + GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si; +} + +static inline void +init_static_tls (size_t memsz, size_t align) +{ + /* That is the size of the TLS memory for this object. The initialized + value of _dl_tls_static_size is provided by dl-open.c to request some + surplus that permits dynamic loading of modules with IE-model TLS. */ + GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size), + TLS_TCB_ALIGN); + GL(dl_tls_static_used) = memsz; + /* The alignment requirement for the static TLS block. */ + GL(dl_tls_static_align) = align; + /* Number of elements in the static TLS block. */ + GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx); +} + +void +__libc_setup_tls (size_t tcbsize, size_t tcbalign) +{ + void *tlsblock; + size_t memsz = 0; + size_t filesz = 0; + void *initimage = NULL; + size_t align = 0; + size_t max_align = tcbalign; + size_t tcb_offset; + ElfW(Phdr) *phdr; + + /* Look through the TLS segment if there is any. */ + if (_dl_phdr != NULL) + for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) + if (phdr->p_type == PT_TLS) + { + /* Remember the values we need. */ + memsz = phdr->p_memsz; + filesz = phdr->p_filesz; + initimage = (void *) phdr->p_vaddr; + align = phdr->p_align; + if (phdr->p_align > max_align) + max_align = phdr->p_align; + break; + } + + /* We have to set up the TCB block which also (possibly) contains + 'errno'. Therefore we avoid 'malloc' which might touch 'errno'. + Instead we use 'sbrk' which would only uses 'errno' if it fails. + In this case we are right away out of memory and the user gets + what she/he deserves. + + The initialized value of _dl_tls_static_size is provided by dl-open.c + to request some surplus that permits dynamic loading of modules with + IE-model TLS. */ +# if defined(TLS_TCB_AT_TP) + tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign); + tlsblock = sbrk (tcb_offset + tcbsize + max_align); +# elif defined(TLS_DTV_AT_TP) + tcb_offset = roundup (tcbsize, align ?: 1); + tlsblock = sbrk (tcb_offset + memsz + max_align + + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); + tlsblock += TLS_PRE_TCB_SIZE; +# else + /* In case a model with a different layout for the TCB and DTV + is defined add another #elif here and in the following #ifs. */ +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* Align the TLS block. */ + tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1) + & ~(max_align - 1)); + + /* Initialize the dtv. [0] is the length, [1] the generation counter. */ + static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2; + // static_dtv[1].counter = 0; would be needed if not already done + + /* Initialize the TLS block. */ +# if defined(TLS_TCB_AT_TP) + static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset + - roundup (memsz, align ?: 1)); + static_map.l_tls_offset = roundup (memsz, align ?: 1); +# elif defined(TLS_DTV_AT_TP) + static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset; + static_map.l_tls_offset = tcb_offset; +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + static_dtv[2].pointer.is_static = true; + /* sbrk gives us zero'd memory, so we don't need to clear the remainder. */ + memcpy (static_dtv[2].pointer.val, initimage, filesz); + + /* Install the pointer to the dtv. */ + + /* Initialize the thread pointer. */ +# if defined(TLS_TCB_AT_TP) + INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv); + + const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0); +# elif defined(TLS_DTV_AT_TP) + INSTALL_DTV (tlsblock, static_dtv); + const char *lossage = (char *)TLS_INIT_TP (tlsblock, 0); +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + if (__builtin_expect (lossage != NULL, 0)) + abort(); + + /* We have to create a fake link map which normally would be created + by the dynamic linker. It just has to have enough information to + make the TLS routines happy. */ + static_map.l_tls_align = align; + static_map.l_tls_blocksize = memsz; + static_map.l_tls_initimage = initimage; + static_map.l_tls_initimage_size = filesz; + static_map.l_tls_modid = 1; + + init_slotinfo (); + // static_slotinfo.si.slotinfo[1].gen = 0; already zero + static_slotinfo.si.slotinfo[1].map = &static_map; + + memsz = roundup (memsz, align ?: 1); + +# if defined(TLS_TCB_AT_TP) + memsz += tcbsize; +# elif defined(TLS_DTV_AT_TP) + memsz += tcb_offset; +# endif + + init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align)); +} + +/* This is called only when the data structure setup was skipped at startup, + when there was no need for it then. Now we have dynamically loaded + something needing TLS, or libpthread needs it. */ +int +internal_function +_dl_tls_setup (void) +{ + init_slotinfo (); + init_static_tls ( +# if defined(TLS_TCB_AT_TP) + TLS_TCB_SIZE, +# else + 0, +# endif + TLS_TCB_ALIGN); + return 0; +} + + +/* This is the minimal initialization function used when libpthread is + not used. */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ + __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN); +} + +#elif defined NONTLS_INIT_TP + +/* This is the minimal initialization function used when libpthread is + not used. */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ + NONTLS_INIT_TP; +} + +#endif diff --git a/libpthread/nptl/sysdeps/generic/lowlevellock.h b/libpthread/nptl/sysdeps/generic/lowlevellock.h new file mode 100644 index 000000000..7f95daada --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/lowlevellock.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <atomic.h> + + +/* Implement generic mutex. Basic futex syscall support is required: + + lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT + and third parameter VALUE + + lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE + and third parameter VALUE +*/ + + +/* Mutex lock counter: + bit 31 clear means unlocked; + bit 31 set means locked. + + All code that looks at bit 31 first increases the 'number of + interested threads' usage counter, which is in bits 0-30. + + All negative mutex values indicate that the mutex is still locked. */ + + +static inline void +__generic_mutex_lock (int *mutex) +{ + unsigned int v; + + /* Bit 31 was clear, we got the mutex. (this is the fastpath). */ + if (atomic_bit_test_set (mutex, 31) == 0) + return; + + atomic_increment (mutex); + + while (1) + { + if (atomic_bit_test_set (mutex, 31) == 0) + { + atomic_decrement (mutex); + return; + } + + /* We have to wait now. First make sure the futex value we are + monitoring is truly negative (i.e. locked). */ + v = *mutex; + if (v >= 0) + continue; + + lll_futex_wait (mutex, v); + } +} + + +static inline void +__generic_mutex_unlock (int *mutex) +{ + /* Adding 0x80000000 to the counter results in 0 if and only if + there are not other interested threads - we can return (this is + the fastpath). */ + if (atomic_add_zero (mutex, 0x80000000)) + return; + + /* There are other threads waiting for this mutex, wake one of them + up. */ + lll_futex_wake (mutex, 1); +} + + +#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex)) +#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex)) diff --git a/libpthread/nptl/sysdeps/generic/sysdep.h b/libpthread/nptl/sysdeps/generic/sysdep.h new file mode 100644 index 000000000..9627b3e79 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/sysdep.h @@ -0,0 +1,137 @@ +/* Generic asm macros used on many machines. + Copyright (C) 1991,92,93,96,98,2002,2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef C_LABEL + +/* Define a macro we can use to construct the asm name for a C symbol. */ +#ifndef __UCLIBC_UNDERSCORES__ +#ifdef __STDC__ +#define C_LABEL(name) name##: +#else +#define C_LABEL(name) name/**/: +#endif +#else +#ifdef __STDC__ +#define C_LABEL(name) _##name##: +#else +#define C_LABEL(name) _/**/name/**/: +#endif +#endif + +#endif + +#ifdef __ASSEMBLER__ +/* Mark the end of function named SYM. This is used on some platforms + to generate correct debugging information. */ +#ifndef END +#define END(sym) +#endif + +#ifndef JUMPTARGET +#define JUMPTARGET(sym) sym +#endif + +/* Macros to generate eh_frame unwind information. */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +# define cfi_startproc .cfi_startproc +# define cfi_endproc .cfi_endproc +# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off +# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg +# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off +# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off +# define cfi_offset(reg, off) .cfi_offset reg, off +# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off +# define cfi_register(r1, r2) .cfi_register r1, r2 +# define cfi_return_column(reg) .cfi_return_column reg +# define cfi_restore(reg) .cfi_restore reg +# define cfi_same_value(reg) .cfi_same_value reg +# define cfi_undefined(reg) .cfi_undefined reg +# define cfi_remember_state .cfi_remember_state +# define cfi_restore_state .cfi_restore_state +# define cfi_window_save .cfi_window_save +# else +# define cfi_startproc +# define cfi_endproc +# define cfi_def_cfa(reg, off) +# define cfi_def_cfa_register(reg) +# define cfi_def_cfa_offset(off) +# define cfi_adjust_cfa_offset(off) +# define cfi_offset(reg, off) +# define cfi_rel_offset(reg, off) +# define cfi_register(r1, r2) +# define cfi_return_column(reg) +# define cfi_restore(reg) +# define cfi_same_value(reg) +# define cfi_undefined(reg) +# define cfi_remember_state +# define cfi_restore_state +# define cfi_window_save +# endif + +#else /* ! ASSEMBLER */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +# define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name) +# define CFI_STRINGIFY2(Name) #Name +# define CFI_STARTPROC ".cfi_startproc" +# define CFI_ENDPROC ".cfi_endproc" +# define CFI_DEF_CFA(reg, off) \ + ".cfi_def_cfa " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_DEF_CFA_REGISTER(reg) \ + ".cfi_def_cfa_register " CFI_STRINGIFY(reg) +# define CFI_DEF_CFA_OFFSET(off) \ + ".cfi_def_cfa_offset " CFI_STRINGIFY(off) +# define CFI_ADJUST_CFA_OFFSET(off) \ + ".cfi_adjust_cfa_offset " CFI_STRINGIFY(off) +# define CFI_OFFSET(reg, off) \ + ".cfi_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_REL_OFFSET(reg, off) \ + ".cfi_rel_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +# define CFI_REGISTER(r1, r2) \ + ".cfi_register " CFI_STRINGIFY(r1) "," CFI_STRINGIFY(r2) +# define CFI_RETURN_COLUMN(reg) \ + ".cfi_return_column " CFI_STRINGIFY(reg) +# define CFI_RESTORE(reg) \ + ".cfi_restore " CFI_STRINGIFY(reg) +# define CFI_UNDEFINED(reg) \ + ".cfi_undefined " CFI_STRINGIFY(reg) +# define CFI_REMEMBER_STATE \ + ".cfi_remember_state" +# define CFI_RESTORE_STATE \ + ".cfi_restore_state" +# define CFI_WINDOW_SAVE \ + ".cfi_window_save" +# else +# define CFI_STARTPROC +# define CFI_ENDPROC +# define CFI_DEF_CFA(reg, off) +# define CFI_DEF_CFA_REGISTER(reg) +# define CFI_DEF_CFA_OFFSET(off) +# define CFI_ADJUST_CFA_OFFSET(off) +# define CFI_OFFSET(reg, off) +# define CFI_REL_OFFSET(reg, off) +# define CFI_REGISTER(r1, r2) +# define CFI_RETURN_COLUMN(reg) +# define CFI_RESTORE(reg) +# define CFI_UNDEFINED(reg) +# define CFI_REMEMBER_STATE +# define CFI_RESTORE_STATE +# define CFI_WINDOW_SAVE +# endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/Makefile b/libpthread/nptl/sysdeps/i386/Makefile new file mode 100644 index 000000000..2f0d88f30 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 2002, 2003 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, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4 +endif diff --git a/libpthread/nptl/sysdeps/i386/Makefile.arch b/libpthread/nptl/sysdeps/i386/Makefile.arch new file mode 100644 index 000000000..2b9a2dc7c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = i486/pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-i386 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/i386/dl-tls.h b/libpthread/nptl/sysdeps/i386/dl-tls.h new file mode 100644 index 000000000..a1707197c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/dl-tls.h @@ -0,0 +1,60 @@ +/* Thread-local storage handling in the ELF dynamic linker. i386 version. + Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +#ifdef SHARED +/* This is the prototype for the GNU version. */ +extern void *___tls_get_addr (tls_index *ti) + __attribute__ ((__regparm__ (1))); +extern void *___tls_get_addr_internal (tls_index *ti) + __attribute__ ((__regparm__ (1))) attribute_hidden; + +# ifdef IS_IN_rtld +/* The special thing about the x86 TLS ABI is that we have two + variants of the __tls_get_addr function with different calling + conventions. The GNU version, which we are mostly concerned here, + takes the parameter in a register. The name is changed by adding + an additional underscore at the beginning. The Sun version uses + the normal calling convention. */ +void * +__tls_get_addr (tls_index *ti) +{ + return ___tls_get_addr_internal (ti); +} + + +/* Prepare using the definition of __tls_get_addr in the generic + version of this file. */ +# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr +strong_alias (___tls_get_addr, ___tls_get_addr_internal) +#else + +/* Users should get the better interface. */ +# define __tls_get_addr ___tls_get_addr + +# endif +#endif diff --git a/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S new file mode 100644 index 000000000..e30072c3d --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S @@ -0,0 +1,47 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 16 +pthread_spin_trylock: + movl 4(%esp), %edx + movl $1, %eax + xorl %ecx, %ecx + LOCK + cmpxchgl %ecx, (%edx) + movl $EBUSY, %eax +#ifdef HAVE_CMOV + cmovel %ecx, %eax +#else + jne 0f + movl %ecx, %eax +0: +#endif + ret + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S new file mode 100644 index 000000000..ffe3d456b --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/Makefile b/libpthread/nptl/sysdeps/i386/i686/Makefile new file mode 100644 index 000000000..137c0a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/Makefile @@ -0,0 +1,32 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +# 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, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),nptl) +# It turns out that stack coloring is in general not good on P4s. Some +# applications will benefit. We will probably have a configuration option +# at some point. Enabling coloring can be done with +# +# -DCOLORING_INCREMENT=128 +# +# What is useful is to avoid the 64k aliasing problem which reliably +# happens if all stacks use sizes which are a multiple of 64k. Tell +# the stack allocator to disturb this by allocation one more page if +# necessary. +CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536 +endif diff --git a/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S new file mode 100644 index 000000000..a5d861f92 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/tls.h b/libpthread/nptl/sysdeps/i386/i686/tls.h new file mode 100644 index 000000000..4025ed8d2 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/tls.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H + +/* Additional definitions for <tls.h> on i686 and up. */ + + +/* Macros to load from and store into segment registers. We can use + the 32-bit instructions. */ +#define TLS_GET_GS() \ + ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; }) +#define TLS_SET_GS(val) \ + __asm ("movl %0, %%gs" :: "q" (val)) + + +/* Get the full set of definitions. */ +#include "../tls.h" + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c new file mode 100644 index 000000000..da859cc9f --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + + +int +pthread_spin_lock (lock) + pthread_spinlock_t *lock; +{ + __asm__ ("\n" + "1:\t" LOCK_PREFIX "decl %0\n\t" + "jne 2f\n\t" + ".subsection 1\n\t" + ".align 16\n" + "2:\trep; nop\n\t" + "cmpl $0, %0\n\t" + "jg 1b\n\t" + "jmp 2b\n\t" + ".previous" + : "=m" (*lock) + : "m" (*lock)); + + return 0; +} diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..d94f1e7b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S @@ -0,0 +1,32 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl 4(%esp), %eax + movl $1, (%eax) + xorl %eax, %eax + ret + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/i386/pthreaddef.h b/libpthread/nptl/sysdeps/i386/pthreaddef.h new file mode 100644 index 000000000..81456a4fc --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthreaddef.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + while (1) { \ + if (__builtin_constant_p (val) && (val) == 0) \ + __asm__ volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit)); \ + else \ + __asm__ volatile ("movl %1, %%ebx; int $0x80" \ + :: "a" (__NR_exit), "r" (val)); \ + } diff --git a/libpthread/nptl/sysdeps/i386/sysdep.h b/libpthread/nptl/sysdeps/i386/sysdep.h new file mode 100644 index 000000000..7f278905f --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/sysdep.h @@ -0,0 +1,156 @@ +/* Assembler macros for i386. + Copyright (C) 1991-93,95,96,98,2002,2003,2005,2006 + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols. */ +#undef NO_UNDERSCORES +#define NO_UNDERSCORES + +/* Define an entry point visible from C. + + There is currently a bug in gdb which prevents us from specifying + incomplete stabs information. Fake some entries here which specify + the current source file. */ +#define ENTRY(name) \ + STABS_CURRENT_FILE1("") \ + STABS_CURRENT_FILE(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(4); \ + STABS_FUN(name) \ + C_LABEL(name) \ + cfi_startproc; \ + CALL_MCOUNT + +#undef END +#define END(name) \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(name) \ + STABS_FUN_END(name) + +#ifdef HAVE_CPP_ASM_DEBUGINFO +/* Disable that goop, because we just pass -g through to the assembler + and it generates proper line number information directly. */ +# define STABS_CURRENT_FILE1(name) +# define STABS_CURRENT_FILE(name) +# define STABS_FUN(name) +# define STABS_FUN_END(name) +#else +/* Remove the following two lines once the gdb bug is fixed. */ +#define STABS_CURRENT_FILE(name) \ + STABS_CURRENT_FILE1 (#name) +#define STABS_CURRENT_FILE1(name) \ + 1: .stabs name,100,0,0,1b; +/* Emit stabs definition lines. We use F(0,1) and define t(0,1) as `int', + the same way gcc does it. */ +#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1)) +#define STABS_FUN2(name, namestr) \ + .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0; \ + .stabs #namestr,36,0,0,name; +#define STABS_FUN_END(name) \ + 1: .stabs "",36,0,0,1b-name; +#endif + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +/* The mcount code relies on a normal frame pointer being on the stack + to locate our caller, so push one just for its benefit. */ +#define CALL_MCOUNT \ + pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \ + cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \ + popl %ebp; cfi_def_cfa (esp, 4); +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#define PSEUDO(name, syscall_name, args) \ + .globl syscall_error; \ +lose: SYSCALL_PIC_SETUP \ + jmp JUMPTARGET(syscall_error); \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + jb lose + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + END (name) + +#undef JUMPTARGET +#ifdef PIC +#define JUMPTARGET(name) name##@PLT +#define SYSCALL_PIC_SETUP \ + pushl %ebx; \ + cfi_adjust_cfa_offset (4); \ + call 0f; \ +0: popl %ebx; \ + cfi_adjust_cfa_offset (-4); \ + addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx; + +# define SETUP_PIC_REG(reg) \ + .ifndef __i686.get_pc_thunk.reg; \ + .section .gnu.linkonce.t.__i686.get_pc_thunk.reg,"ax",@progbits; \ + .globl __i686.get_pc_thunk.reg; \ + .hidden __i686.get_pc_thunk.reg; \ + .type __i686.get_pc_thunk.reg,@function; \ +__i686.get_pc_thunk.reg: \ + movl (%esp), %e##reg; \ + ret; \ + .size __i686.get_pc_thunk.reg, . - __i686.get_pc_thunk.reg; \ + .previous; \ + .endif; \ + call __i686.get_pc_thunk.reg + +# define LOAD_PIC_REG(reg) \ + SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg + +#else +#define JUMPTARGET(name) name +#define SYSCALL_PIC_SETUP /* Nothing. */ +#endif + +/* Local label name for asm code. */ +#ifndef L +#ifdef HAVE_ELF +#define L(name) .L##name +#else +#define L(name) name +#endif +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/tcb-offsets.sym b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym new file mode 100644 index 000000000..4e0444ba3 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym @@ -0,0 +1,13 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +SYSINFO_OFFSET offsetof (tcbhead_t, sysinfo) +CLEANUP offsetof (struct pthread, cleanup) +CLEANUP_PREV offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/i386/tls.h b/libpthread/nptl/sysdeps/i386/tls.h new file mode 100644 index 000000000..52bde9eec --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tls.h @@ -0,0 +1,429 @@ +/* Definition for thread-local data handling. nptl/i386 version. + Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessarily the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Alignment requirement for the stack. For IA-32 this is governed by + the SSE memory functions. */ +#define STACK_ALIGN 16 + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +/* The old way: using LDT. */ + +/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls. */ +struct user_desc +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* Initializing bit fields is slow. We speed it up by using a union. */ +union user_desc_init +{ + struct user_desc desc; + unsigned int vals[4]; +}; + + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* Get the thread descriptor definition. */ +#include <descr.h> + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ struct pthread *__pd; \ + THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +#define THREAD_SELF_SYSINFO THREAD_GETMEM (THREAD_SELF, header.sysinfo) +#define THREAD_SYSINFO(pd) ((pd)->header.sysinfo) + +/* Macros to load from and store into segment registers. */ +# ifndef TLS_GET_GS +# define TLS_GET_GS() \ + ({ int __seg; __asm__ ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; }) +# endif +# ifndef TLS_SET_GS +# define TLS_SET_GS(val) \ + __asm__ ("movw %w0, %%gs" :: "q" (val)) +# endif + + +# ifndef __NR_set_thread_area +# define __NR_set_thread_area 243 +# endif +# ifndef TLS_FLAG_WRITABLE +# define TLS_FLAG_WRITABLE 0x00000001 +# endif + +// XXX Enable for the real world. +#if 0 +# ifndef __ASSUME_SET_THREAD_AREA +# error "we need set_thread_area" +# endif +#endif + +# ifdef __PIC__ +# define TLS_EBX_ARG "r" +# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" +# else +# define TLS_EBX_ARG "b" +# define TLS_LOAD_EBX +# endif + +#if defined NEED_DL_SYSINFO +# define INIT_SYSINFO \ + _head->sysinfo = GLRO(dl_sysinfo) +#else +# define INIT_SYSINFO +#endif + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(thrdescr, secondcall) \ + ({ void *_thrdescr = (thrdescr); \ + tcbhead_t *_head = _thrdescr; \ + union user_desc_init _segdescr; \ + int _result; \ + \ + _head->tcb = _thrdescr; \ + /* For now the thread descriptor is at the same address. */ \ + _head->self = _thrdescr; \ + /* New syscall handling support. */ \ + INIT_SYSINFO; \ + \ + /* The 'entry_number' field. Let the kernel pick a value. */ \ + if (secondcall) \ + _segdescr.vals[0] = TLS_GET_GS () >> 3; \ + else \ + _segdescr.vals[0] = -1; \ + /* The 'base_addr' field. Pointer to the TCB. */ \ + _segdescr.vals[1] = (unsigned long int) _thrdescr; \ + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \ + _segdescr.vals[2] = 0xfffff; \ + /* Collapsed value of the bitfield: \ + .seg_32bit = 1 \ + .contents = 0 \ + .read_exec_only = 0 \ + .limit_in_pages = 1 \ + .seg_not_present = 0 \ + .useable = 1 */ \ + _segdescr.vals[3] = 0x51; \ + \ + /* Install the TLS. */ \ + __asm__ volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (_result), "=m" (_segdescr.desc.entry_number) \ + : "0" (__NR_set_thread_area), \ + TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \ + \ + if (_result == 0) \ + /* We know the index in the GDT, now load the segment register. \ + The use of the GDT is described by the value 3 in the lower \ + three bits of the segment descriptor value. \ + \ + Note that we have to do this even if the numeric value of \ + the descriptor does not change. Loading the segment register \ + causes the segment information from the GDT to be loaded \ + which is necessary since we have changed it. */ \ + TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3); \ + \ + _result == 0 ? NULL \ + : "set_thread_area failed when setting up thread-local storage\n"; }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct pthread *__pd; \ + THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__self; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct pthread, header.self))); \ + __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \ + REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */ + + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) \ + ({ __typeof (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%gs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member))); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%gs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%gs:%P1,%%eax\n\t" \ + "movl %%gs:%P2,%%edx" \ + : "=A" (__value) \ + : "i" (offsetof (struct pthread, member)), \ + "i" (offsetof (struct pthread, member) + 4)); \ + } \ + __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ({ __typeof (descr->member[0]) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%gs:%P2(%3),%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%gs:%P1(,%2,4),%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \ + "movl %%gs:4+%P1(,%2,8),%%edx" \ + : "=&A" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + } \ + __value; }) + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM(descr, member, value) \ + ({ if (sizeof (descr->member) == 1) \ + __asm__ volatile ("movb %b0,%%gs:%P1" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member))); \ + else if (sizeof (descr->member) == 4) \ + __asm__ volatile ("movl %0,%%gs:%P1" : \ + : "ir" (value), \ + "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (descr->member) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%eax,%%gs:%P1\n\t" \ + "movl %%edx,%%gs:%P2" : \ + : "A" (value), \ + "i" (offsetof (struct pthread, member)), \ + "i" (offsetof (struct pthread, member) + 4)); \ + }}) + + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ({ if (sizeof (descr->member[0]) == 1) \ + __asm__ volatile ("movb %b0,%%gs:%P1(%2)" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + else if (sizeof (descr->member[0]) == 4) \ + __asm__ volatile ("movl %0,%%gs:%P1(,%2,4)" : \ + : "ir" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (descr->member[0]) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \ + "movl %%edx,%%gs:4+%P1(,%2,8)" : \ + : "A" (value), \ + "i" (offsetof (struct pthread, member)), \ + "r" (idx)); \ + }}) + + +/* Atomic compare and exchange on TLS, returning old value. */ +#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ + ({ __typeof (descr->member) __ret; \ + __typeof (oldval) __old = (oldval); \ + if (sizeof (descr->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3" \ + : "=a" (__ret) \ + : "0" (__old), "r" (newval), \ + "i" (offsetof (struct pthread, member))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); \ + __ret; }) + + +/* Atomic set bit. */ +#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "orl %1, %%gs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (1 << (bit))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +/* Call the user-provided thread function. */ +#define CALL_THREAD_FCT(descr) \ + ({ void *__res; \ + int __ignore1, __ignore2; \ + __asm__ volatile ("pushl %%eax\n\t" \ + "pushl %%eax\n\t" \ + "pushl %%eax\n\t" \ + "pushl %%gs:%P4\n\t" \ + "call *%%gs:%P3\n\t" \ + "addl $16, %%esp" \ + : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2) \ + : "i" (offsetof (struct pthread, start_routine)), \ + "i" (offsetof (struct pthread, arg))); \ + __res; }) + + +/* Set the stack guard field in TCB head. */ +#define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +#define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/mips/Makefile b/libpthread/nptl/sysdeps/mips/Makefile new file mode 100644 index 000000000..6371d2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/mips/Makefile.arch b/libpthread/nptl/sysdeps/mips/Makefile.arch new file mode 100644 index 000000000..5d77b0074 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/Makefile.arch @@ -0,0 +1,65 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S \ + nptl-sysdep.S + +libc_a_CSRC = libc-tls.c + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-nptl-sysdep.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/mips + +CFLAGS-mips = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +LIBC_ARCH_OBJ := $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y += $(LIBC_ARCH_OBJ) + +libc-nomulti-y += $(LIBC_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + awk -f $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.s \ + $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: + $(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/mips/dl-tls.h b/libpthread/nptl/sysdeps/mips/dl-tls.h new file mode 100644 index 000000000..6d3ed6f5a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/dl-tls.h @@ -0,0 +1,46 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block. */ +#define TLS_TP_OFFSET 0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each + TLS block. */ +#define TLS_DTV_OFFSET 0x8000 + +/* Compute the value for a GOTTPREL reloc. */ +#define TLS_TPREL_VALUE(sym_map, sym) \ + ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET) + +/* Compute the value for a DTPREL reloc. */ +#define TLS_DTPREL_VALUE(sym) \ + ((sym)->st_value - TLS_DTV_OFFSET) + +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) diff --git a/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h new file mode 100644 index 000000000..a9cfe43b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj)) + +/* We use the normal longjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/mips/libc-tls.c b/libpthread/nptl/sysdeps/mips/libc-tls.c new file mode 100644 index 000000000..fdedc9f5a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker. MIPS version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <../generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On MIPS, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET; +} + +#endif diff --git a/libpthread/nptl/sysdeps/mips/nptl-sysdep.S b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S new file mode 100644 index 000000000..7a4a8d311 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S @@ -0,0 +1,2 @@ +/* Pull in __syscall_error. */ +#include <syscall_error.S> diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S new file mode 100644 index 000000000..e35c381ed --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S @@ -0,0 +1,38 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/asm.h> +#include <sysdep.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_lock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif +1: ll a2, 0(a0) + li a1, 1 + bnez a2, 1b + sc a1, 0(a0) + beqz a1, 1b + MIPS_SYNC + .set pop + li v0, 0 + j ra + nop +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S new file mode 100644 index 000000000..b54732869 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S @@ -0,0 +1,43 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sys/asm.h> +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_trylock) + .set push +#if _MIPS_SIM == _ABIO32 + .set mips2 +#endif + ll a2, 0(a0) + li a1, 1 + bnez a2, 1f + sc a1, 0(a0) + beqz a1, 1f + MIPS_SYNC + .set pop + li v0, 0 + j ra + nop +1: li v0, EBUSY + j ra + nop +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/mips/pthreaddef.h b/libpthread/nptl/sysdeps/mips/pthreaddef.h new file mode 100644 index 000000000..e72b4bc58 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/mips/regdef.h b/libpthread/nptl/sysdeps/mips/regdef.h new file mode 100644 index 000000000..a462d512a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/regdef.h @@ -0,0 +1,26 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ralf Baechle <ralf@gnu.org>. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _REGDEF_H +#define _REGDEF_H + +#include <sys/regdef.h> +#include <sys/fpregdef.h> + +#endif /* _REGDEF_H */ diff --git a/libpthread/nptl/sysdeps/mips/sysdep.h b/libpthread/nptl/sysdeps/mips/sysdep.h new file mode 100644 index 000000000..69cecae70 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/sysdep.h @@ -0,0 +1,110 @@ +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Brendan Kehoe (brendan@zen.org). + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sgidefs.h> +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +#include <regdef.h> + +#define ENTRY(name) \ + .globl name; \ + .align 2; \ + .ent name,0; \ + name##: + +#undef END +#define END(function) \ + .end function; \ + .size function,.-function + +#define ret j ra ; nop + +#undef PSEUDO_END +#define PSEUDO_END(sym) .end sym; .size sym,.-sym + +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .align 2; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) .end sym; .size sym,.-sym + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .align 2; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) .end sym; .size sym,.-sym + +#define ret_ERRVAL ret + +#define r0 v0 +#define r1 v1 +/* The mips move insn is d,s. */ +#define MOVE(x,y) move y , x + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +/* Note that while it's better structurally, going back to call __syscall_error + can make things confusing if you're debugging---it looks like it's jumping + backwards into the previous fn. */ +#ifdef __PIC__ +#define PSEUDO(name, syscall_name, args) \ + .align 2; \ + 99: la t9,__syscall_error; \ + jr t9; \ + ENTRY(name) \ + .set noreorder; \ + .cpload t9; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, 99b; \ +L(syse1): +#else +#define PSEUDO(name, syscall_name, args) \ + .set noreorder; \ + .align 2; \ + 99: j __syscall_error; \ + nop; \ + ENTRY(name) \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, 99b; \ +L(syse1): +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/mips/tcb-offsets.sym b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym new file mode 100644 index 000000000..e0e71dc43 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +PID_OFFSET thread_offsetof (pid) +TID_OFFSET thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/mips/tls.h b/libpthread/nptl/sysdeps/mips/tls.h new file mode 100644 index 000000000..0a83ac672 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tls.h @@ -0,0 +1,159 @@ +/* Definition for thread-local data handling. NPTL/MIPS version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +/* Note: rd must be $v1 to be ABI-conformant. */ +# define READ_THREAD_POINTER() \ + ({ void *__result; \ + __asm__ __volatile__ (".set\tpush\n\t.set\tmips32r2\n\t" \ + "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result)); \ + __result; }) + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> + +# define READ_THREAD_POINTER(rd) \ + .set push; \ + .set mips32r2; \ + rdhwr rd, $29; \ + .set pop +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +#define HAVE___THREAD 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +#include <../../descr.h> + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. Because our TCB is before the thread + pointer, we don't need this. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size we need before TCB - actually, it includes the TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct pthread) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The thread pointer (in hardware register $29) points to the end of + the TCB + 0x7000, as for PowerPC. The pthread_descr structure is + immediately in front of the TCB. */ +# define TLS_TCB_OFFSET 0x7000 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL (set_thread_area, err, 1, \ + (char *) (tcbp) + TLS_TCB_OFFSET); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (READ_THREAD_POINTER () \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Access to data in the thread descriptor is easy. */ +# define THREAD_GETMEM(descr, member) \ + descr->member +# define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +# define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/powerpc/Makefile b/libpthread/nptl/sysdeps/powerpc/Makefile new file mode 100644 index 000000000..3af245600 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/Makefile @@ -0,0 +1,21 @@ +# Copyright (C) 2003 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, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/powerpc/dl-tls.h b/libpthread/nptl/sysdeps/powerpc/dl-tls.h new file mode 100644 index 000000000..957d4b4b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/dl-tls.h @@ -0,0 +1,49 @@ +/* Thread-local storage handling in the ELF dynamic linker. PowerPC version. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the TOC. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block. */ +#define TLS_TP_OFFSET 0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each + TLS block. */ +#define TLS_DTV_OFFSET 0x8000 + +/* Compute the value for a @tprel reloc. */ +#define TLS_TPREL_VALUE(sym_map, sym, reloc) \ + ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend \ + - TLS_TP_OFFSET) + +/* Compute the value for a @dtprel reloc. */ +#define TLS_DTPREL_VALUE(sym, reloc) \ + ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET) + +#ifdef SHARED +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET) +#endif diff --git a/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h new file mode 100644 index 000000000..0b817160d --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_GPR1] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c new file mode 100644 index 000000000..e2293fda1 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (lock) + pthread_spinlock_t *lock; +{ + unsigned int __tmp; + + asm volatile ( + "1: lwarx %0,0,%1\n" + " cmpwi 0,%0,0\n" + " bne- 2f\n" + " stwcx. %2,0,%1\n" + " bne- 2f\n" + " isync\n" + " .subsection 1\n" + "2: lwzx %0,0,%1\n" + " cmpwi 0,%0,0\n" + " bne 2b\n" + " b 1b\n" + " .previous" + : "=&r" (__tmp) + : "r" (lock), "r" (1) + : "cr0", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c new file mode 100644 index 000000000..d8e1dbcc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (lock) + pthread_spinlock_t *lock; +{ + unsigned int old; + int err = EBUSY; + + asm ("1: lwarx %0,0,%2\n" + " cmpwi 0,%0,0\n" + " bne 2f\n" + " stwcx. %3,0,%2\n" + " bne- 1b\n" + " li %1,0\n" + " isync\n" + "2: " + : "=&r" (old), "=&r" (err) + : "r" (lock), "r" (1), "1" (err) + : "cr0", "memory"); + + return err; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthreaddef.h b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h new file mode 100644 index 000000000..342c15c67 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. The ABI requires 16 + bytes (for both 32-bit and 64-bit PowerPC). */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym new file mode 100644 index 000000000..3962edbd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym @@ -0,0 +1,16 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +# undef __thread_register +# define __thread_register ((void *) 0) +# define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) + + +#if TLS_MULTIPLE_THREADS_IN_TCB +MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +#endif +PID thread_offsetof (pid) +TID thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/powerpc/tls.h b/libpthread/nptl/sysdeps/powerpc/tls.h new file mode 100644 index 000000000..1157116a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tls.h @@ -0,0 +1,173 @@ +/* Definition for thread-local data handling. NPTL/PowerPC version. + Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* We use the multiple_threads field in the pthread struct */ +#define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. */ +# include <nptl/descr.h> + +/* The stack_guard is accessed directly by GCC -fstack-protector code, + so it is a part of public ABI. The dtv field is private. */ +typedef struct +{ + uintptr_t stack_guard; + dtv_t *dtv; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE 0 + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE 0 + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE \ + (sizeof (struct pthread) \ + + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +# ifndef __powerpc64__ +/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r2"); +# define PT_THREAD_POINTER PT_R2 +# else +/* Register r13 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r13"); +# define PT_THREAD_POINTER PT_R13 +# endif + +/* The following assumes that TP (R2 or R13) points to the end of the + TCB + 0x7000 (per the ABI). This implies that TCB address is + TP - 0x7000. As we define TLS_DTV_AT_TP we can + assume that the pthread struct is allocated immediately ahead of the + TCB. This implies that the pthread_descr address is + TP - (TLS_PRE_TCB_SIZE + 0x7000). */ +# define TLS_TCB_OFFSET 0x7000 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (__thread_register \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (32, 32, PT_THREAD_POINTER * 4, \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) \ + REGISTER (64, 64, PT_THREAD_POINTER * 8, \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ((void)(descr), (THREAD_SELF)->member[idx]) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ + ((void)(descr), (THREAD_SELF)->member = (value)) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ((void)(descr), (THREAD_SELF)->member[idx] = (value)) + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + (((tcbhead_t *) ((char *) __thread_register \ + - TLS_TCB_OFFSET))[-1].stack_guard = (value)) +# define THREAD_COPY_STACK_GUARD(descr) \ + (((tcbhead_t *) ((char *) (descr) \ + + TLS_PRE_TCB_SIZE))[-1].stack_guard \ + = ((tcbhead_t *) ((char *) __thread_register \ + - TLS_TCB_OFFSET))[-1].stack_guard) + +/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some + different value to mean unset l_tls_offset. */ +# define NO_TLS_OFFSET -1 + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/pthread/Makefile b/libpthread/nptl/sysdeps/pthread/Makefile new file mode 100644 index 000000000..a30ded527 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/pthread/Makefile.in b/libpthread/nptl/sysdeps/pthread/Makefile.in new file mode 100644 index 000000000..2a825329a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile.in @@ -0,0 +1,146 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005-2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# +# NOTE: glibc puts flockfile.c, ftrylockfile.c, funlockfile.c, and +# pt-longjmp.c in libc and libpthread. For uClibc, they are +# in libc only. +# +libpthread_CSRC = pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c pthread_cond_timedwait.c \ + pthread_cond_wait.c pthread_rwlock_rdlock.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c \ + pthread_rwlock_wrlock.c pthread_sigmask.c \ + pthread_spin_destroy.c pthread_spin_init.c \ + pthread_spin_unlock.c pt-sigfillset.c \ + pt-longjmp.c + + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ + pthread_cond_wait.c pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c pthread_cond_timedwait.c pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \ + pthread_rwlock_rdlock.c + +libpthread_CSRC := $(filter-out $(X86_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ + pthread_rwlock_wrlock.c pthread_rwlock_rdlock.c \ + pthread_rwlock_unlock.c pt-longjmp.c \ + pthread_barrier_wait.c pthread_cond_broadcast.c \ + pthread_cond_signal.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_timedwrlock.c + +libpthread_CSRC := $(filter-out $(SH_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),x86_64) +libpthread_CSRC += pthread_once.c +endif + + +CFLAGS-pt-common = -DNOT_IN_libc=1 $(SSP_ALL_CFLAGS) + +CFLAGS-pthread_barrier_wait.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_broadcast.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_signal.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_timedwait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_wait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_rdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedrdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedwrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_unlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_wrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_sigmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_destroy.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_init.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_unlock.c = -D_GNU_SOURCE $(CFLAGS-pt-common) \ + -DIS_IN_libpthread=1 +CFLAGS-pt-sigaction.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \ + -I$(top_srcdir)libc/signal +CFLAGS-pt-sigfillset.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/signal +CFLAGS-pt-sigprocmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 \ + -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-unwind-forcedunwind.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 -fexceptions -fasynchronous-unwind-tables +CFLAGS-librt-cancellation.c = -DIS_IN_librt=1 $(CFLAGS-pt-common) \ + -fexceptions -fasynchronous-unwind-tables +CFLAGS-rt-unwind-resume.c = -DIS_IN_librt=1 $(CFLAGS-pt-common) \ + -fexceptions -fasynchronous-unwind-tables + +#CFLAGS:=$(CFLAGS:-O1=-O2) + +pthread_DIR := $(top_srcdir)libpthread/nptl/sysdeps/pthread +pthread_OUT := $(top_builddir)libpthread/nptl/sysdeps/pthread + +pthread_SRC = $(patsubst %.c, $(pthread_DIR)/%.c, $(libpthread_CSRC)) +pthread_OBJ = $(patsubst %.c, $(pthread_OUT)/%.o, $(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(pthread_OBJ:.o=.os) +else +libpthread-a-y += $(pthread_OBJ) +endif +libpthread-so-y += $(pthread_OBJ:.o=.oS) +libpthread-so-y += $(pthread_OUT)/pt-sigaction.oS $(pthread_OUT)/pt-sigprocmask.oS \ + $(pthread_OUT)/unwind-forcedunwind.oS + +CFLAGS-sigaction.c = -I$(top_srcdir)libc/signal +libc-y += $(pthread_OUT)/sigaction.o + +librt-a-y += $(pthread_OUT)/librt-cancellation.o +librt-so-y += $(pthread_OUT)/librt-cancellation.oS \ + $(pthread_OUT)/rt-unwind-resume.oS + +ifeq ($(UCLIBC_CTOR_DTOR),y) +CFLAGS-pt-initfini.c = -S -g0 -fPIC -fno-inline-functions \ + $(call check_gcc,-fno-unit-at-a-time,) \ + -finhibit-size-directive \ + $(patsubst -f%,-fno-%,$(call check_gcc,-fexceptions,)) +ASFLAGS-crti.S = -g0 +ASFLAGS-crtn.S = -g0 + +$(pthread_OUT)/pt-initfini.s: $(pthread_DIR)/pt-initfini.c + $(compile.c) + sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \ + awk -f $(pthread_DIR)/defs.awk > $(pthread_OUT)/defs.h + +$(pthread_OUT)/crti.S: $(pthread_OUT)/pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ + +$(pthread_OUT)/crtn.S: $(pthread_OUT)/pt-initfini.s + sed -n -e '1,/@HEADER_ENDS/p' \ + -e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \ + -e '/@TRAILER_BEGINS/,$$p' $< > $@ +endif + +$(pthread_DIR)/pt-sigaction.c: + $(LN) -s sigaction.c $@ + +$(pthread_DIR)/pt-sigfillset.c: + $(LN) -s sigfillset.c $@ + +$(pthread_DIR)/pt-sigprocmask.c: + $(LN) -s sigprocmask.c $@ + +objclean-y += nptl_pthread_clean + +nptl_pthread_clean: + $(do_rm) $(addprefix $(pthread_OUT)/*., o os oS s S) $(pthread_OUT)/defs.h \ + $(pthread_DIR)/pt-sigaction.c $(pthread_DIR)/pt-sigfillset.c \ + $(pthread_DIR)/pt-sigprocmask.c diff --git a/libpthread/nptl/sysdeps/pthread/allocalim.h b/libpthread/nptl/sysdeps/pthread/allocalim.h new file mode 100644 index 000000000..35224ec74 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/allocalim.h @@ -0,0 +1,29 @@ +/* Determine whether block of given size can be allocated on the stack or not. + Copyright (C) 2002 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <alloca.h> +#include <limits.h> + + +extern inline int +__libc_use_alloca (size_t size) +{ + return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1) + || __libc_alloca_cutoff (size)); +} diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 000000000..c59e3a0cc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,566 @@ +/* libc-internal interface for mutex locks. NPTL version. + Copyright (C) 1996-2001, 2002, 2003, 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_LIBC_LOCK_H +#define _BITS_LIBC_LOCK_H 1 + +#include <pthread.h> +#define __need_NULL +#include <stddef.h> + + +/* Fortunately Linux now has a mean to do locking which is realtime + safe without the aid of the thread library. We also need no fancy + options like error checking mutexes etc. We only need simple + locks, maybe recursive. This can be easily and cheaply implemented + using futexes. We will use them everywhere except in ld.so since + ld.so might be used on old kernels with a different libc.so. */ +#ifdef _LIBC +# include <lowlevellock.h> +# include <tls.h> +# include <pthread-functions.h> +#endif + +/* Mutex type. */ +#if defined _LIBC || defined _IO_MTSAFE_IO +# if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC +typedef pthread_mutex_t __libc_lock_t; +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# else +typedef int __libc_lock_t; +typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; +# endif +typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +#else +typedef struct __libc_lock_opaque__ __libc_lock_t; +typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +#endif + +/* Type for key to thread-specific data. */ +typedef pthread_key_t __libc_key_t; + +/* Define a lock variable NAME with storage class CLASS. The lock must be + initialized with __libc_lock_init before it can be used (or define it + with __libc_lock_define_initialized, below). Use `extern' for CLASS to + declare a lock defined in another module. In public structure + definitions you must use a pointer to the lock structure (i.e., NAME + begins with a `*'), because its storage size will not be known outside + of libc. */ +#define __libc_lock_define(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +#define __libc_rwlock_define(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME; +#define __libc_lock_define_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; +#define __rtld_lock_define_recursive(CLASS,NAME) \ + CLASS __rtld_lock_recursive_t NAME; + +/* Define an initialized lock variable NAME with storage class CLASS. + + For the C library we take a deeper look at the initializer. For + this implementation all fields are initialized to zero. Therefore + we don't initialize the variable which allows putting it into the + BSS section. (Except on PA-RISC and other odd architectures, where + initialized locks must be set to one due to the lack of normal + atomic operations.) */ + +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +# else +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME = LLL_LOCK_INITIALIZER; +# endif +#else +# if __LT_SPINLOCK_INIT == 0 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +# else +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; +# endif +#endif + +#define __libc_rwlock_define_initialized(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; + +/* Define an initialized recursive lock variable NAME with storage + class CLASS. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; +# else +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# endif +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ + { LLL_LOCK_INITIALIZER, 0, NULL } +#else +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ + {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} +#endif + +#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER; +#define _RTLD_LOCK_RECURSIVE_INITIALIZER \ + {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} + +#define __rtld_lock_initialize(NAME) \ + (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER) + +/* If we check for a weakly referenced symbol and then perform a + normal jump to it te code generated for some platforms in case of + PIC is unnecessarily slow. What would happen is that the function + is first referenced as data and then it is called indirectly + through the PLT. We can make this a direct jump. */ +#ifdef __PIC__ +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ + (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \ + _fn != NULL ? (*_fn) ARGS : ELSE; })) +#else +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ + (FUNC != NULL ? FUNC ARGS : ELSE) +#endif + +/* Call thread functions through the function pointer table. */ +#if defined SHARED && !defined NOT_IN_libc +# define PTF(NAME) __libc_pthread_functions.ptr_##NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ + (PTF(FUNC) != NULL ? PTF(FUNC) ARGS : ELSE) +#else +# define PTF(NAME) NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ + __libc_maybe_call (FUNC, ARGS, ELSE) +#endif + + +/* Initialize the named lock variable, leaving it in a consistent, unlocked + state. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init(NAME) ((NAME) = LLL_LOCK_INITIALIZER, 0) +#else +# define __libc_lock_init(NAME) \ + __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0) +#endif +#define __libc_rwlock_init(NAME) \ + __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0) + +/* Same as last but this time we initialize a recursive mutex. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init_recursive(NAME) \ + ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER, 0) +#else +# define __libc_lock_init_recursive(NAME) \ + do { \ + if (__pthread_mutex_init != NULL) \ + { \ + pthread_mutexattr_t __attr; \ + __pthread_mutexattr_init (&__attr); \ + __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + __pthread_mutex_init (&(NAME).mutex, &__attr); \ + __pthread_mutexattr_destroy (&__attr); \ + } \ + } while (0) +#endif + +#define __rtld_lock_init_recursive(NAME) \ + do { \ + if (__pthread_mutex_init != NULL) \ + { \ + pthread_mutexattr_t __attr; \ + __pthread_mutexattr_init (&__attr); \ + __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + __pthread_mutex_init (&(NAME).mutex, &__attr); \ + __pthread_mutexattr_destroy (&__attr); \ + } \ + } while (0) + +/* Finalize the named lock variable, which must be locked. It cannot be + used again until __libc_lock_init is called again on it. This must be + called on a lock variable before the containing storage is reused. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini(NAME) ((void) 0) +#else +# define __libc_lock_fini(NAME) \ + __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif +#define __libc_rwlock_fini(NAME) \ + __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0) + +/* Finalize recursive named lock. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini_recursive(NAME) ((void) 0) +#else +# define __libc_lock_fini_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif + +/* Lock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock(NAME) \ + ({ lll_lock (NAME); 0; }) +#else +# define __libc_lock_lock(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0) +#endif +#define __libc_rwlock_rdlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_rdlock, (&(NAME)), 0) +#define __libc_rwlock_wrlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_wrlock, (&(NAME)), 0) + +/* Lock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock_recursive(NAME) \ + do { \ + void *self = THREAD_SELF; \ + if ((NAME).owner != self) \ + { \ + lll_lock ((NAME).lock); \ + (NAME).owner = self; \ + } \ + ++(NAME).cnt; \ + } while (0) +#else +# define __libc_lock_lock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) +#endif + +/* Try to lock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock(NAME) \ + lll_trylock (NAME) +#else +# define __libc_lock_trylock(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif +#define __libc_rwlock_tryrdlock(NAME) \ + __libc_maybe_call (__pthread_rwlock_tryrdlock, (&(NAME)), 0) +#define __libc_rwlock_trywrlock(NAME) \ + __libc_maybe_call (__pthread_rwlock_trywrlock, (&(NAME)), 0) + +/* Try to lock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock_recursive(NAME) \ + ({ \ + int result = 0; \ + void *self = THREAD_SELF; \ + if ((NAME).owner != self) \ + { \ + if (lll_trylock ((NAME).lock) == 0) \ + { \ + (NAME).owner = self; \ + (NAME).cnt = 1; \ + } \ + else \ + result = EBUSY; \ + } \ + else \ + ++(NAME).cnt; \ + result; \ + }) +#else +# define __libc_lock_trylock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif + +#define __rtld_lock_trylock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) + +/* Unlock the named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_unlock(NAME) \ + lll_unlock (NAME) +#else +# define __libc_lock_unlock(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif +#define __libc_rwlock_unlock(NAME) \ + __libc_ptf_call (__pthread_rwlock_unlock, (&(NAME)), 0) + +/* Unlock the recursive named lock variable. */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +/* We do no error checking here. */ +# define __libc_lock_unlock_recursive(NAME) \ + do { \ + if (--(NAME).cnt == 0) \ + { \ + (NAME).owner = NULL; \ + lll_unlock ((NAME).lock); \ + } \ + } while (0) +#else +# define __libc_lock_unlock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif + +#if defined _LIBC && defined SHARED +# define __rtld_lock_default_lock_recursive(lock) \ + ++((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_default_unlock_recursive(lock) \ + --((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_lock_recursive(NAME) \ + GL(dl_rtld_lock_recursive) (&(NAME).mutex) + +# define __rtld_lock_unlock_recursive(NAME) \ + GL(dl_rtld_unlock_recursive) (&(NAME).mutex) +#else +# define __rtld_lock_lock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) + +# define __rtld_lock_unlock_recursive(NAME) \ + __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0) +#endif + +/* Define once control variable. */ +#if PTHREAD_ONCE_INIT == 0 +/* Special case for static variables where we can avoid the initialization + if it is zero. */ +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME +#else +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT +#endif + +/* Call handler iff the first call. */ +#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \ + do { \ + if (PTF(__pthread_once) != NULL) \ + PTF(__pthread_once) (&(ONCE_CONTROL), INIT_FUNCTION); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) |= 2; \ + } \ + } while (0) + + +/* Note that for I/O cleanup handling we are using the old-style + cancel handling. It does not have to be integrated with C++ snce + no C++ code is called in the middle. The old-style handling is + faster and the support is not going away. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, + int execute); +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, + void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, + int execute); + +/* Start critical region with cleanup. */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ + { struct _pthread_cleanup_buffer _buffer; \ + int _avail; \ + if (DOIT) { \ + _avail = PTF(_pthread_cleanup_push_defer) != NULL; \ + if (_avail) { \ + PTF(_pthread_cleanup_push_defer) (&_buffer, FCT, ARG); \ + } else { \ + _buffer.__routine = (FCT); \ + _buffer.__arg = (ARG); \ + } \ + } else { \ + _avail = 0; \ + } + +/* End critical region with cleanup. */ +#define __libc_cleanup_region_end(DOIT) \ + if (_avail) { \ + PTF(_pthread_cleanup_pop_restore) (&_buffer, DOIT); \ + } else if (DOIT) \ + _buffer.__routine (_buffer.__arg); \ + } + +/* Sometimes we have to exit the block in the middle. */ +#define __libc_cleanup_end(DOIT) \ + if (_avail) { \ + PTF(_pthread_cleanup_pop_restore) (&_buffer, DOIT); \ + } else if (DOIT) \ + _buffer.__routine (_buffer.__arg) + + +/* Normal cleanup handling, based on C cleanup attribute. */ +__extern_inline void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f); + +__extern_inline void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ + if (f->__do_it) + f->__cancel_routine (f->__cancel_arg); +} + +#define __libc_cleanup_push(fct, arg) \ + do { \ + struct __pthread_cleanup_frame __clframe \ + __attribute__ ((__cleanup__ (__libc_cleanup_routine))) \ + = { .__cancel_routine = (fct), .__cancel_arg = (arg), \ + .__do_it = 1 }; + +#define __libc_cleanup_pop(execute) \ + __clframe.__do_it = (execute); \ + } while (0) + + +/* Create thread-specific key. */ +#define __libc_key_create(KEY, DESTRUCTOR) \ + __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1) + +/* Get thread-specific data. */ +#define __libc_getspecific(KEY) \ + __libc_ptf_call (__pthread_getspecific, (KEY), NULL) + +/* Set thread-specific data. */ +#define __libc_setspecific(KEY, VALUE) \ + __libc_ptf_call (__pthread_setspecific, (KEY, VALUE), 0) + + +/* Register handlers to execute before and after `fork'. Note that the + last parameter is NULL. The handlers registered by the libc are + never removed so this is OK. */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ + __register_atfork (PREPARE, PARENT, CHILD, NULL) +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *__dso_handle); + +/* Functions that are used by this file and are internal to the GNU C + library. */ + +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutex_attr); + +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); + +extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr, + int __kind); + +#ifdef __USE_UNIX98 +extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock, + __const pthread_rwlockattr_t *__attr); + +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +#endif + +extern int __pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)); + +extern int __pthread_setspecific (pthread_key_t __key, + __const void *__pointer); + +extern void *__pthread_getspecific (pthread_key_t __key); + +extern int __pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)); + +extern int __pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)); + + + +/* Make the pthread functions weak so that we can elide them from + single-threaded processes. */ +#ifndef __NO_WEAK_PTHREAD_ALIASES +# ifdef weak_extern +weak_extern (__pthread_mutex_init) +weak_extern (__pthread_mutex_destroy) +weak_extern (__pthread_mutex_lock) +weak_extern (__pthread_mutex_trylock) +weak_extern (__pthread_mutex_unlock) +weak_extern (__pthread_mutexattr_init) +weak_extern (__pthread_mutexattr_destroy) +weak_extern (__pthread_mutexattr_settype) +weak_extern (__pthread_rwlock_init) +weak_extern (__pthread_rwlock_destroy) +weak_extern (__pthread_rwlock_rdlock) +weak_extern (__pthread_rwlock_tryrdlock) +weak_extern (__pthread_rwlock_wrlock) +weak_extern (__pthread_rwlock_trywrlock) +weak_extern (__pthread_rwlock_unlock) +weak_extern (__pthread_key_create) +weak_extern (__pthread_setspecific) +weak_extern (__pthread_getspecific) +weak_extern (__pthread_once) +weak_extern (__pthread_atfork) +#ifdef SHARED +weak_extern (_pthread_cleanup_push_defer) +weak_extern (_pthread_cleanup_pop_restore) +#endif +weak_extern (pthread_setcancelstate) +# else +# pragma weak __pthread_mutex_init +# pragma weak __pthread_mutex_destroy +# pragma weak __pthread_mutex_lock +# pragma weak __pthread_mutex_trylock +# pragma weak __pthread_mutex_unlock +# pragma weak __pthread_mutexattr_init +# pragma weak __pthread_mutexattr_destroy +# pragma weak __pthread_mutexattr_settype +# pragma weak __pthread_rwlock_destroy +# pragma weak __pthread_rwlock_rdlock +# pragma weak __pthread_rwlock_tryrdlock +# pragma weak __pthread_rwlock_wrlock +# pragma weak __pthread_rwlock_trywrlock +# pragma weak __pthread_rwlock_unlock +# pragma weak __pthread_key_create +# pragma weak __pthread_setspecific +# pragma weak __pthread_getspecific +# pragma weak __pthread_once +# pragma weak __pthread_atfork +# pragma weak _pthread_cleanup_push_defer +# pragma weak _pthread_cleanup_pop_restore +# pragma weak pthread_setcancelstate +# endif +#endif + +#endif /* bits/libc-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 000000000..3f1676b3e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,69 @@ +/* libc-internal interface for thread-specific data. Stub or TLS version. + Copyright (C) 1998,2001,02 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GENERIC_BITS_LIBC_TSD_H +#define _GENERIC_BITS_LIBC_TSD_H 1 + +/* This file defines the following macros for accessing a small fixed + set of thread-specific `void *' data used only internally by libc. + + __libc_tsd_define(CLASS, KEY) -- Define or declare a `void *' datum + for KEY. CLASS can be `static' for + keys used in only one source file, + empty for global definitions, or + `extern' for global declarations. + __libc_tsd_address(KEY) -- Return the `void **' pointing to + the current thread's datum for KEY. + __libc_tsd_get(KEY) -- Return the `void *' datum for KEY. + __libc_tsd_set(KEY, VALUE) -- Set the datum for KEY to VALUE. + + The set of available KEY's will usually be provided as an enum, + and contains (at least): + _LIBC_TSD_KEY_MALLOC + _LIBC_TSD_KEY_DL_ERROR + _LIBC_TSD_KEY_RPC_VARS + All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros. + Some implementations may not provide any enum at all and instead + using string pasting in the macros. */ + +#include <tls.h> + +/* When full support for __thread variables is available, this interface is + just a trivial wrapper for it. Without TLS, this is the generic/stub + implementation for wholly single-threaded systems. + + We don't define an enum for the possible key values, because the KEYs + translate directly into variables by macro magic. */ + +#if USE___THREAD +# define __libc_tsd_define(CLASS, KEY) \ + CLASS __thread void *__libc_tsd_##KEY attribute_tls_model_ie; + +# define __libc_tsd_address(KEY) (&__libc_tsd_##KEY) +# define __libc_tsd_get(KEY) (__libc_tsd_##KEY) +# define __libc_tsd_set(KEY, VALUE) (__libc_tsd_##KEY = (VALUE)) +#else +# define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data; + +# define __libc_tsd_address(KEY) (&__libc_tsd_##KEY##_data) +# define __libc_tsd_get(KEY) (__libc_tsd_##KEY##_data) +# define __libc_tsd_set(KEY, VALUE) (__libc_tsd_##KEY##_data = (VALUE)) +#endif + +#endif /* bits/libc-tsd.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/sigthread.h b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h new file mode 100644 index 000000000..960bde18a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h @@ -0,0 +1,38 @@ +/* Signal handling function for threaded programs. + Copyright (C) 1998, 1999, 2000, 2002 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_SIGTHREAD_H +#define _BITS_SIGTHREAD_H 1 + +#if !defined _SIGNAL_H && !defined _PTHREAD_H +# error "Never include this file directly. Use <pthread.h> instead" +#endif + +/* Functions for handling signals. */ + +/* Modify the signal mask for the calling thread. The arguments have + the same meaning as for sigprocmask(2). */ +extern int pthread_sigmask (int __how, + __const __sigset_t *__restrict __newmask, + __sigset_t *__restrict __oldmask)__THROW; + +/* Send signal SIGNO to the given thread. */ +extern int pthread_kill (pthread_t __threadid, int __signo) __THROW; + +#endif /* bits/sigthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h new file mode 100644 index 000000000..cd64bc37e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h @@ -0,0 +1,105 @@ +/* Thread package specific definitions of stream lock type. NPTL version. + Copyright (C) 2000, 2001, 2002, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_STDIO_LOCK_H +#define _BITS_STDIO_LOCK_H 1 + +#include <bits/libc-lock.h> +#include <lowlevellock.h> + + +/* The locking here is very inexpensive, even for inlining. */ +#define _IO_lock_inexpensive 1 + +typedef struct { int lock; int cnt; void *owner; } _IO_lock_t; + +#define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL } + +#define _IO_lock_init(_name) \ + ((_name) = (_IO_lock_t) _IO_lock_initializer , 0) + +#define _IO_lock_fini(_name) \ + ((void) 0) + +#define _IO_lock_lock(_name) \ + do { \ + void *__self = THREAD_SELF; \ + if ((_name).owner != __self) \ + { \ + lll_lock ((_name).lock); \ + (_name).owner = __self; \ + } \ + ++(_name).cnt; \ + } while (0) + +#define _IO_lock_trylock(_name) \ + ({ \ + int __result = 0; \ + void *__self = THREAD_SELF; \ + if ((_name).owner != __self) \ + { \ + if (lll_trylock ((_name).lock) == 0) \ + { \ + (_name).owner = __self; \ + (_name).cnt = 1; \ + } \ + else \ + __result = EBUSY; \ + } \ + else \ + ++(_name).cnt; \ + __result; \ + }) + +#define _IO_lock_unlock(_name) \ + do { \ + if (--(_name).cnt == 0) \ + { \ + (_name).owner = NULL; \ + lll_unlock ((_name).lock); \ + } \ + } while (0) + + + +#define _IO_cleanup_region_start(_fct, _fp) \ + __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp) +#define _IO_cleanup_region_start_noarg(_fct) \ + __libc_cleanup_region_start (1, _fct, NULL) +#define _IO_cleanup_region_end(_doit) \ + __libc_cleanup_region_end (_doit) + +#if defined _LIBC && !defined NOT_IN_libc + +# ifdef __EXCEPTIONS +# define _IO_acquire_lock(_fp) \ + do { \ + _IO_FILE *_IO_acquire_lock_file \ + __attribute__((cleanup (_IO_acquire_lock_fct))) \ + = (_fp); \ + _IO_flockfile (_IO_acquire_lock_file); + +# else +# define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled +# endif +# define _IO_release_lock(_fp) ; } while (0) + +#endif + +#endif /* bits/stdio-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/createthread.c b/libpthread/nptl/sysdeps/pthread/createthread.c new file mode 100644 index 000000000..88ffe09d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/createthread.c @@ -0,0 +1,255 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> + +#include <bits/kernel-features.h> + + +#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) + +/* Unless otherwise specified, the thread "register" is going to be + initialized with a pointer to the TCB. */ +#ifndef TLS_VALUE +# define TLS_VALUE pd +#endif + +#ifndef ARCH_CLONE +# define ARCH_CLONE __clone +#endif + + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Pointer to the corresponding variable in libc. */ +int *__libc_multiple_threads_ptr attribute_hidden; +#endif + + +static int +do_clone (struct pthread *pd, const struct pthread_attr *attr, + int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS, + int stopped) +{ +#ifdef PREPARE_CREATE + PREPARE_CREATE; +#endif + + if (stopped) + /* We Make sure the thread does not run far by forcing it to get a + lock. We lock it here too so that the new thread cannot continue + until we tell it to. */ + lll_lock (pd->lock); + + /* One more thread. We cannot have the thread do this itself, since it + might exist but not have been scheduled yet by the time we've returned + and need to check the value to behave correctly. We must do it before + creating the thread, in case it does get scheduled first and then + might mistakenly think it was the only thread. In the failure case, + we momentarily store a false value; this doesn't matter because there + is no kosher thing a signal handler interrupting us right here can do + that cares whether the thread count is correct. */ + atomic_increment (&__nptl_nthreads); + + if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags, + pd, &pd->tid, TLS_VALUE, &pd->tid) == -1) + { + atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */ + + /* Failed. If the thread is detached, remove the TCB here since + the caller cannot do this. The caller remembered the thread + as detached and cannot reverify that it is not since it must + not access the thread descriptor again. */ + if (IS_DETACHED (pd)) + __deallocate_stack (pd); + + return errno; + } + + /* Now we have the possibility to set scheduling parameters etc. */ + if (__builtin_expect (stopped != 0, 0)) + { + INTERNAL_SYSCALL_DECL (err); + int res = 0; + + /* Set the affinity mask if necessary. */ + if (attr->cpuset != NULL) + { + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, + sizeof (cpu_set_t), attr->cpuset); + + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) + { + /* The operation failed. We have to kill the thread. First + send it the cancellation signal. */ + INTERNAL_SYSCALL_DECL (err2); + err_out: +#if __ASSUME_TGKILL + (void) INTERNAL_SYSCALL (tgkill, err2, 3, + THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, SIGCANCEL); +#else + (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL); +#endif + + return (INTERNAL_SYSCALL_ERROR_P (res, err) + ? INTERNAL_SYSCALL_ERRNO (res, err) + : 0); + } + } + + /* Set the scheduling parameters. */ + if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0) + { + res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid, + pd->schedpolicy, &pd->schedparam); + + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) + goto err_out; + } + } + + /* We now have for sure more than one thread. The main thread might + not yet have the flag set. No need to set the global variable + again if this is what we use. */ + THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); + + return 0; +} + + +static int +create_thread (struct pthread *pd, const struct pthread_attr *attr, + STACK_VARIABLES_PARMS) +{ +#ifdef TLS_TCB_AT_TP + assert (pd->header.tcb != NULL); +#endif + + /* We rely heavily on various flags the CLONE function understands: + + CLONE_VM, CLONE_FS, CLONE_FILES + These flags select semantics with shared address space and + file descriptors according to what POSIX requires. + + CLONE_SIGNAL + This flag selects the POSIX signal semantics. + + CLONE_SETTLS + The sixth parameter to CLONE determines the TLS area for the + new thread. + + CLONE_PARENT_SETTID + The kernels writes the thread ID of the newly created thread + into the location pointed to by the fifth parameters to CLONE. + + Note that it would be semantically equivalent to use + CLONE_CHILD_SETTID but it is be more expensive in the kernel. + + CLONE_CHILD_CLEARTID + The kernels clears the thread ID of a thread that has called + sys_exit() in the location pointed to by the seventh parameter + to CLONE. + + CLONE_DETACHED + No signal is generated if the thread exists and it is + automatically reaped. + + The termination signal is chosen to be zero which means no signal + is sent. */ + int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL + | CLONE_SETTLS | CLONE_PARENT_SETTID + | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM +#if __ASSUME_NO_CLONE_DETACHED == 0 + | CLONE_DETACHED +#endif + | 0); + + if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0)) + { + /* The parent thread is supposed to report events. Check whether + the TD_CREATE event is needed, too. */ + const int _idx = __td_eventword (TD_CREATE); + const uint32_t _mask = __td_eventmask (TD_CREATE); + + if ((_mask & (__nptl_threads_events.event_bits[_idx] + | pd->eventbuf.eventmask.event_bits[_idx])) != 0) + { + /* We always must have the thread start stopped. */ + pd->stopped_start = true; + + /* Create the thread. We always create the thread stopped + so that it does not get far before we tell the debugger. */ + int res = do_clone (pd, attr, clone_flags, start_thread, + STACK_VARIABLES_ARGS, 1); + if (res == 0) + { + /* Now fill in the information about the new thread in + the newly created thread's data structure. We cannot let + the new thread do this since we don't know whether it was + already scheduled when we send the event. */ + pd->eventbuf.eventnum = TD_CREATE; + pd->eventbuf.eventdata = pd; + + /* Enqueue the descriptor. */ + do + pd->nextevent = __nptl_last_event; + while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, + pd, pd->nextevent) + != 0); + + /* Now call the function which signals the event. */ + __nptl_create_event (); + + /* And finally restart the new thread. */ + lll_unlock (pd->lock); + } + + return res; + } + } + +#ifdef NEED_DL_SYSINFO + assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd)); +#endif + + /* Determine whether the newly created threads has to be started + stopped since we have to set the scheduling parameters or set the + affinity. */ + bool stopped = false; + if (attr != NULL && (attr->cpuset != NULL + || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)) + stopped = true; + pd->stopped_start = stopped; + + /* Actually create the thread. */ + int res = do_clone (pd, attr, clone_flags, start_thread, + STACK_VARIABLES_ARGS, stopped); + + if (res == 0 && stopped) + /* And finally restart the new thread. */ + lll_unlock (pd->lock); + + return res; +} diff --git a/libpthread/nptl/sysdeps/pthread/defs.awk b/libpthread/nptl/sysdeps/pthread/defs.awk new file mode 100644 index 000000000..d41d57bd7 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/defs.awk @@ -0,0 +1,24 @@ +/^[ ]*\.endp/ { need_endp = 1 } +/^[ ]*\.end/ { need_end = 1 } +/^[ ]*\.align/ { if($2 > max) max = $2; } + +END { + if(need_endp) + { + print "#define END_INIT .endp _init"; + print "#define END_FINI .endp _fini"; + } else if(need_end) + { + print "#define END_INIT .end _init"; + print "#define END_FINI .end _fini"; + } + else + { + print "#define END_INIT"; + print "#define END_FINI"; + } + if(max) + print "#define ALIGN .align", max; + else + print "#define ALIGN"; +} diff --git a/libpthread/nptl/sysdeps/pthread/librt-cancellation.c b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c new file mode 100644 index 000000000..753a2d831 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "atomic.h" + + +#ifdef IS_IN_librt +/* The next two functions are similar to pthread_setcanceltype() but + more specialized for the use in the cancelable functions like write(). + They do not need to check parameters etc. */ +int +attribute_hidden +__librt_enable_asynccancel (void) +{ + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval | CANCELTYPE_BITMASK; + + if (__builtin_expect ((oldval & CANCELED_BITMASK) != 0, 0)) + { + /* If we are already exiting or if PTHREAD_CANCEL_DISABLED, + stop right here. */ + if ((oldval & (EXITING_BITMASK | CANCELSTATE_BITMASK)) != 0) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + newval, oldval); + if (__builtin_expect (curval != oldval, 0)) + { + /* Somebody else modified the word, try again. */ + oldval = curval; + continue; + } + + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + + __do_cancel (); + + /* NOTREACHED */ + } + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } + + return oldval; +} + + +void +internal_function attribute_hidden +__librt_disable_asynccancel (int oldtype) +{ + /* If asynchronous cancellation was enabled before we do not have + anything to do. */ + if (oldtype & CANCELTYPE_BITMASK) + return; + + struct pthread *self = THREAD_SELF; + int oldval = THREAD_GETMEM (self, cancelhandling); + + while (1) + { + int newval = oldval & ~CANCELTYPE_BITMASK; + + if (newval == oldval) + break; + + int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, + oldval); + if (__builtin_expect (curval == oldval, 1)) + break; + + /* Prepare the next round. */ + oldval = curval; + } +} + + +#endif diff --git a/libpthread/nptl/sysdeps/pthread/list.h b/libpthread/nptl/sysdeps/pthread/list.h new file mode 100644 index 000000000..43186a2d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/list.h @@ -0,0 +1,114 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LIST_H +#define _LIST_H 1 + +/* The definitions of this file are adopted from those which can be + found in the Linux kernel headers to enable people familiar with + the latter find their way in these sources as well. */ + + +/* Basic type for the double-link list. */ +typedef struct list_head +{ + struct list_head *next; + struct list_head *prev; +} list_t; + + +/* Define a variable with the head and tail of the list. */ +#define LIST_HEAD(name) \ + list_t name = { &(name), &(name) } + +/* Initialize a new list head. */ +#define INIT_LIST_HEAD(ptr) \ + (ptr)->next = (ptr)->prev = (ptr) + + +/* Add new element at the head of the list. */ +static inline void +list_add (list_t *newp, list_t *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + + +/* Add new element at the tail of the list. */ +static inline void +list_add_tail (list_t *newp, list_t *head) +{ + head->prev->next = newp; + newp->next = head; + newp->prev = head->prev; + head->prev = newp; +} + + +/* Remove element from list. */ +static inline void +list_del (list_t *elem) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + + +/* Join two lists. */ +static inline void +list_splice (list_t *add, list_t *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) + { + add->next->prev = head; + add->prev->next = head->next; + head->next->prev = add->prev; + head->next = add->next; + } +} + + +/* Get typed element from list at a given position. */ +#define list_entry(ptr, type, member) \ + ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list. */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list. */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list. The list elements can be + removed from the list while doing this. */ +#define list_for_each_prev_safe(pos, p, head) \ + for (pos = (head)->prev, p = pos->prev; \ + pos != (head); \ + pos = p, p = pos->prev) + +#endif /* list.h */ diff --git a/libpthread/nptl/sysdeps/pthread/malloc-machine.h b/libpthread/nptl/sysdeps/pthread/malloc-machine.h new file mode 100644 index 000000000..efab230aa --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,62 @@ +/* Basic platform-independent macro definitions for mutexes, + thread-specific data and parameters for malloc. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _MALLOC_MACHINE_H +#define _MALLOC_MACHINE_H + +#undef thread_atfork_static + +#include <atomic.h> +#include <bits/libc-lock.h> + +__libc_lock_define (typedef, mutex_t) + +#define mutex_init(m) __libc_lock_init (*(m)) +#define mutex_lock(m) __libc_lock_lock (*(m)) +#define mutex_trylock(m) __libc_lock_trylock (*(m)) +#define mutex_unlock(m) __libc_lock_unlock (*(m)) + +/* This is defined by newer gcc version unique for each module. */ +extern void *__dso_handle __attribute__ ((__weak__)); + +#include <fork.h> + +#ifdef SHARED +# define thread_atfork(prepare, parent, child) \ + __register_atfork (prepare, parent, child, __dso_handle) +#else +# define thread_atfork(prepare, parent, child) \ + __register_atfork (prepare, parent, child, \ + &__dso_handle == NULL ? NULL : __dso_handle) +#endif + +/* thread specific data for glibc */ + +#include <bits/libc-tsd.h> + +typedef int tsd_key_t[1]; /* no key data structure, libc magic does it */ +__libc_tsd_define (static, MALLOC) /* declaration/common definition */ +#define tsd_key_create(key, destr) ((void) (key)) +#define tsd_setspecific(key, data) __libc_tsd_set (MALLOC, (data)) +#define tsd_getspecific(key, vptr) ((vptr) = __libc_tsd_get (MALLOC)) + +#include <sysdeps/generic/malloc-machine.h> + +#endif /* !defined(_MALLOC_MACHINE_H) */ diff --git a/libpthread/nptl/sysdeps/pthread/posix-timer.h b/libpthread/nptl/sysdeps/pthread/posix-timer.h new file mode 100644 index 000000000..8b4cbc8cd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/posix-timer.h @@ -0,0 +1,197 @@ +/* Definitions for POSIX timer implementation on top of NPTL. + Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <limits.h> +#include <signal.h> + +/* Double linked list. */ +struct list_links +{ + struct list_links *next; + struct list_links *prev; +}; + + +/* Forward declaration. */ +struct timer_node; + + +/* Definitions for an internal thread of the POSIX timer implementation. */ +struct thread_node +{ + struct list_links links; + pthread_attr_t attr; + pthread_t id; + unsigned int exists; + struct list_links timer_queue; + pthread_cond_t cond; + struct timer_node *current_timer; + pthread_t captured; + clockid_t clock_id; +}; + + +/* Internal representation of a timer. */ +struct timer_node +{ + struct list_links links; + struct sigevent event; + clockid_t clock; + struct itimerspec value; + struct timespec expirytime; + pthread_attr_t attr; + unsigned int abstime; + unsigned int armed; + enum { + TIMER_FREE, TIMER_INUSE, TIMER_DELETED + } inuse; + struct thread_node *thread; + pid_t creator_pid; + int refcount; + int overrun_count; +}; + + +/* The limit is not published if we are compiled with kernel timer support. + But we still compiled in this implementation with its limit unless built + to require the kernel support. */ +#ifndef TIMER_MAX +# define TIMER_MAX 256 +#endif + +/* Static array with the structures for all the timers. */ +extern struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists. */ +extern pthread_mutex_t __timer_mutex; + +/* Variable to protext initialization. */ +extern pthread_once_t __timer_init_once_control; + +/* Nonzero if initialization of timer implementation failed. */ +extern int __timer_init_failed; + +/* Node for the thread used to deliver signals. */ +extern struct thread_node __timer_signal_thread_rclk; + + +/* Return pointer to timer structure corresponding to ID. */ +#define timer_id2ptr(timerid) ((struct timer_node *) timerid) +#define timer_ptr2id(timerid) ((void *) timerid) + +/* Check whether timer is valid; global mutex must be held. */ +static inline int +timer_valid (struct timer_node *timer) +{ + return timer && timer->inuse == TIMER_INUSE; +} + +/* Timer refcount functions; need global mutex. */ +extern void __timer_dealloc (struct timer_node *timer); + +static inline void +timer_addref (struct timer_node *timer) +{ + timer->refcount++; +} + +static inline void +timer_delref (struct timer_node *timer) +{ + if (--timer->refcount == 0) + __timer_dealloc (timer); +} + +/* Timespec helper routines. */ +static inline int +__attribute ((always_inline)) +timespec_compare (const struct timespec *left, const struct timespec *right) +{ + if (left->tv_sec < right->tv_sec) + return -1; + if (left->tv_sec > right->tv_sec) + return 1; + + if (left->tv_nsec < right->tv_nsec) + return -1; + if (left->tv_nsec > right->tv_nsec) + return 1; + + return 0; +} + +static inline void +timespec_add (struct timespec *sum, const struct timespec *left, + const struct timespec *right) +{ + sum->tv_sec = left->tv_sec + right->tv_sec; + sum->tv_nsec = left->tv_nsec + right->tv_nsec; + + if (sum->tv_nsec >= 1000000000) + { + ++sum->tv_sec; + sum->tv_nsec -= 1000000000; + } +} + +static inline void +timespec_sub (struct timespec *diff, const struct timespec *left, + const struct timespec *right) +{ + diff->tv_sec = left->tv_sec - right->tv_sec; + diff->tv_nsec = left->tv_nsec - right->tv_nsec; + + if (diff->tv_nsec < 0) + { + --diff->tv_sec; + diff->tv_nsec += 1000000000; + } +} + + +/* We need one of the list functions in the other modules. */ +static inline void +list_unlink_ip (struct list_links *list) +{ + struct list_links *lnext = list->next, *lprev = list->prev; + + lnext->prev = lprev; + lprev->next = lnext; + + /* The suffix ip means idempotent; list_unlink_ip can be called + * two or more times on the same node. + */ + + list->next = list; + list->prev = list; +} + + +/* Functions in the helper file. */ +extern void __timer_mutex_cancel_handler (void *arg); +extern void __timer_init_once (void); +extern struct timer_node *__timer_alloc (void); +extern int __timer_thread_start (struct thread_node *thread); +extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t); +extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t); +extern void __timer_thread_dealloc (struct thread_node *thread); +extern int __timer_thread_queue_timer (struct thread_node *thread, + struct timer_node *insert); +extern void __timer_thread_wakeup (struct thread_node *thread); diff --git a/libpthread/nptl/sysdeps/pthread/pt-initfini.c b/libpthread/nptl/sysdeps/pthread/pt-initfini.c new file mode 100644 index 000000000..5955a7efc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,125 @@ +/* Special .init and .fini section support. Linuxthread version. + Copyright (C) 1995,1996,1997,2000,2001,2002 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 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The Library General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the + .init and .fini sections and defines global symbols for + those addresses, so they can be called as functions. + + * crtn.s puts the corresponding function epilogues + in the .init and .fini sections. */ + +#include <stdlib.h> + +/* We use embedded asm for .section unconditionally, as this makes it + easier to insert the necessary directives into crtn.S. */ +#define SECTION(x) __asm__ (".section " x ) + +/* Embed an #include to pull in the alignment and .end directives. */ +asm ("\n#include \"defs.h\""); + +/* The initial common code ends here. */ +asm ("\n/*@HEADER_ENDS*/"); + +/* To determine whether we need .end and .align: */ +asm ("\n/*@TESTS_BEGIN*/"); +extern void dummy (void (*foo) (void)); +void +dummy (void (*foo) (void)) +{ + if (foo) + (*foo) (); +} +asm ("\n/*@TESTS_END*/"); + +/* The beginning of _init: */ +asm ("\n/*@_init_PROLOG_BEGINS*/"); + +static void +call_initialize_minimal (void) +{ + extern void __pthread_initialize_minimal_internal (void) + __attribute ((visibility ("hidden"))); + + __pthread_initialize_minimal_internal (); +} + +SECTION (".init"); +extern void _init (void); +void +_init (void) +{ + /* The very first thing we must do is to set up the registers. */ + call_initialize_minimal (); + + asm ("ALIGN"); + asm("END_INIT"); + /* Now the epilog. */ + asm ("\n/*@_init_PROLOG_ENDS*/"); + asm ("\n/*@_init_EPILOG_BEGINS*/"); + SECTION(".init"); +} +asm ("END_INIT"); + +/* End of the _init epilog, beginning of the _fini prolog. */ +asm ("\n/*@_init_EPILOG_ENDS*/"); +asm ("\n/*@_fini_PROLOG_BEGINS*/"); + +SECTION (".fini"); +extern void _fini (void); +void +_fini (void) +{ + + /* End of the _fini prolog. */ + asm ("ALIGN"); + asm ("END_FINI"); + asm ("\n/*@_fini_PROLOG_ENDS*/"); + + { + /* Let GCC know that _fini is not a leaf function by having a dummy + function call here. We arrange for this call to be omitted from + either crt file. */ + extern void i_am_not_a_leaf (void); + i_am_not_a_leaf (); + } + + /* Beginning of the _fini epilog. */ + asm ("\n/*@_fini_EPILOG_BEGINS*/"); + SECTION (".fini"); +} +asm ("END_FINI"); + +/* End of the _fini epilog. Any further generated assembly (e.g. .ident) + is shared between both crt files. */ +asm ("\n/*@_fini_EPILOG_ENDS*/"); +asm ("\n/*@TRAILER_BEGINS*/"); + +/* End of file. */ diff --git a/libpthread/nptl/sysdeps/pthread/pt-longjmp.c b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c new file mode 100644 index 000000000..b4106fdba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include "pthreadP.h" + +extern void __libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +void +longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} +weak_alias (longjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/pthread/pthread-functions.h b/libpthread/nptl/sysdeps/pthread/pthread-functions.h new file mode 100644 index 000000000..813d55621 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREAD_FUNCTIONS_H +#define _PTHREAD_FUNCTIONS_H 1 + +#include <pthread.h> +#include <setjmp.h> +#include <internaltypes.h> + +struct xid_command; + +/* Data type shared with libc. The libc uses it to pass on calls to + the thread functions. */ +struct pthread_functions +{ + int (*ptr_pthread_attr_destroy) (pthread_attr_t *); + int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); + int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); + int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, + struct sched_param *); + int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, + const struct sched_param *); + int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); + int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); + int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); + int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); + int (*ptr_pthread_condattr_init) (pthread_condattr_t *); + int (*ptr___pthread_cond_broadcast) (pthread_cond_t *); + int (*ptr___pthread_cond_destroy) (pthread_cond_t *); + int (*ptr___pthread_cond_init) (pthread_cond_t *, + const pthread_condattr_t *); + int (*ptr___pthread_cond_signal) (pthread_cond_t *); + int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); + int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, + const struct timespec *); + int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *, + const pthread_condattr_t *); + int (*ptr___pthread_cond_signal_2_0) (pthread_cond_2_0_t *); + int (*ptr___pthread_cond_wait_2_0) (pthread_cond_2_0_t *, pthread_mutex_t *); + int (*ptr___pthread_cond_timedwait_2_0) (pthread_cond_2_0_t *, + pthread_mutex_t *, + const struct timespec *); + int (*ptr_pthread_equal) (pthread_t, pthread_t); + void (*ptr___pthread_exit) (void *); + int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); + int (*ptr_pthread_setschedparam) (pthread_t, int, + const struct sched_param *); + int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); + int (*ptr_pthread_mutex_init) (pthread_mutex_t *, + const pthread_mutexattr_t *); + int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); + int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); + int (*ptr_pthread_mutexattr_init) (pthread_mutexattr_t *attr); + int (*ptr_pthread_mutexattr_destroy) (pthread_mutexattr_t *attr); + int (*ptr_pthread_mutexattr_settype) (pthread_mutexattr_t *attr, int kind); + pthread_t (*ptr_pthread_self) (void); + int (*ptr_pthread_setcancelstate) (int, int *); + int (*ptr_pthread_setcanceltype) (int, int *); + void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *); + int (*ptr___pthread_once) (pthread_once_t *, void (*) (void)); + int (*ptr___pthread_rwlock_rdlock) (pthread_rwlock_t *); + int (*ptr___pthread_rwlock_wrlock) (pthread_rwlock_t *); + int (*ptr___pthread_rwlock_unlock) (pthread_rwlock_t *); + int (*ptr___pthread_key_create) (pthread_key_t *, void (*) (void *)); + void *(*ptr___pthread_getspecific) (pthread_key_t); + int (*ptr___pthread_setspecific) (pthread_key_t, const void *); + void (*ptr__pthread_cleanup_push_defer) (struct _pthread_cleanup_buffer *, + void (*) (void *), void *); + void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer *, + int); +#define HAVE_PTR_NTHREADS + unsigned int *ptr_nthreads; + void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *) + __attribute ((noreturn)) __cleanup_fct_attribute; + void (*ptr__nptl_deallocate_tsd) (void); + int (*ptr__nptl_setxid) (struct xid_command *); +}; + +/* Variable in libc.so. */ +extern struct pthread_functions __libc_pthread_functions attribute_hidden; + +#endif /* pthread-functions.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread.h b/libpthread/nptl/sysdeps/pthread/pthread.h new file mode 100644 index 000000000..c4bfc0e81 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread.h @@ -0,0 +1,976 @@ +/* Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H 1 + +#include <features.h> +#include <sched.h> +#include <time.h> + +#define __need_sigset_t +#include <signal.h> +#include <bits/pthreadtypes.h> +#include <bits/setjmp.h> +#include <bits/wordsize.h> +#if defined _LIBC && ( defined IS_IN_libc || defined NOT_IN_libc ) +#include <bits/uClibc_pthread.h> +#endif + + +/* Detach state. */ +enum +{ + PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE + PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED +}; + + +/* Mutex types. */ +enum +{ + PTHREAD_MUTEX_TIMED_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_ADAPTIVE_NP +#ifdef __USE_UNIX98 + , + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +#endif +#ifdef __USE_GNU + /* For compatibility. */ + , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP +#endif +}; + +/* Mutex initializers. */ +#if __WORDSIZE == 64 +# define PTHREAD_MUTEX_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } +# ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } } +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } } +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } } +# endif +#else +# define PTHREAD_MUTEX_INITIALIZER \ + { { 0, 0, 0, 0, 0, { 0 } } } +# ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } } +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } } +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } } +# endif +#endif + +/* Read-write lock types. */ +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +enum +{ + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP +}; + +/* Read-write lock initializers. */ +# if __WORDSIZE == 64 +# define PTHREAD_RWLOCK_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +# else +# define PTHREAD_RWLOCK_INITIALIZER \ + { { 0, 0, 0, 0, 0, 0, 0, 0 } } +# endif +# ifdef __USE_GNU +# if __WORDSIZE == 64 +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } +# else +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0 } } +# endif +# endif +#endif /* Unix98 or XOpen2K */ + + +/* Scheduler inheritance. */ +enum +{ + PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED + PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED +}; + + +/* Scope handling. */ +enum +{ + PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM + PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +}; + + +/* Process shared or private flag. */ +enum +{ + PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE + PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED +}; + + + +/* Conditional variable handling. */ +#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } + + +/* Cleanup buffers */ +struct _pthread_cleanup_buffer +{ + void (*__routine) (void *); /* Function to call. */ + void *__arg; /* Its argument. */ + int __canceltype; /* Saved cancellation type. */ + struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ +}; + +/* Cancellation */ +enum +{ + PTHREAD_CANCEL_ENABLE, +#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE + PTHREAD_CANCEL_DISABLE +#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE +}; +enum +{ + PTHREAD_CANCEL_DEFERRED, +#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED + PTHREAD_CANCEL_ASYNCHRONOUS +#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS +}; +#define PTHREAD_CANCELED ((void *) -1) + + +/* Single execution handling. */ +#define PTHREAD_ONCE_INIT 0 + + +#ifdef __USE_XOPEN2K +/* Value returned by 'pthread_barrier_wait' for one of the threads after + the required number of threads have called this function. + -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + + +__BEGIN_DECLS + +/* Create a new thread, starting with execution of START-ROUTINE + getting passed ARG. Creation attributed come from ATTR. The new + handle is stored in *NEWTHREAD. */ +extern int pthread_create (pthread_t *__restrict __newthread, + __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), + void *__restrict __arg) __THROW; + +/* Terminate calling thread. + + The registered cleanup handlers are called via exception handling + so we cannot mark this function with __THROW.*/ +extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); + +/* Make calling thread wait for termination of the thread TH. The + exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN + is not NULL. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +#ifdef __USE_GNU +/* Check whether thread TH has terminated. If yes return the status of + the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. */ +extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW; + +/* Make calling thread wait for termination of the thread TH, but only + until TIMEOUT. The exit status of the thread is stored in + *THREAD_RETURN, if THREAD_RETURN is not NULL. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return, + __const struct timespec *__abstime); +#endif + +/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. + The resources of TH will therefore be freed immediately when it + terminates, instead of waiting for another thread to perform PTHREAD_JOIN + on it. */ +extern int pthread_detach (pthread_t __th) __THROW; + + +/* Obtain the identifier of the current thread. */ +extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); + +/* Compare two thread identifiers. */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + + +/* Thread attribute handling. */ + +/* Initialize thread attribute *ATTR with default attributes + (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, + no user-provided stack). */ +extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; + +/* Destroy thread attribute *ATTR. */ +extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; + +/* Get detach state attribute. */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, + int *__detachstate) __THROW; + +/* Set detach state attribute. */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, + int __detachstate) __THROW; + + +/* Get the size of the guard area created for stack overflow protection. */ +extern int pthread_attr_getguardsize (__const pthread_attr_t *__attr, + size_t *__guardsize) __THROW; + +/* Set the size of the guard area created for stack overflow protection. */ +extern int pthread_attr_setguardsize (pthread_attr_t *__attr, + size_t __guardsize) __THROW; + + +/* Return in *PARAM the scheduling parameters of *ATTR. */ +extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict + __attr, + struct sched_param *__restrict __param) + __THROW; + +/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ +extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, + __const struct sched_param *__restrict + __param) __THROW; + +/* Return in *POLICY the scheduling policy of *ATTR. */ +extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict + __attr, int *__restrict __policy) + __THROW; + +/* Set scheduling policy in *ATTR according to POLICY. */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) + __THROW; + +/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ +extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict + __attr, int *__restrict __inherit) + __THROW; + +/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, + int __inherit) __THROW; + + +/* Return in *SCOPE the scheduling contention scope of *ATTR. */ +extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, + int *__restrict __scope) __THROW; + +/* Set scheduling contention scope in *ATTR according to SCOPE. */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) + __THROW; + +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr) + __THROW __attribute_deprecated__; + +/* Set the starting address of the stack of the thread to be created. + Depending on whether the stack grows up or down the value must either + be higher or lower than all the address in the memory block. The + minimal size of the block must be PTHREAD_STACK_MIN. */ +extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, + void *__stackaddr) + __THROW __attribute_deprecated__; + +/* Return the currently used minimal stack size. */ +extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict + __attr, size_t *__restrict __stacksize) + __THROW; + +/* Add information about the minimum stack size needed for the thread + to be started. This size must never be less than PTHREAD_STACK_MIN + and must also not exceed the system limits. */ +extern int pthread_attr_setstacksize (pthread_attr_t *__attr, + size_t __stacksize) __THROW; + +#ifdef __USE_XOPEN2K +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, + void **__restrict __stackaddr, + size_t *__restrict __stacksize) __THROW; + +/* The following two interfaces are intended to replace the last two. They + require setting the address as well as the size since only setting the + address will make the implementation on some architectures impossible. */ +extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize) __THROW; +#endif + +#ifdef __USE_GNU +/* Thread created with attribute ATTR will be limited to run only on + the processors represented in CPUSET. */ +extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr, + size_t __cpusetsize, + __const cpu_set_t *__cpuset) __THROW; + +/* Get bit set in CPUSET representing the processors threads created with + ATTR can run on. */ +extern int pthread_attr_getaffinity_np (__const pthread_attr_t *__attr, + size_t __cpusetsize, + cpu_set_t *__cpuset) __THROW; + + +/* Initialize thread attribute *ATTR with attributes corresponding to the + already running thread TH. It shall be called on unitialized ATTR + and destroyed with pthread_attr_destroy when no longer needed. */ +extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; +#endif + + +/* Functions for scheduling control. */ + +/* Set the scheduling parameters for TARGET_THREAD according to POLICY + and *PARAM. */ +extern int pthread_setschedparam (pthread_t __target_thread, int __policy, + __const struct sched_param *__param) + __THROW; + +/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ +extern int pthread_getschedparam (pthread_t __target_thread, + int *__restrict __policy, + struct sched_param *__restrict __param) + __THROW; + +/* Set the scheduling priority for TARGET_THREAD. */ +extern int pthread_setschedprio (pthread_t __target_thread, int __prio) + __THROW; + + +#ifdef __USE_UNIX98 +/* Determine level of concurrency. */ +extern int pthread_getconcurrency (void) __THROW; + +/* Set new concurrency level to LEVEL. */ +extern int pthread_setconcurrency (int __level) __THROW; +#endif + +#ifdef __USE_GNU +/* Yield the processor to another thread or process. + This function is similar to the POSIX `sched_yield' function but + might be differently implemented in the case of a m-on-n thread + implementation. */ +extern int pthread_yield (void) __THROW; + + +/* Limit specified thread TH to run only on the processors represented + in CPUSET. */ +extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, + __const cpu_set_t *__cpuset) __THROW; + +/* Get bit set in CPUSET representing the processors TH can run on. */ +extern int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize, + cpu_set_t *__cpuset) __THROW; +#endif + + +/* Functions for handling initialization. */ + +/* Guarantee that the initialization function INIT_ROUTINE will be called + only once, even if pthread_once is executed several times with the + same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or + extern variable initialized to PTHREAD_ONCE_INIT. + + The initialization functions might throw exception which is why + this function is not marked with __THROW. */ +extern int pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)); + + +/* Functions for handling cancellation. + + Note that these functions are explicitly not marked to not throw an + exception in C++ code. If cancellation is implemented by unwinding + this is necessary to have the compiler generate the unwind information. */ + +/* Set cancelability state of current thread to STATE, returning old + state in *OLDSTATE if OLDSTATE is not NULL. */ +extern int pthread_setcancelstate (int __state, int *__oldstate); + +/* Set cancellation state of current thread to TYPE, returning the old + type in *OLDTYPE if OLDTYPE is not NULL. */ +extern int pthread_setcanceltype (int __type, int *__oldtype); + +/* Cancel THREAD immediately or at the next possibility. */ +extern int pthread_cancel (pthread_t __th); + +/* Test for pending cancellation for the current thread and terminate + the thread as per pthread_exit(PTHREAD_CANCELED) if it has been + cancelled. */ +extern void pthread_testcancel (void); + + +/* Cancellation handling with integration into exception handling. */ + +typedef struct +{ + struct + { + __jmp_buf __cancel_jmp_buf; + int __mask_was_saved; + } __cancel_jmp_buf[1]; + void *__pad[4]; +} __pthread_unwind_buf_t __attribute__ ((__aligned__)); + +/* No special attributes by default. */ +#ifndef __cleanup_fct_attribute +# define __cleanup_fct_attribute +#endif + + +/* Structure to hold the cleanup handler information. */ +struct __pthread_cleanup_frame +{ + void (*__cancel_routine) (void *); + void *__cancel_arg; + int __do_it; + int __cancel_type; +}; + +#if defined __GNUC__ && defined __EXCEPTIONS +# ifdef __cplusplus +/* Class to handle cancellation handler invocation. */ +class __pthread_cleanup_class +{ + void (*__cancel_routine) (void *); + void *__cancel_arg; + int __do_it; + int __cancel_type; + + public: + __pthread_cleanup_class (void (*__fct) (void *), void *__arg) + : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { } + ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); } + void __setdoit (int __newval) { __do_it = __newval; } + void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, + &__cancel_type); } + void __restore () const { pthread_setcanceltype (__cancel_type, 0); } +}; + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG + when the thread is canceled or calls pthread_exit. ROUTINE will also + be called with arguments ARG when the matching pthread_cleanup_pop + is executed with non-zero EXECUTE argument. + + pthread_cleanup_push and pthread_cleanup_pop are macros and must always + be used in matching pairs at the same nesting level of braces. */ +# define pthread_cleanup_push(routine, arg) \ + do { \ + __pthread_cleanup_class __clframe (routine, arg) + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. + If EXECUTE is non-zero, the handler function is called. */ +# define pthread_cleanup_pop(execute) \ + __clframe.__setdoit (execute); \ + } while (0) + +# ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also + saves the current cancellation type and sets it to deferred + cancellation. */ +# define pthread_cleanup_push_defer_np(routine, arg) \ + do { \ + __pthread_cleanup_class __clframe (routine, arg); \ + __clframe.__defer () + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also + restores the cancellation type that was in effect when the matching + pthread_cleanup_push_defer was called. */ +# define pthread_cleanup_pop_restore_np(execute) \ + __clframe.__restore (); \ + __clframe.__setdoit (execute); \ + } while (0) +# endif +# else +/* Function called to call the cleanup handler. As an extern inline + function the compiler is free to decide inlining the change when + needed or fall back on the copy which must exist somewhere + else. */ +__extern_inline void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame); + +__extern_inline void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) +{ + if (__frame->__do_it) + __frame->__cancel_routine (__frame->__cancel_arg); +} + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG + when the thread is canceled or calls pthread_exit. ROUTINE will also + be called with arguments ARG when the matching pthread_cleanup_pop + is executed with non-zero EXECUTE argument. + + pthread_cleanup_push and pthread_cleanup_pop are macros and must always + be used in matching pairs at the same nesting level of braces. */ +# define pthread_cleanup_push(routine, arg) \ + do { \ + struct __pthread_cleanup_frame __clframe \ + __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ + = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ + .__do_it = 1 }; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. + If EXECUTE is non-zero, the handler function is called. */ +# define pthread_cleanup_pop(execute) \ + __clframe.__do_it = (execute); \ + } while (0) + +# ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also + saves the current cancellation type and sets it to deferred + cancellation. */ +# define pthread_cleanup_push_defer_np(routine, arg) \ + do { \ + struct __pthread_cleanup_frame __clframe \ + __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ + = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ + .__do_it = 1 }; \ + (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, \ + &__clframe.__cancel_type) + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also + restores the cancellation type that was in effect when the matching + pthread_cleanup_push_defer was called. */ +# define pthread_cleanup_pop_restore_np(execute) \ + (void) pthread_setcanceltype (__clframe.__cancel_type, NULL); \ + __clframe.__do_it = (execute); \ + } while (0) +# endif +# endif +#else +/* Install a cleanup handler: ROUTINE will be called with arguments ARG + when the thread is canceled or calls pthread_exit. ROUTINE will also + be called with arguments ARG when the matching pthread_cleanup_pop + is executed with non-zero EXECUTE argument. + + pthread_cleanup_push and pthread_cleanup_pop are macros and must always + be used in matching pairs at the same nesting level of braces. */ +# define pthread_cleanup_push(routine, arg) \ + do { \ + __pthread_unwind_buf_t __cancel_buf; \ + void (*__cancel_routine) (void *) = (routine); \ + void *__cancel_arg = (arg); \ + int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \ + __cancel_buf.__cancel_jmp_buf, 0); \ + if (__builtin_expect (not_first_call, 0)) \ + { \ + __cancel_routine (__cancel_arg); \ + __pthread_unwind_next (&__cancel_buf); \ + /* NOTREACHED */ \ + } \ + \ + __pthread_register_cancel (&__cancel_buf); \ + do { +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. + If EXECUTE is non-zero, the handler function is called. */ +# define pthread_cleanup_pop(execute) \ + } while (0); \ + __pthread_unregister_cancel (&__cancel_buf); \ + if (execute) \ + __cancel_routine (__cancel_arg); \ + } while (0) +extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; + +# ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also + saves the current cancellation type and sets it to deferred + cancellation. */ +# define pthread_cleanup_push_defer_np(routine, arg) \ + do { \ + __pthread_unwind_buf_t __cancel_buf; \ + void (*__cancel_routine) (void *) = (routine); \ + void *__cancel_arg = (arg); \ + int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) \ + __cancel_buf.__cancel_jmp_buf, 0); \ + if (__builtin_expect (not_first_call, 0)) \ + { \ + __cancel_routine (__cancel_arg); \ + __pthread_unwind_next (&__cancel_buf); \ + /* NOTREACHED */ \ + } \ + \ + __pthread_register_cancel_defer (&__cancel_buf); \ + do { +extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also + restores the cancellation type that was in effect when the matching + pthread_cleanup_push_defer was called. */ +# define pthread_cleanup_pop_restore_np(execute) \ + } while (0); \ + __pthread_unregister_cancel_restore (&__cancel_buf); \ + if (execute) \ + __cancel_routine (__cancel_arg); \ + } while (0) +extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute; +# endif + +/* Internal interface to initiate cleanup. */ +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) + __cleanup_fct_attribute __attribute ((__noreturn__)) +# ifndef SHARED + __attribute ((__weak__)) +# endif + ; +#endif + +/* Function used in the macros. */ +struct __jmp_buf_tag; +extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROW; + + +/* Mutex handling. */ + +/* Initialize a mutex. */ +extern int pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutexattr) + __THROW; + +/* Destroy a mutex. */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try locking a mutex. */ +extern int pthread_mutex_trylock (pthread_mutex_t *_mutex) __THROW; + +/* Lock a mutex. */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; + +#ifdef __USE_XOPEN2K +/* Wait until lock becomes available, or specified time passes. */ +extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, + __const struct timespec *__restrict + __abstime) __THROW; +#endif + +/* Unlock a mutex. */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; + + +/* Functions for handling mutex attributes. */ + +/* Initialize mutex attribute object ATTR with default attributes + (kind is PTHREAD_MUTEX_TIMED_NP). */ +extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW; + +/* Destroy mutex attribute object ATTR. */ +extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; + +/* Get the process-shared flag of the mutex attribute ATTR. */ +extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the mutex attribute ATTR. */ +extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, + int __pshared) __THROW; + +#ifdef __USE_UNIX98 +/* Return in *KIND the mutex kind attribute in *ATTR. */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict + __attr, int *__restrict __kind) __THROW; + +/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, + PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or + PTHREAD_MUTEX_DEFAULT). */ +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) + __THROW; +#endif + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Functions for handling read-write locks. */ + +/* Initialize read-write lock RWLOCK using attributes ATTR, or use + the default values if later is NULL. */ +extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + __const pthread_rwlockattr_t *__restrict + __attr) __THROW; + +/* Destroy read-write lock RWLOCK. */ +extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; + +/* Acquire read lock for RWLOCK. */ +extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire read lock for RWLOCK. */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire read lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Acquire write lock for RWLOCK. */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire write lock for RWLOCK. */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire write lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Unlock RWLOCK. */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; + + +/* Functions for handling read-write lock attributes. */ + +/* Initialize attribute object ATTR with default values. */ +extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; + +/* Destroy attribute object ATTR. */ +extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; + +/* Return current setting of process-shared attribute of ATTR in PSHARED. */ +extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set process-shared attribute of ATTR to PSHARED. */ +extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, + int __pshared) __THROW; + +/* Return current setting of reader/writer preference. */ +extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t * + __restrict __attr, + int *__restrict __pref) __THROW; + +/* Set reader/write preference. */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, + int __pref) __THROW; +#endif + + +/* Functions for handling conditional variables. */ + +/* Initialize condition variable COND using attributes ATTR, or use + the default values if later is NULL. */ +extern int pthread_cond_init (pthread_cond_t *__restrict __cond, + __const pthread_condattr_t *__restrict + __cond_attr) __THROW; + +/* Destroy condition variable COND. */ +extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; + +/* Wake up one thread waiting for condition variable COND. */ +extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; + +/* Wake up all threads waiting for condition variables COND. */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; + +/* Wait for condition variable COND to be signaled or broadcast. + MUTEX is assumed to be locked before. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex); + +/* Wait for condition variable COND to be signaled or broadcast until + ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an + absolute time specification; zero is the beginning of the epoch + (00:00:00 GMT, January 1, 1970). + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex, + __const struct timespec *__restrict + __abstime); + +/* Functions for handling condition variable attributes. */ + +/* Initialize condition variable attribute ATTR. */ +extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; + +/* Destroy condition variable attribute ATTR. */ +extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; + +/* Get the process-shared flag of the condition variable attribute ATTR. */ +extern int pthread_condattr_getpshared (__const pthread_condattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the condition variable attribute ATTR. */ +extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, + int __pshared) __THROW; + +#ifdef __USE_XOPEN2K +/* Get the clock selected for the conditon variable attribute ATTR. */ +extern int pthread_condattr_getclock (__const pthread_condattr_t * + __restrict __attr, + __clockid_t *__restrict __clock_id) + __THROW; + +/* Set the clock selected for the conditon variable attribute ATTR. */ +extern int pthread_condattr_setclock (pthread_condattr_t *__attr, + __clockid_t __clock_id) __THROW; + +#endif + + +#ifdef __USE_XOPEN2K +/* Functions to handle spinlocks. */ + +/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can + be shared between different processes. */ +extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) + __THROW; + +/* Destroy the spinlock LOCK. */ +extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; + +/* Wait until spinlock LOCK is retrieved. */ +extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; + +/* Try to lock spinlock LOCK. */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; + +/* Release spinlock LOCK. */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; + + +/* Functions to handle barriers. */ + +/* Initialize BARRIER with the attributes in ATTR. The barrier is + opened when COUNT waiters arrived. */ +extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, + __const pthread_barrierattr_t *__restrict + __attr, unsigned int __count) __THROW; + +/* Destroy a previously dynamically initialized barrier BARRIER. */ +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +/* Wait on barrier BARRIER. */ +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; + + +/* Initialize barrier attribute ATTR. */ +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +/* Destroy previously dynamically initialized barrier attribute ATTR. */ +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +/* Get the process-shared flag of the barrier attribute ATTR. */ +extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the barrier attribute ATTR. */ +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, + int __pshared) __THROW; +#endif + + +/* Functions for handling thread-specific data. */ + +/* Create a key value identifying a location in the thread-specific + data area. Each thread maintains a distinct thread-specific data + area. DESTR_FUNCTION, if non-NULL, is called with the value + associated to that key when the key is destroyed. + DESTR_FUNCTION is not called if the value associated is NULL when + the key is destroyed. */ +extern int pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)) __THROW; + +/* Destroy KEY. */ +extern int pthread_key_delete (pthread_key_t __key) __THROW; + +/* Return current value of the thread-specific data slot identified by KEY. */ +extern void *pthread_getspecific (pthread_key_t __key) __THROW; + +/* Store POINTER in the thread-specific data slot identified by KEY. */ +extern int pthread_setspecific (pthread_key_t __key, + __const void *__pointer) __THROW; + + +#ifdef __USE_XOPEN2K +/* Get ID of CPU-time clock for thread THREAD_ID. */ +extern int pthread_getcpuclockid (pthread_t __thread_id, + __clockid_t *__clock_id) __THROW; +#endif + + +/* Install handlers to be called when a new process is created with FORK. + The PREPARE handler is called in the parent process just before performing + FORK. The PARENT handler is called in the parent process just after FORK. + The CHILD handler is called in the child process. Each of the three + handlers can be NULL, meaning that no handler needs to be called at that + point. + PTHREAD_ATFORK can be called several times, in which case the PREPARE + handlers are called in LIFO order (last added with PTHREAD_ATFORK, + first called before FORK), and the PARENT and CHILD handlers are called + in FIFO (first added, first called). */ + +extern int pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)) __THROW; + +__END_DECLS + +#endif /* pthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c new file mode 100644 index 000000000..c6b563f24 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthreadP.h> + + +/* Wait on barrier. */ +int +pthread_barrier_wait (barrier) + pthread_barrier_t *barrier; +{ + struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier; + int result = 0; + + /* Make sure we are alone. */ + lll_lock (ibarrier->lock); + + /* One more arrival. */ + --ibarrier->left; + + /* Are these all? */ + if (ibarrier->left == 0) + { + /* Yes. Increment the event counter to avoid invalid wake-ups and + tell the current waiters that it is their turn. */ + ++ibarrier->curr_event; + + /* Wake up everybody. */ + lll_futex_wake (&ibarrier->curr_event, INT_MAX); + + /* This is the thread which finished the serialization. */ + result = PTHREAD_BARRIER_SERIAL_THREAD; + } + else + { + /* The number of the event we are waiting for. The barrier's event + number must be bumped before we continue. */ + unsigned int event = ibarrier->curr_event; + + /* Before suspending, make the barrier available to others. */ + lll_unlock (ibarrier->lock); + + /* Wait for the event counter of the barrier to change. */ + do + lll_futex_wait (&ibarrier->curr_event, event); + while (event == ibarrier->curr_event); + } + + /* Make sure the init_count is stored locally or in a register. */ + unsigned int init_count = ibarrier->init_count; + + /* If this was the last woken thread, unlock. */ + if (atomic_increment_val (&ibarrier->left) == init_count) + /* We are done. */ + lll_unlock (ibarrier->lock); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c new file mode 100644 index 000000000..d83524182 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_broadcast (cond) + pthread_cond_t *cond; +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + /* Are there any waiters to be woken? */ + if (cond->__data.__total_seq > cond->__data.__wakeup_seq) + { + /* Yes. Mark them all as woken. */ + cond->__data.__wakeup_seq = cond->__data.__total_seq; + cond->__data.__woken_seq = cond->__data.__total_seq; + cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2; + int futex_val = cond->__data.__futex; + /* Signal that a broadcast happened. */ + ++cond->__data.__broadcast_seq; + + /* We are done. */ + lll_mutex_unlock (cond->__data.__lock); + + /* Do not use requeue for pshared condvars. */ + if (cond->__data.__mutex == (void *) ~0l) + goto wake_all; + + /* Wake everybody. */ + pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; + /* lll_futex_requeue returns 0 for success and non-zero + for errors. */ + if (__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1, + INT_MAX, &mut->__data.__lock, + futex_val), 0)) + { + /* The requeue functionality is not available. */ + wake_all: + lll_futex_wake (&cond->__data.__futex, INT_MAX); + } + + /* That's all. */ + return 0; + } + + /* We are done. */ + lll_mutex_unlock (cond->__data.__lock); + + return 0; +} +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c new file mode 100644 index 000000000..863b0a029 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_signal (cond) + pthread_cond_t *cond; +{ + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + /* Are there any waiters to be woken? */ + if (cond->__data.__total_seq > cond->__data.__wakeup_seq) + { + /* Yes. Mark one of them as woken. */ + ++cond->__data.__wakeup_seq; + ++cond->__data.__futex; + + /* Wake one. */ + lll_futex_wake (&cond->__data.__futex, 1); + } + + /* We are done. */ + lll_mutex_unlock (cond->__data.__lock); + + return 0; +} +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c new file mode 100644 index 000000000..db9dc4dcd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Cleanup handler, defined in pthread_cond_wait.c. */ +extern void __condvar_cleanup (void *arg) + __attribute__ ((visibility ("hidden"))); + +struct _condvar_cleanup_buffer +{ + int oldtype; + pthread_cond_t *cond; + pthread_mutex_t *mutex; + unsigned int bc_seq; +}; + +int +__pthread_cond_timedwait (cond, mutex, abstime) + pthread_cond_t *cond; + pthread_mutex_t *mutex; + const struct timespec *abstime; +{ + struct _pthread_cleanup_buffer buffer; + struct _condvar_cleanup_buffer cbuffer; + int result = 0; + + /* Catch invalid parameters. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Make sure we are along. */ + lll_mutex_lock (cond->__data.__lock); + + /* Now we can release the mutex. */ + int err = __pthread_mutex_unlock_usercnt (mutex, 0); + if (err) + { + lll_mutex_unlock (cond->__data.__lock); + return err; + } + + /* We have one new user of the condvar. */ + ++cond->__data.__total_seq; + ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + + /* Remember the mutex we are using here. If there is already a + different address store this is a bad user bug. Do not store + anything for pshared condvars. */ + if (cond->__data.__mutex != (void *) ~0l) + cond->__data.__mutex = mutex; + + /* Prepare structure passed to cancellation handler. */ + cbuffer.cond = cond; + cbuffer.mutex = mutex; + + /* Before we block we enable cancellation. Therefore we have to + install a cancellation handler. */ + __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); + + /* The current values of the wakeup counter. The "woken" counter + must exceed this value. */ + unsigned long long int val; + unsigned long long int seq; + val = seq = cond->__data.__wakeup_seq; + /* Remember the broadcast counter. */ + cbuffer.bc_seq = cond->__data.__broadcast_seq; + + while (1) + { + struct timespec rt; + { +#ifdef __NR_clock_gettime + INTERNAL_SYSCALL_DECL (err); + int ret; + ret = INTERNAL_SYSCALL (clock_gettime, err, 2, + (cond->__data.__nwaiters + & ((1 << COND_CLOCK_BITS) - 1)), + &rt); +# ifndef __ASSUME_POSIX_TIMERS + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + } + else +# endif + { + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - rt.tv_sec; + rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; + } +#else + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +#endif + } + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (__builtin_expect (rt.tv_sec < 0, 0)) + { + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + goto timeout; + } + + unsigned int futex_val = cond->__data.__futex; + + /* Prepare to wait. Release the condvar futex. */ + lll_mutex_unlock (cond->__data.__lock); + + /* Enable asynchronous cancellation. Required by the standard. */ + cbuffer.oldtype = __pthread_enable_asynccancel (); + + /* Wait until woken by signal or broadcast. */ + err = lll_futex_timed_wait (&cond->__data.__futex, + futex_val, &rt); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (cbuffer.oldtype); + + /* We are going to look at shared data again, so get the lock. */ + lll_mutex_lock(cond->__data.__lock); + + /* If a broadcast happened, we are done. */ + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + /* Check whether we are eligible for wakeup. */ + val = cond->__data.__wakeup_seq; + if (val != seq && cond->__data.__woken_seq != val) + break; + + /* Not woken yet. Maybe the time expired? */ + if (__builtin_expect (err == -ETIMEDOUT, 0)) + { + timeout: + /* Yep. Adjust the counters. */ + ++cond->__data.__wakeup_seq; + ++cond->__data.__futex; + + /* The error value. */ + result = ETIMEDOUT; + break; + } + } + + /* Another thread woken up. */ + ++cond->__data.__woken_seq; + + bc_out: + + cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this variable already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + if (cond->__data.__total_seq == -1ULL + && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + + /* We are done with the condvar. */ + lll_mutex_unlock (cond->__data.__lock); + + /* The cancellation handling is back to normal, remove the handler. */ + __pthread_cleanup_pop (&buffer, 0); + + /* Get the mutex before returning. */ + err = __pthread_mutex_cond_lock (mutex); + + return err ?: result; +} +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c new file mode 100644 index 000000000..b0fe694ba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +struct _condvar_cleanup_buffer +{ + int oldtype; + pthread_cond_t *cond; + pthread_mutex_t *mutex; + unsigned int bc_seq; +}; + + +void +__attribute__ ((visibility ("hidden"))) +__condvar_cleanup (void *arg) +{ + struct _condvar_cleanup_buffer *cbuffer = + (struct _condvar_cleanup_buffer *) arg; + unsigned int destroying; + + /* We are going to modify shared data. */ + lll_mutex_lock (cbuffer->cond->__data.__lock); + + if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq) + { + /* This thread is not waiting anymore. Adjust the sequence counters + appropriately. */ + ++cbuffer->cond->__data.__wakeup_seq; + ++cbuffer->cond->__data.__woken_seq; + ++cbuffer->cond->__data.__futex; + } + + cbuffer->cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this variable already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + destroying = 0; + if (cbuffer->cond->__data.__total_seq == -1ULL + && cbuffer->cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + { + lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1); + destroying = 1; + } + + /* We are done. */ + lll_mutex_unlock (cbuffer->cond->__data.__lock); + + /* Wake everybody to make sure no condvar signal gets lost. */ + if (! destroying) + lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX); + + /* Get the mutex before returning unless asynchronous cancellation + is in effect. */ + __pthread_mutex_cond_lock (cbuffer->mutex); +} + + +int +__pthread_cond_wait (cond, mutex) + pthread_cond_t *cond; + pthread_mutex_t *mutex; +{ + struct _pthread_cleanup_buffer buffer; + struct _condvar_cleanup_buffer cbuffer; + int err; + + /* Make sure we are along. */ + lll_mutex_lock (cond->__data.__lock); + + /* Now we can release the mutex. */ + err = __pthread_mutex_unlock_usercnt (mutex, 0); + if (__builtin_expect (err, 0)) + { + lll_mutex_unlock (cond->__data.__lock); + return err; + } + + /* We have one new user of the condvar. */ + ++cond->__data.__total_seq; + ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + + /* Remember the mutex we are using here. If there is already a + different address store this is a bad user bug. Do not store + anything for pshared condvars. */ + if (cond->__data.__mutex != (void *) ~0l) + cond->__data.__mutex = mutex; + + /* Prepare structure passed to cancellation handler. */ + cbuffer.cond = cond; + cbuffer.mutex = mutex; + + /* Before we block we enable cancellation. Therefore we have to + install a cancellation handler. */ + __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); + + /* The current values of the wakeup counter. The "woken" counter + must exceed this value. */ + unsigned long long int val; + unsigned long long int seq; + val = seq = cond->__data.__wakeup_seq; + /* Remember the broadcast counter. */ + cbuffer.bc_seq = cond->__data.__broadcast_seq; + + do + { + unsigned int futex_val = cond->__data.__futex; + + /* Prepare to wait. Release the condvar futex. */ + lll_mutex_unlock (cond->__data.__lock); + + /* Enable asynchronous cancellation. Required by the standard. */ + cbuffer.oldtype = __pthread_enable_asynccancel (); + + /* Wait until woken by signal or broadcast. */ + lll_futex_wait (&cond->__data.__futex, futex_val); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (cbuffer.oldtype); + + /* We are going to look at shared data again, so get the lock. */ + lll_mutex_lock (cond->__data.__lock); + + /* If a broadcast happened, we are done. */ + if (cbuffer.bc_seq != cond->__data.__broadcast_seq) + goto bc_out; + + /* Check whether we are eligible for wakeup. */ + val = cond->__data.__wakeup_seq; + } + while (val == seq || cond->__data.__woken_seq == val); + + /* Another thread woken up. */ + ++cond->__data.__woken_seq; + + bc_out: + + cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this varaible already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + if (cond->__data.__total_seq == -1ULL + && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + + /* We are done with the condvar. */ + lll_mutex_unlock (cond->__data.__lock); + + /* The cancellation handling is back to normal, remove the handler. */ + __pthread_cleanup_pop (&buffer, 0); + + /* Get the mutex before returning. */ + return __pthread_mutex_cond_lock (mutex); +} +weak_alias(__pthread_cond_wait, pthread_cond_wait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_once.c b/libpthread/nptl/sysdeps/pthread/pthread_once.c new file mode 100644 index 000000000..9b2cef864 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_once.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + + +static lll_lock_t once_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a + global lock variable or one which is part of the pthread_once_t + object. */ + if (*once_control == PTHREAD_ONCE_INIT) + { + lll_lock (once_lock); + + /* XXX This implementation is not complete. It doesn't take + cancelation and fork into account. */ + if (*once_control == PTHREAD_ONCE_INIT) + { + init_routine (); + + *once_control = !PTHREAD_ONCE_INIT; + } + + lll_unlock (once_lock); + } + + return 0; +} +strong_alias (__pthread_once, pthread_once) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 000000000..e225d7030 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Acquire read lock for RWLOCK. */ +int +__pthread_rwlock_rdlock (rwlock) + pthread_rwlock_t *rwlock; +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + while (1) + { + /* Get the rwlock if there is no writer... */ + if (rwlock->__data.__writer == 0 + /* ...and if either no writer is waiting or we prefer readers. */ + && (!rwlock->__data.__nr_writers_queued + || rwlock->__data.__flags == 0)) + { + /* Increment the reader counter. Avoid overflow. */ + if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) + { + /* Overflow on number of readers. */ + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Remember that we are a reader. */ + if (__builtin_expect (++rwlock->__data.__nr_readers_queued == 0, 0)) + { + /* Overflow on number of queued readers. */ + --rwlock->__data.__nr_readers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__readers_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer to finish. */ + lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + --rwlock->__data.__nr_readers_queued; + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} + +weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock) +strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c new file mode 100644 index 000000000..80ea83a3d --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire read lock for RWLOCK or return after specfied time. */ +int +pthread_rwlock_timedrdlock (rwlock, abstime) + pthread_rwlock_t *rwlock; + const struct timespec *abstime; +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock(rwlock->__data.__lock); + + while (1) + { + int err; + + /* Get the rwlock if there is no writer... */ + if (rwlock->__data.__writer == 0 + /* ...and if either no writer is waiting or we prefer readers. */ + && (!rwlock->__data.__nr_writers_queued + || rwlock->__data.__flags == 0)) + { + /* Increment the reader counter. Avoid overflow. */ + if (++rwlock->__data.__nr_readers == 0) + { + /* Overflow on number of readers. */ + --rwlock->__data.__nr_readers; + result = EAGAIN; + } + + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Make sure the passed in timeout value is valid. Ideally this + test would be executed once. But since it must not be + performed if we would not block at all simply moving the test + to the front is no option. Replicating all the code is + costly while this test is not. */ + if (__builtin_expect (abstime->tv_nsec >= 1000000000 + || abstime->tv_nsec < 0, 0)) + { + result = EINVAL; + break; + } + + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + struct timespec rt; + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (rt.tv_sec < 0) + { + /* Yep, return with an appropriate error. */ + result = ETIMEDOUT; + break; + } + + /* Remember that we are a reader. */ + if (++rwlock->__data.__nr_readers_queued == 0) + { + /* Overflow on number of queued readers. */ + --rwlock->__data.__nr_readers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__readers_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer to finish. */ + err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup, + waitval, &rt); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + --rwlock->__data.__nr_readers_queued; + + /* Did the futex call time out? */ + if (err == -ETIMEDOUT) + { + /* Yep, report it. */ + result = ETIMEDOUT; + break; + } + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c new file mode 100644 index 000000000..97c0598f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire write lock for RWLOCK or return after specfied time. */ +int +pthread_rwlock_timedwrlock (rwlock, abstime) + pthread_rwlock_t *rwlock; + const struct timespec *abstime; +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + while (1) + { + int err; + + /* Get the rwlock if there is no writer and no reader. */ + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + /* Mark self as writer. */ + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Make sure the passed in timeout value is valid. Ideally this + test would be executed once. But since it must not be + performed if we would not block at all simply moving the test + to the front is no option. Replicating all the code is + costly while this test is not. */ + if (__builtin_expect (abstime->tv_nsec >= 1000000000 + || abstime->tv_nsec < 0, 0)) + { + result = EINVAL; + break; + } + + /* Get the current time. So far we support only one clock. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + /* Convert the absolute timeout value to a relative timeout. */ + struct timespec rt; + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + /* Did we already time out? */ + if (rt.tv_sec < 0) + { + result = ETIMEDOUT; + break; + } + + /* Remember that we are a writer. */ + if (++rwlock->__data.__nr_writers_queued == 0) + { + /* Overflow on number of queued writers. */ + --rwlock->__data.__nr_writers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__writer_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer or reader(s) to finish. */ + err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup, + waitval, &rt); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + /* To start over again, remove the thread from the writer list. */ + --rwlock->__data.__nr_writers_queued; + + /* Did the futex call time out? */ + if (err == -ETIMEDOUT) + { + result = ETIMEDOUT; + break; + } + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c new file mode 100644 index 000000000..9cae8b6c2 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + +/* Unlock RWLOCK. */ +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + lll_mutex_lock (rwlock->__data.__lock); + if (rwlock->__data.__writer) + rwlock->__data.__writer = 0; + else + --rwlock->__data.__nr_readers; + if (rwlock->__data.__nr_readers == 0) + { + if (rwlock->__data.__nr_writers_queued) + { + ++rwlock->__data.__writer_wakeup; + lll_mutex_unlock (rwlock->__data.__lock); + lll_futex_wake (&rwlock->__data.__writer_wakeup, 1); + return 0; + } + else if (rwlock->__data.__nr_readers_queued) + { + ++rwlock->__data.__readers_wakeup; + lll_mutex_unlock (rwlock->__data.__lock); + lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX); + return 0; + } + } + lll_mutex_unlock (rwlock->__data.__lock); + return 0; +} + +weak_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock) +strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 000000000..822aeed79 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Acquire write lock for RWLOCK. */ +int +__pthread_rwlock_wrlock (rwlock) + pthread_rwlock_t *rwlock; +{ + int result = 0; + + /* Make sure we are along. */ + lll_mutex_lock (rwlock->__data.__lock); + + while (1) + { + /* Get the rwlock if there is no writer and no reader. */ + if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) + { + /* Mark self as writer. */ + rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); + break; + } + + /* Make sure we are not holding the rwlock as a writer. This is + a deadlock situation we recognize and report. */ + if (__builtin_expect (rwlock->__data.__writer + == THREAD_GETMEM (THREAD_SELF, tid), 0)) + { + result = EDEADLK; + break; + } + + /* Remember that we are a writer. */ + if (++rwlock->__data.__nr_writers_queued == 0) + { + /* Overflow on number of queued writers. */ + --rwlock->__data.__nr_writers_queued; + result = EAGAIN; + break; + } + + int waitval = rwlock->__data.__writer_wakeup; + + /* Free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + /* Wait for the writer or reader(s) to finish. */ + lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval); + + /* Get the lock. */ + lll_mutex_lock (rwlock->__data.__lock); + + /* To start over again, remove the thread from the writer list. */ + --rwlock->__data.__nr_writers_queued; + } + + /* We are done, free the lock. */ + lll_mutex_unlock (rwlock->__data.__lock); + + return result; +} + +weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock) +strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c new file mode 100644 index 000000000..0d12fe6bf --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <sysdep.h> + + +int +pthread_sigmask (how, newmask, oldmask) + int how; + const sigset_t *newmask; + sigset_t *oldmask; +{ + sigset_t local_newmask; + + /* The only thing we have to make sure here is that SIGCANCEL and + SIGSETXID is not blocked. */ + if (newmask != NULL + && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0) + || __builtin_expect (__sigismember (newmask, SIGSETXID), 0))) + { + local_newmask = *newmask; + __sigdelset (&local_newmask, SIGCANCEL); + __sigdelset (&local_newmask, SIGSETXID); + newmask = &local_newmask; + } + +#ifdef INTERNAL_SYSCALL + /* We know that realtime signals are available if NPTL is used. */ + INTERNAL_SYSCALL_DECL (err); + int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask, + oldmask, _NSIG / 8); + + return (INTERNAL_SYSCALL_ERROR_P (result, err) + ? INTERNAL_SYSCALL_ERRNO (result, err) + : 0); +#else + return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0; +#endif +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c new file mode 100644 index 000000000..4d0109cf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + + +int +pthread_spin_destroy (lock) + pthread_spinlock_t *lock; +{ + /* Nothing to do. */ + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c new file mode 100644 index 000000000..c2275085e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c @@ -0,0 +1,28 @@ +/* pthread_spin_init -- initialize a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c new file mode 100644 index 000000000..f97cadfbd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + atomic_full_barrier (); + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c new file mode 100644 index 000000000..743e675d4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c @@ -0,0 +1 @@ +#include <unwind-resume.c> diff --git a/libpthread/nptl/sysdeps/pthread/setxid.h b/libpthread/nptl/sysdeps/pthread/setxid.h new file mode 100644 index 000000000..8ec382f40 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/setxid.h @@ -0,0 +1,64 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <sysdep.h> + +#define __SETXID_1(cmd, arg1) \ + cmd.id[0] = arg1 +#define __SETXID_2(cmd, arg1, arg2) \ + __SETXID_1 (cmd, arg1); cmd.id[1] = arg2 +#define __SETXID_3(cmd, arg1, arg2, arg3) \ + __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = arg3 + +#ifdef SINGLE_THREAD +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + INLINE_SYSCALL (name, nr, args) +#elif defined SHARED +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + int __result; \ + if (__builtin_expect (__libc_pthread_functions.ptr__nptl_setxid \ + != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result = __libc_pthread_functions.ptr__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#else +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\ + int __result; \ + if (__builtin_expect (__nptl_setxid != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result =__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#endif diff --git a/libpthread/nptl/sysdeps/pthread/sigaction.c b/libpthread/nptl/sysdeps/pthread/sigaction.c new file mode 100644 index 000000000..54b5d2de4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigaction.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This is tricky. GCC doesn't like #include_next in the primary + source file and even if it did, the first #include_next is this + exact file anyway. */ +#ifndef LIBC_SIGACTION + +#include <pthreadP.h> + +/* We use the libc implementation but we tell it to not allow + SIGCANCEL or SIGTIMER to be handled. */ +# define LIBC_SIGACTION 1 + +# include <sigaction.c> + +int +sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + +int +__sigaction (int sig, const struct sigaction *act, struct sigaction *oact) +{ + if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0)) + { + __set_errno (EINVAL); + return -1; + } + + return __libc_sigaction (sig, act, oact); +} +libc_hidden_proto(sigaction) +weak_alias (__sigaction, sigaction) +libc_hidden_weak(sigaction) +#else + +# include_next <sigaction.c> + +#endif /* LIBC_SIGACTION */ diff --git a/libpthread/nptl/sysdeps/pthread/sigfillset.c b/libpthread/nptl/sysdeps/pthread/sigfillset.c new file mode 100644 index 000000000..fbe458f55 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigfillset.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + +#include <../../../../libc/signal/sigfillset.c> diff --git a/libpthread/nptl/sysdeps/pthread/sigprocmask.c b/libpthread/nptl/sysdeps/pthread/sigprocmask.c new file mode 100644 index 000000000..35aa843ba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigprocmask.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1997,1998,1999,2000,2001,2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#undef _LARGEFILE64_SOURCE + +#include <../../../../libc/sysdeps/linux/common/sigprocmask.c> diff --git a/libpthread/nptl/sysdeps/pthread/timer_create.c b/libpthread/nptl/sysdeps/pthread/timer_create.c new file mode 100644 index 000000000..2809ac744 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_create.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include <time.h> +#include <unistd.h> + +#include "posix-timer.h" + + +/* Create new per-process timer using CLOCK. */ +int +timer_create (clock_id, evp, timerid) + clockid_t clock_id; + struct sigevent *evp; + timer_t *timerid; +{ + int retval = -1; + struct timer_node *newtimer = NULL; + struct thread_node *thread = NULL; + + if (0 +#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 + || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 + || clock_id == CLOCK_THREAD_CPUTIME_ID +#endif + ) + { + /* We don't allow timers for CPU clocks. At least not in the + moment. */ + __set_errno (ENOTSUP); + return -1; + } + + if (clock_id != CLOCK_REALTIME) + { + __set_errno (EINVAL); + return -1; + } + + pthread_once (&__timer_init_once_control, __timer_init_once); + + if (__timer_init_failed) + { + __set_errno (ENOMEM); + return -1; + } + + pthread_mutex_lock (&__timer_mutex); + + newtimer = __timer_alloc (); + if (__builtin_expect (newtimer == NULL, 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + + if (evp != NULL) + newtimer->event = *evp; + else + { + newtimer->event.sigev_notify = SIGEV_SIGNAL; + newtimer->event.sigev_signo = SIGALRM; + newtimer->event.sigev_value.sival_ptr = timer_ptr2id (newtimer); + newtimer->event.sigev_notify_function = 0; + } + + newtimer->event.sigev_notify_attributes = &newtimer->attr; + newtimer->creator_pid = getpid (); + + switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) + { + case SIGEV_NONE: + case SIGEV_SIGNAL: + /* We have a global thread for delivering timed signals. + If it is not running, try to start it up. */ + thread = &__timer_signal_thread_rclk; + if (! thread->exists) + { + if (__builtin_expect (__timer_thread_start (thread), + 1) < 0) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + } + break; + + case SIGEV_THREAD: + /* Copy over thread attributes or set up default ones. */ + if (evp->sigev_notify_attributes) + newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; + else + pthread_attr_init (&newtimer->attr); + + /* Ensure thread attributes call for deatched thread. */ + pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); + + /* Try to find existing thread having the right attributes. */ + thread = __timer_thread_find_matching (&newtimer->attr, clock_id); + + /* If no existing thread has these attributes, try to allocate one. */ + if (thread == NULL) + thread = __timer_thread_alloc (&newtimer->attr, clock_id); + + /* Out of luck; no threads are available. */ + if (__builtin_expect (thread == NULL, 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + + /* If the thread is not running already, try to start it. */ + if (! thread->exists + && __builtin_expect (! __timer_thread_start (thread), 0)) + { + __set_errno (EAGAIN); + goto unlock_bail; + } + break; + + default: + __set_errno (EINVAL); + goto unlock_bail; + } + + newtimer->clock = clock_id; + newtimer->abstime = 0; + newtimer->armed = 0; + newtimer->thread = thread; + + *timerid = timer_ptr2id (newtimer); + retval = 0; + + if (__builtin_expect (retval, 0) == -1) + { + unlock_bail: + if (thread != NULL) + __timer_thread_dealloc (thread); + if (newtimer != NULL) + { + timer_delref (newtimer); + __timer_dealloc (newtimer); + } + } + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_delete.c b/libpthread/nptl/sysdeps/pthread/timer_delete.c new file mode 100644 index 000000000..48ba1f272 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_delete.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID. */ +int +timer_delete (timerid) + timer_t timerid; +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + timer = timer_id2ptr (timerid); + if (! timer_valid (timer)) + /* Invalid timer ID or the timer is not in use. */ + __set_errno (EINVAL); + else + { + if (timer->armed && timer->thread != NULL) + { + struct thread_node *thread = timer->thread; + assert (thread != NULL); + + /* If thread is cancelled while waiting for handler to terminate, + the mutex is unlocked and timer_delete is aborted. */ + pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); + + /* If timer is currently being serviced, wait for it to finish. */ + while (thread->current_timer == timer) + pthread_cond_wait (&thread->cond, &__timer_mutex); + + pthread_cleanup_pop (0); + } + + /* Remove timer from whatever queue it may be on and deallocate it. */ + timer->inuse = TIMER_DELETED; + list_unlink_ip (&timer->links); + timer_delref (timer); + retval = 0; + } + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_getoverr.c b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c new file mode 100644 index 000000000..f3e22215b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get expiration overrun for timer TIMERID. */ +int +timer_getoverrun (timerid) + timer_t timerid; +{ + struct timer_node *timer; + int retval = -1; + + pthread_mutex_lock (&__timer_mutex); + + if (! timer_valid (timer = timer_id2ptr (timerid))) + __set_errno (EINVAL); + else + retval = timer->overrun_count; + + pthread_mutex_unlock (&__timer_mutex); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_gettime.c b/libpthread/nptl/sysdeps/pthread/timer_gettime.c new file mode 100644 index 000000000..723a61632 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_gettime.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2000, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get current value of timer TIMERID and store it in VLAUE. */ +int +timer_gettime (timerid, value) + timer_t timerid; + struct itimerspec *value; +{ + struct timer_node *timer; + struct timespec now, expiry; + int retval = -1, armed = 0, valid; + clock_t clock = 0; + + pthread_mutex_lock (&__timer_mutex); + + timer = timer_id2ptr (timerid); + valid = timer_valid (timer); + + if (valid) { + armed = timer->armed; + expiry = timer->expirytime; + clock = timer->clock; + value->it_interval = timer->value.it_interval; + } + + pthread_mutex_unlock (&__timer_mutex); + + if (valid) + { + if (armed) + { + clock_gettime (clock, &now); + if (timespec_compare (&now, &expiry) < 0) + timespec_sub (&value->it_value, &expiry, &now); + else + { + value->it_value.tv_sec = 0; + value->it_value.tv_nsec = 0; + } + } + else + { + value->it_value.tv_sec = 0; + value->it_value.tv_nsec = 0; + } + + retval = 0; + } + else + __set_errno (EINVAL); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_routines.c b/libpthread/nptl/sysdeps/pthread/timer_routines.c new file mode 100644 index 000000000..8d5b1d13a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_routines.c @@ -0,0 +1,578 @@ +/* Helper code for POSIX timer implementation on NPTL. + Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include "posix-timer.h" +#include <pthreadP.h> + + +/* Number of threads used. */ +#define THREAD_MAXNODES 16 + +/* Array containing the descriptors for the used threads. */ +static struct thread_node thread_array[THREAD_MAXNODES]; + +/* Static array with the structures for all the timers. */ +struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists. */ +pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Variable to protext initialization. */ +pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT; + +/* Nonzero if initialization of timer implementation failed. */ +int __timer_init_failed; + +/* Node for the thread used to deliver signals. */ +struct thread_node __timer_signal_thread_rclk; + +/* Lists to keep free and used timers and threads. */ +struct list_links timer_free_list; +struct list_links thread_free_list; +struct list_links thread_active_list; + + +#ifdef __NR_rt_sigqueueinfo +extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *); +#endif + + +/* List handling functions. */ +static inline void +list_init (struct list_links *list) +{ + list->next = list->prev = list; +} + +static inline void +list_append (struct list_links *list, struct list_links *newp) +{ + newp->prev = list->prev; + newp->next = list; + list->prev->next = newp; + list->prev = newp; +} + +static inline void +list_insbefore (struct list_links *list, struct list_links *newp) +{ + list_append (list, newp); +} + +/* + * Like list_unlink_ip, except that calling it on a node that + * is already unlinked is disastrous rather than a noop. + */ + +static inline void +list_unlink (struct list_links *list) +{ + struct list_links *lnext = list->next, *lprev = list->prev; + + lnext->prev = lprev; + lprev->next = lnext; +} + +static inline struct list_links * +list_first (struct list_links *list) +{ + return list->next; +} + +static inline struct list_links * +list_null (struct list_links *list) +{ + return list; +} + +static inline struct list_links * +list_next (struct list_links *list) +{ + return list->next; +} + +static inline int +list_isempty (struct list_links *list) +{ + return list->next == list; +} + + +/* Functions build on top of the list functions. */ +static inline struct thread_node * +thread_links2ptr (struct list_links *list) +{ + return (struct thread_node *) ((char *) list + - offsetof (struct thread_node, links)); +} + +static inline struct timer_node * +timer_links2ptr (struct list_links *list) +{ + return (struct timer_node *) ((char *) list + - offsetof (struct timer_node, links)); +} + + +/* Initialize a newly allocated thread structure. */ +static void +thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id) +{ + if (attr != NULL) + thread->attr = *attr; + else + { + pthread_attr_init (&thread->attr); + pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED); + } + + thread->exists = 0; + list_init (&thread->timer_queue); + pthread_cond_init (&thread->cond, 0); + thread->current_timer = 0; + thread->captured = pthread_self (); + thread->clock_id = clock_id; +} + + +/* Initialize the global lists, and acquire global resources. Error + reporting is done by storing a non-zero value to the global variable + timer_init_failed. */ +static void +init_module (void) +{ + int i; + + list_init (&timer_free_list); + list_init (&thread_free_list); + list_init (&thread_active_list); + + for (i = 0; i < TIMER_MAX; ++i) + { + list_append (&timer_free_list, &__timer_array[i].links); + __timer_array[i].inuse = TIMER_FREE; + } + + for (i = 0; i < THREAD_MAXNODES; ++i) + list_append (&thread_free_list, &thread_array[i].links); + + thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME); +} + + +/* This is a handler executed in a child process after a fork() + occurs. It reinitializes the module, resetting all of the data + structures to their initial state. The mutex is initialized in + case it was locked in the parent process. */ +static void +reinit_after_fork (void) +{ + init_module (); + pthread_mutex_init (&__timer_mutex, 0); +} + + +/* Called once form pthread_once in timer_init. This initializes the + module and ensures that reinit_after_fork will be executed in any + child process. */ +void +__timer_init_once (void) +{ + init_module (); + pthread_atfork (0, 0, reinit_after_fork); +} + + +/* Deinitialize a thread that is about to be deallocated. */ +static void +thread_deinit (struct thread_node *thread) +{ + assert (list_isempty (&thread->timer_queue)); + pthread_cond_destroy (&thread->cond); +} + + +/* Allocate a thread structure from the global free list. Global + mutex lock must be held by caller. The thread is moved to + the active list. */ +struct thread_node * +__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id) +{ + struct list_links *node = list_first (&thread_free_list); + + if (node != list_null (&thread_free_list)) + { + struct thread_node *thread = thread_links2ptr (node); + list_unlink (node); + thread_init (thread, desired_attr, clock_id); + list_append (&thread_active_list, node); + return thread; + } + + return 0; +} + + +/* Return a thread structure to the global free list. Global lock + must be held by caller. */ +void +__timer_thread_dealloc (struct thread_node *thread) +{ + thread_deinit (thread); + list_unlink (&thread->links); + list_append (&thread_free_list, &thread->links); +} + + +/* Each of our threads which terminates executes this cleanup + handler. We never terminate threads ourselves; if a thread gets here + it means that the evil application has killed it. If the thread has + timers, these require servicing and so we must hire a replacement + thread right away. We must also unblock another thread that may + have been waiting for this thread to finish servicing a timer (see + timer_delete()). */ + +static void +thread_cleanup (void *val) +{ + if (val != NULL) + { + struct thread_node *thread = val; + + /* How did the signal thread get killed? */ + assert (thread != &__timer_signal_thread_rclk); + + pthread_mutex_lock (&__timer_mutex); + + thread->exists = 0; + + /* We are no longer processing a timer event. */ + thread->current_timer = 0; + + if (list_isempty (&thread->timer_queue)) + __timer_thread_dealloc (thread); + else + (void) __timer_thread_start (thread); + + pthread_mutex_unlock (&__timer_mutex); + + /* Unblock potentially blocked timer_delete(). */ + pthread_cond_broadcast (&thread->cond); + } +} + + +/* Handle a timer which is supposed to go off now. */ +static void +thread_expire_timer (struct thread_node *self, struct timer_node *timer) +{ + self->current_timer = timer; /* Lets timer_delete know timer is running. */ + + pthread_mutex_unlock (&__timer_mutex); + + switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL)) + { + case SIGEV_NONE: + break; + + case SIGEV_SIGNAL: +#ifdef __NR_rt_sigqueueinfo + { + siginfo_t info; + + /* First, clear the siginfo_t structure, so that we don't pass our + stack content to other tasks. */ + memset (&info, 0, sizeof (siginfo_t)); + /* We must pass the information about the data in a siginfo_t + value. */ + info.si_signo = timer->event.sigev_signo; + info.si_code = SI_TIMER; + info.si_pid = timer->creator_pid; + info.si_uid = getuid (); + info.si_value = timer->event.sigev_value; + + INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info); + } +#else + if (pthread_kill (self->captured, timer->event.sigev_signo) != 0) + { + if (pthread_kill (self->id, timer->event.sigev_signo) != 0) + abort (); + } +#endif + break; + + case SIGEV_THREAD: + timer->event.sigev_notify_function (timer->event.sigev_value); + break; + + default: + assert (! "unknown event"); + break; + } + + pthread_mutex_lock (&__timer_mutex); + + self->current_timer = 0; + + pthread_cond_broadcast (&self->cond); +} + + +/* Thread function; executed by each timer thread. The job of this + function is to wait on the thread's timer queue and expire the + timers in chronological order as close to their scheduled time as + possible. */ +static void +__attribute__ ((noreturn)) +thread_func (void *arg) +{ + struct thread_node *self = arg; + + /* Register cleanup handler, in case rogue application terminates + this thread. (This cannot happen to __timer_signal_thread, which + doesn't invoke application callbacks). */ + + pthread_cleanup_push (thread_cleanup, self); + + pthread_mutex_lock (&__timer_mutex); + + while (1) + { + struct list_links *first; + struct timer_node *timer = NULL; + + /* While the timer queue is not empty, inspect the first node. */ + first = list_first (&self->timer_queue); + if (first != list_null (&self->timer_queue)) + { + struct timespec now; + + timer = timer_links2ptr (first); + + /* This assumes that the elements of the list of one thread + are all for the same clock. */ + clock_gettime (timer->clock, &now); + + while (1) + { + /* If the timer is due or overdue, remove it from the queue. + If it's a periodic timer, re-compute its new time and + requeue it. Either way, perform the timer expiry. */ + if (timespec_compare (&now, &timer->expirytime) < 0) + break; + + list_unlink_ip (first); + + if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0 + || timer->value.it_interval.tv_nsec != 0) + { + timer->overrun_count = 0; + timespec_add (&timer->expirytime, &timer->expirytime, + &timer->value.it_interval); + while (timespec_compare (&timer->expirytime, &now) < 0) + { + timespec_add (&timer->expirytime, &timer->expirytime, + &timer->value.it_interval); + if (timer->overrun_count < DELAYTIMER_MAX) + ++timer->overrun_count; + } + __timer_thread_queue_timer (self, timer); + } + + thread_expire_timer (self, timer); + + first = list_first (&self->timer_queue); + if (first == list_null (&self->timer_queue)) + break; + + timer = timer_links2ptr (first); + } + } + + /* If the queue is not empty, wait until the expiry time of the + first node. Otherwise wait indefinitely. Insertions at the + head of the queue must wake up the thread by broadcasting + this condition variable. */ + if (timer != NULL) + pthread_cond_timedwait (&self->cond, &__timer_mutex, + &timer->expirytime); + else + pthread_cond_wait (&self->cond, &__timer_mutex); + } + /* This macro will never be executed since the while loop loops + forever - but we have to add it for proper nesting. */ + pthread_cleanup_pop (1); +} + + +/* Enqueue a timer in wakeup order in the thread's timer queue. + Returns 1 if the timer was inserted at the head of the queue, + causing the queue's next wakeup time to change. */ + +int +__timer_thread_queue_timer (struct thread_node *thread, + struct timer_node *insert) +{ + struct list_links *iter; + int athead = 1; + + for (iter = list_first (&thread->timer_queue); + iter != list_null (&thread->timer_queue); + iter = list_next (iter)) + { + struct timer_node *timer = timer_links2ptr (iter); + + if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0) + break; + athead = 0; + } + + list_insbefore (iter, &insert->links); + return athead; +} + + +/* Start a thread and associate it with the given thread node. Global + lock must be held by caller. */ +int +__timer_thread_start (struct thread_node *thread) +{ + int retval = 1; + + assert (!thread->exists); + thread->exists = 1; + + if (pthread_create (&thread->id, &thread->attr, + (void *(*) (void *)) thread_func, thread) != 0) + { + thread->exists = 0; + retval = -1; + } + + return retval; +} + + +void +__timer_thread_wakeup (struct thread_node *thread) +{ + pthread_cond_broadcast (&thread->cond); +} + + +/* Compare two pthread_attr_t thread attributes for exact equality. + Returns 1 if they are equal, otherwise zero if they are not equal + or contain illegal values. This version is NPTL-specific for + performance reason. One could use the access functions to get the + values of all the fields of the attribute structure. */ +static int +thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right) +{ + struct pthread_attr *ileft = (struct pthread_attr *) left; + struct pthread_attr *iright = (struct pthread_attr *) right; + + return (ileft->flags == iright->flags + && ileft->schedpolicy == iright->schedpolicy + && (ileft->schedparam.sched_priority + == iright->schedparam.sched_priority) + && ileft->guardsize == iright->guardsize + && ileft->stackaddr == iright->stackaddr + && ileft->stacksize == iright->stacksize + && ((ileft->cpuset == NULL && iright->cpuset == NULL) + || (ileft->cpuset != NULL && iright->cpuset != NULL + && ileft->cpusetsize == iright->cpusetsize + && memcmp (ileft->cpuset, iright->cpuset, + ileft->cpusetsize) == 0))); +} + + +/* Search the list of active threads and find one which has matching + attributes. Global mutex lock must be held by caller. */ +struct thread_node * +__timer_thread_find_matching (const pthread_attr_t *desired_attr, + clockid_t desired_clock_id) +{ + struct list_links *iter = list_first (&thread_active_list); + + while (iter != list_null (&thread_active_list)) + { + struct thread_node *candidate = thread_links2ptr (iter); + + if (thread_attr_compare (desired_attr, &candidate->attr) + && desired_clock_id == candidate->clock_id) + return candidate; + + iter = list_next (iter); + } + + return NULL; +} + + +/* Grab a free timer structure from the global free list. The global + lock must be held by the caller. */ +struct timer_node * +__timer_alloc (void) +{ + struct list_links *node = list_first (&timer_free_list); + + if (node != list_null (&timer_free_list)) + { + struct timer_node *timer = timer_links2ptr (node); + list_unlink_ip (node); + timer->inuse = TIMER_INUSE; + timer->refcount = 1; + return timer; + } + + return NULL; +} + + +/* Return a timer structure to the global free list. The global lock + must be held by the caller. */ +void +__timer_dealloc (struct timer_node *timer) +{ + assert (timer->refcount == 0); + timer->thread = NULL; /* Break association between timer and thread. */ + timer->inuse = TIMER_FREE; + list_append (&timer_free_list, &timer->links); +} + + +/* Thread cancellation handler which unlocks a mutex. */ +void +__timer_mutex_cancel_handler (void *arg) +{ + pthread_mutex_unlock (arg); +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_settime.c b/libpthread/nptl/sysdeps/pthread/timer_settime.c new file mode 100644 index 000000000..592b5271b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_settime.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */ +int +timer_settime (timerid, flags, value, ovalue) + timer_t timerid; + int flags; + const struct itimerspec *value; + struct itimerspec *ovalue; +{ + struct timer_node *timer; + struct thread_node *thread = NULL; + struct timespec now; + int have_now = 0, need_wakeup = 0; + int retval = -1; + + timer = timer_id2ptr (timerid); + if (timer == NULL) + { + __set_errno (EINVAL); + goto bail; + } + + if (value->it_interval.tv_nsec < 0 + || value->it_interval.tv_nsec >= 1000000000 + || value->it_value.tv_nsec < 0 + || value->it_value.tv_nsec >= 1000000000) + { + __set_errno (EINVAL); + goto bail; + } + + /* Will need to know current time since this is a relative timer; + might as well make the system call outside of the lock now! */ + + if ((flags & TIMER_ABSTIME) == 0) + { + clock_gettime (timer->clock, &now); + have_now = 1; + } + + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + + /* One final check of timer validity; this one is possible only + until we have the mutex, because it accesses the inuse flag. */ + + if (! timer_valid(timer)) + { + __set_errno (EINVAL); + goto unlock_bail; + } + + if (ovalue != NULL) + { + ovalue->it_interval = timer->value.it_interval; + + if (timer->armed) + { + if (! have_now) + { + pthread_mutex_unlock (&__timer_mutex); + clock_gettime (timer->clock, &now); + have_now = 1; + pthread_mutex_lock (&__timer_mutex); + timer_addref (timer); + } + + timespec_sub (&ovalue->it_value, &timer->expirytime, &now); + } + else + { + ovalue->it_value.tv_sec = 0; + ovalue->it_value.tv_nsec = 0; + } + } + + timer->value = *value; + + list_unlink_ip (&timer->links); + timer->armed = 0; + + thread = timer->thread; + + /* A value of { 0, 0 } causes the timer to be stopped. */ + if (value->it_value.tv_sec != 0 + || __builtin_expect (value->it_value.tv_nsec != 0, 1)) + { + if ((flags & TIMER_ABSTIME) != 0) + /* The user specified the expiration time. */ + timer->expirytime = value->it_value; + else + timespec_add (&timer->expirytime, &now, &value->it_value); + + /* Only need to wake up the thread if timer is inserted + at the head of the queue. */ + if (thread != NULL) + need_wakeup = __timer_thread_queue_timer (thread, timer); + timer->armed = 1; + } + + retval = 0; + +unlock_bail: + timer_delref (timer); + pthread_mutex_unlock (&__timer_mutex); + +bail: + if (thread != NULL && need_wakeup) + __timer_thread_wakeup (thread); + + return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c new file mode 100644 index 000000000..8b1f24407 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#include <pthreadP.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, + struct _Unwind_Context *); +static _Unwind_Reason_Code (*libgcc_s_forcedunwind) + (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); +static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *); + +void +pthread_cancel_init (void) +{ + void *resume, *personality, *forcedunwind, *getcfa; + void *handle; + + if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) + return; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + if (handle == NULL + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL + || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) + == NULL + || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT + || ARCH_CANCEL_INIT (handle) +#endif + ) + { + printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort(); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; + libgcc_s_forcedunwind = forcedunwind; + libgcc_s_getcfa = getcfa; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + if (__builtin_expect (libgcc_s_resume == NULL, 0)) + pthread_cancel_init (); + libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_personality (version, actions, exception_class, + ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, + void *stop_argument) +{ + if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_getcfa (context); +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-resume.c b/libpthread/nptl/sysdeps/pthread/unwind-resume.c new file mode 100644 index 000000000..018d2fd2f --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-resume.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <unwind.h> + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, + struct _Unwind_Context *); + +extern +void abort(void); + +static void +init (void) +{ + void *resume = NULL; + void *personality = NULL; + void *handle; + resume = personality = NULL; /* make gcc silent */ + handle = dlopen ("libgcc_s.so.1", (RTLD_LOCAL | RTLD_LAZY)); + + if (handle == NULL + || (resume = dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = dlsym (handle, "__gcc_personality_v0")) == NULL) + { + printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort(); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + if (__builtin_expect (libgcc_s_resume == NULL, 0)) + init (); + libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + init (); + return libgcc_s_personality (version, actions, exception_class, + ue_header, context); +} diff --git a/libpthread/nptl/sysdeps/sh/Makefile b/libpthread/nptl/sysdeps/sh/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sh/Makefile.arch b/libpthread/nptl/sysdeps/sh/Makefile.arch new file mode 100644 index 000000000..83db10fbe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile.arch @@ -0,0 +1,56 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_unlock.S pthread_spin_trylock.S +libpthread_CSRC = pthread_spin_lock.c pthread_spin_init.c + +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sh = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sh/dl-tls.h b/libpthread/nptl/sysdeps/sh/dl-tls.h new file mode 100644 index 000000000..98e2f1904 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. SH version. + Copyright (C) 2002 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h new file mode 100644 index 000000000..41c3c3984 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(jmpbuf, address, adj) \ + ((uintptr_t) (address) - (adj) < (uintptr_t) (jmpbuf)[0].__regs[7] - (adj)) + +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_init.c b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c new file mode 100644 index 000000000..d158183f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (lock) + pthread_spinlock_t *lock; +{ + unsigned int val; + + do + __asm__ volatile ("tas.b @%1; movt %0" + : "=&r" (val) + : "r" (lock) + : "memory"); + while (val == 0); + + return 0; +} diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S new file mode 100644 index 000000000..18112ba23 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S @@ -0,0 +1,32 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 5 +pthread_spin_trylock: + tas.b @r4 + bf/s 1f + mov #EBUSY, r0 + mov #0, r0 +1: + rts + nop + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S new file mode 100644 index 000000000..c77acaffe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 5 +pthread_spin_unlock: + mov #0,r0 + rts + mov.l r0,@r4 + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/sh/pthreaddef.h b/libpthread/nptl/sysdeps/sh/pthreaddef.h new file mode 100644 index 000000000..c1902fb54 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthreaddef.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 8 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 8 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + while (1) { \ + if (__builtin_constant_p (val) && (val) == 0) \ + __asm__ volatile ("mov #0,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD \ + :: "i" (__NR_exit)); \ + else \ + __asm__ volatile ("mov %1,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD \ + :: "i" (__NR_exit), "r" (val)); \ + } diff --git a/libpthread/nptl/sysdeps/sh/sysdep.h b/libpthread/nptl/sysdeps/sh/sysdep.h new file mode 100644 index 000000000..5b75198f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/sysdep.h @@ -0,0 +1,82 @@ +/* Assembler macros for SH. + Copyright (C) 1999, 2000, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#include <features.h> +#include <libc-internal.h> + +#ifdef __ASSEMBLER__ + +/* Syntactic details of assembler. */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,@##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +#ifdef SHARED +#define PLTJMP(_x) _x##@PLT +#else +#define PLTJMP(_x) _x +#endif + +/* Define an entry point visible from C. */ +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function) \ + .align ALIGNARG(5); \ + C_LABEL(name) \ + cfi_startproc; \ + CALL_MCOUNT + +#undef END +#define END(name) \ + cfi_endproc; \ + ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(name)) + +/* If compiled for profiling, call `mcount' at the start of each function. */ +#ifdef PROF +#define CALL_MCOUNT \ + mov.l 1f,r1; \ + sts.l pr,@-r15; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (pr, 0); \ + mova 2f,r0; \ + jmp @r1; \ + lds r0,pr; \ + .align 2; \ +1: .long mcount; \ +2: lds.l @r15+,pr; \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (pr) + +#else +#define CALL_MCOUNT /* Do nothing. */ +#endif + +#ifdef __UCLIBC_UNDERSCORES__ +/* Since C identifiers are not normally prefixed with an underscore + on this system, the asm identifier `syscall_error' intrudes on the + C name space. Make sure we use an innocuous name. */ +#define syscall_error __syscall_error +#define mcount _mcount +#endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/sh/tcb-offsets.sym b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym new file mode 100644 index 000000000..539789a81 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +TLS_PRE_TCB_SIZE sizeof (struct pthread) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/sh/tls.h b/libpthread/nptl/sysdeps/sh/tls.h new file mode 100644 index 000000000..5e5ce12b0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tls.h @@ -0,0 +1,142 @@ +/* Definition for thread-local data handling. NPTL/SH version. + Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include <sysdep.h> + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* The TLS blocks start right after the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include <descr.h> + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ tcbhead_t *__tcbp; \ + __asm __volatile ("stc gbr,%0" : "=r" (__tcbp)); \ + __tcbp->dtv = (dtv);}) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ __asm __volatile ("ldc %0,gbr" : : "r" (tcbp)); 0; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ tcbhead_t *__tcbp; \ + __asm __volatile ("stc gbr,%0" : "=r" (__tcbp)); \ + __tcbp->dtv;}) + +/* Return the thread descriptor for the current thread. + The contained asm must *not* be marked volatile since otherwise + assignments like + struct pthread *self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__thread_self; \ + __asm ("stc gbr,%0" : "=r" (__thread_self)); \ + __thread_self - 1;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread)) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) (descr->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) (descr->member[idx]) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/sparc/Makefile b/libpthread/nptl/sysdeps/sparc/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sparc/Makefile.arch b/libpthread/nptl/sysdeps/sparc/Makefile.arch new file mode 100644 index 000000000..b13eee9f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = sparc32/pthread_spin_lock.c \ + sparc32/pthread_spin_trylock.c + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sparc = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sparc/dl-tls.h b/libpthread/nptl/sysdeps/sparc/dl-tls.h new file mode 100644 index 000000000..6edf8d525 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. SPARC version. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h new file mode 100644 index 000000000..6cbb37baf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/jmpbuf-unwind.h" +#else +#include "sparc32/jmpbuf-unwind.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/pthreaddef.h new file mode 100644 index 000000000..d4695c47d --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/pthreaddef.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pthreaddef.h" +#else +#include "sparc32/pthreaddef.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h new file mode 100644 index 000000000..b9528f363 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c new file mode 100644 index 000000000..d3c6e3049 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g2\n" + " orcc %%g2, 0x0, %%g0\n" + " bne,a 2f\n" + " ldub [%0], %%g2\n" + ".subsection 2\n" + "2: orcc %%g2, 0x0, %%g0\n" + " bne,a 2b\n" + " ldub [%0], %%g2\n" + " b,a 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g2", "memory", "cc"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c new file mode 100644 index 000000000..bcc3158fd --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int res; + __asm __volatile ("ldstub [%1], %0" : "=r" (res) : "r" (lock) : "memory"); + return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h new file mode 100644 index 000000000..9908df9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 64)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c new file mode 100644 index 000000000..8880f535b --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g2\n" + " brnz,pn %%g2, 2f\n" + " membar #StoreLoad | #StoreStore\n" + ".subsection 2\n" + "2: ldub [%0], %%g2\n" + " brnz,pt %%g2, 2b\n" + " membar #LoadLoad\n" + " b,a,pt %%xcc, 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g2", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c new file mode 100644 index 000000000..3b20a2180 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_trylock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c new file mode 100644 index 000000000..482cbe3d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_unlock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c new file mode 100644 index 000000000..77171d9b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + __asm __volatile + ("1: ldstub [%0], %%g5\n" + " brnz,pn %%g5, 2f\n" + " membar #StoreLoad | #StoreStore\n" + ".subsection 2\n" + "2: ldub [%0], %%g5\n" + " brnz,pt %%g5, 2b\n" + " membar #LoadLoad\n" + " b,a,pt %%xcc, 1b\n" + ".previous" + : /* no outputs */ + : "r" (lock) + : "g5", "memory"); + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c new file mode 100644 index 000000000..2bda809da --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + int res; + __asm __volatile + ("ldstub [%1], %0\n" + "membar #StoreLoad | #StoreStore" + : "=r" (res) + : "r" (lock) + : "memory"); + return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c new file mode 100644 index 000000000..7037675a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock. Generic version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + __asm __volatile ("membar #StoreStore | #LoadStore"); + *lock = 0; + return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h new file mode 100644 index 000000000..ec7651211 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 4096 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 128)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym new file mode 100644 index 000000000..237f975b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym @@ -0,0 +1,6 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +PID offsetof (struct pthread, pid) +TID offsetof (struct pthread, tid) diff --git a/libpthread/nptl/sysdeps/sparc/tls.h b/libpthread/nptl/sysdeps/sparc/tls.h new file mode 100644 index 000000000..e5d27fb57 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tls.h @@ -0,0 +1,139 @@ +/* Definitions for thread-local data handling. NPTL/sparc version. + Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + +register struct pthread *__thread_self __asm__("%g7"); + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* Get the thread descriptor definition. */ +# include <descr.h> + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(DTV) \ + (((tcbhead_t *) __thread_self)->dtv = (DTV)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. */ +# define TLS_INIT_TP(descr, secondcall) \ + (__thread_self = (__typeof (__thread_self)) (descr), NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) __thread_self)->dtv) + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF_INCLUDE <sys/ucontext.h> +# define DB_THREAD_SELF \ + REGISTER (32, 32, REG_G7 * 4, 0) REGISTER (64, 64, REG_G7 * 8, 0) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* Set the stack guard field in TCB head. */ +#define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + +#endif /* !ASSEMBLER */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/unix/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sh/sysdep.h new file mode 100644 index 000000000..bf1ac0fd4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sh/sysdep.h @@ -0,0 +1,29 @@ +/* Copyright (C) 1999, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/unix/sysdep.h> +#include <sysdeps/sh/sysdep.h> + +#ifdef __ASSEMBLER__ + +#define ret rts ; nop + +/* The sh move insn is s, d. */ +#define MOVE(x,y) mov x , y + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysdep.h b/libpthread/nptl/sysdeps/unix/sysdep.h new file mode 100644 index 000000000..0e7c9da5a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysdep.h @@ -0,0 +1,63 @@ +/* Copyright (C) 1991, 92, 93, 96, 98, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdeps/generic/sysdep.h> + +#include <sys/syscall.h> +#define HAVE_SYSCALLS + +/* Note that using a `PASTE' macro loses. */ +#ifdef __STDC__ +#define SYSCALL__(name, args) PSEUDO (__##name, name, args) +#else +#define SYSCALL__(name, args) PSEUDO (__/**/name, name, args) +#endif +#define SYSCALL(name, args) PSEUDO (name, name, args) + +/* Machine-dependent sysdep.h files are expected to define the macro + PSEUDO (function_name, syscall_name) to emit assembly code to define the + C-callable function FUNCTION_NAME to do system call SYSCALL_NAME. + r0 and r1 are the system call outputs. MOVE(x, y) should be defined as + an instruction such that "MOVE(r1, r0)" works. ret should be defined + as the return instruction. */ + +#ifndef SYS_ify +#ifdef __STDC__ +#define SYS_ify(syscall_name) SYS_##syscall_name +#else +#define SYS_ify(syscall_name) SYS_/**/syscall_name +#endif +#endif + +/* Terminate a system call named SYM. This is used on some platforms + to generate correct debugging information. */ +#ifndef PSEUDO_END +#define PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) PSEUDO_END(sym) +#endif + +/* Wrappers around system calls should normally inline the system call code. + But sometimes it is not possible or implemented and we use this code. */ +#ifndef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 000000000..34d647527 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../ +top_builddir=../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in new file mode 100644 index 000000000..563b6c1cc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in @@ -0,0 +1,207 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_attr_getaffinity.c \ + pthread_attr_setaffinity.c pthread_getaffinity.c \ + pthread_getcpuclockid.c pthread_kill.c \ + pthread_mutex_cond_lock.c pthread_setaffinity.c \ + pthread_yield.c sem_post.c sem_timedwait.c \ + sem_trywait.c sem_wait.c pt-fork.c \ + sigtimedwait.c sigwaitinfo.c sigwait.c pt-sleep.c + +libpthread_SSRC = #ptw-close.S ptw-open.S ptw-waitid.S ptw-waidpid.S ptw-write.S + +libc_CSRC = libc_pthread_init.c libc_multiple_threads.c \ + register-atfork.c unregister-atfork.c getpid.c \ + raise.c sleep.c jmp-unwind.c + +# These provide both a cancellable and a not cancellable implementation +libc_SSRC = close.S open.S write.S read.S + +ifneq ($(TARGET_ARCH),arm) +libc_SSRC += waitpid.S +endif + +librt_CSRC := mq_notify.c timer_create.c timer_delete.c \ + timer_getoverr.c timer_gettime.c timer_routines.c \ + timer_settime.c + + +ifeq ($(TARGET_ARCH),alpha) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),mips) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +endif + +ifeq ($(TARGET_ARCH),powerpc) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),sparc) +libpthread_CSRC += __syscall_error.c +librt_CSRC := mq_notify.c __syscall_error.c +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(SH_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(X86_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + + +ifeq ($(TARGET_ARCH),x86_64) +librt_CSRC := mq_notify.c +endif + +CFLAGS-pthread_getcpuclockid.c = -I$(top_srcdir)librt +CFLAGS-pt-pread_pwrite.c = -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \ + -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-mq_notify.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_create.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_delete.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_getoverr.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_gettime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_routines.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_settime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 + +CFLAGS-linux = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +CFLAGS-OMIT-libc_pthread_init.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc_multiple_threads.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-register-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-unregister-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-getpid.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-sleep.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-close.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-open.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-read.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-write.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-waitpid.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-mq_notify.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_create.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_delete.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_getoverr.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_gettime.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_routines.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_settime.c = -DIS_IN_libpthread=1 + +PTHREAD_LINUX_DIR := $(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux +PTHREAD_LINUX_OUT := $(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux + +PTHREAD_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_CSRC)) +PTHREAD_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_LINUX_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_LINUX_OBJ) +endif +libpthread-so-y += $(PTHREAD_LINUX_OBJ:.o=.oS) +libpthread-so-y += $(PTHREAD_LINUX_OUT)/pt-raise.oS +libpthread-nomulti-y += $(PTHREAD_LINUX_OBJ) + +ASFLAGS-open.S = -D_LIBC_REENTRANT +ASFLAGS-close.S = -D_LIBC_REENTRANT +ASFLAGS-read.S = -D_LIBC_REENTRANT +ASFLAGS-write.S = -D_LIBC_REENTRANT +ASFLAGS-waitpid.S = -D_LIBC_REENTRANT + +LIBC_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libc_CSRC)) +LIBC_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libc_SSRC)) + +libc-static-y += $(LIBC_LINUX_OBJ) +libc-shared-y += $(LIBC_LINUX_OBJ:.o=.oS) +libc-nomulti-y += $(LIBC_LINUX_OBJ) + +LIBRT_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(librt_CSRC)) + +librt-a-y += $(LIBRT_LINUX_OBJ) +librt-so-y += $(LIBRT_LINUX_OBJ:.o=.oS) + +objclean-y += nptl_linux_clean +headers_clean-y += nptl_linux_headers_clean + +# +# Create header files. +# +CFLAGS-lowlevelbarrier.c = -S +CFLAGS-lowlevelcond.c = -S +CFLAGS-lowlevelrwlock.c = -S +CFLAGS-unwindbuf.c = -S + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.c: $(PTHREAD_LINUX_DIR)/lowlevelbarrier.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.c: $(PTHREAD_LINUX_DIR)/lowlevelcond.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrwlock.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.c: $(PTHREAD_LINUX_DIR)/unwindbuf.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.s: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelcond.s: $(PTHREAD_LINUX_OUT)/lowlevelcond.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.s: $(PTHREAD_LINUX_OUT)/lowlevelrwlock.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/unwindbuf.s: $(PTHREAD_LINUX_OUT)/unwindbuf.c + $(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.h: $(PTHREAD_LINUX_OUT)/lowlevelcond.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h: $(PTHREAD_LINUX_OUT)/lowlevelrwlock.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.h: $(PTHREAD_LINUX_OUT)/unwindbuf.s + $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_linux_headers: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \ + $(PTHREAD_LINUX_OUT)/lowlevelcond.h \ + $(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \ + $(PTHREAD_LINUX_OUT)/unwindbuf.h + +HEADERS_BITS_PTHREAD := $(notdir $(wildcard $(PTHREAD_LINUX_DIR)/bits/*.h)) +ALL_HEADERS_BITS_PTHREAD := $(addprefix include/bits/,$(HEADERS_BITS_PTHREAD)) + +$(ALL_HEADERS_BITS_PTHREAD): + $(do_ln) ../../$(PTHREAD_LINUX_DIR)/bits/$(@F) $(top_builddir)$@ + +nptl_linux_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelbarrier., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelcond., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/lowlevelrwlock., c h s) \ + $(addprefix $(PTHREAD_LINUX_OUT)/unwindbuf., c h s) + + +nptl_linux_clean: + $(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c new file mode 100644 index 000000000..5e109a83b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c @@ -0,0 +1,18 @@ +/* Wrapper for setting errno. + * + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <features.h> + +/* This routine is jumped to by all the syscall handlers, to stash + * an error number into errno. */ +int __syscall_error(int err_no) attribute_hidden; +int __syscall_error(int err_no) +{ + __set_errno(err_no); + return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S new file mode 100644 index 000000000..529763d80 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libc_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libc_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libc_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile new file mode 100644 index 000000000..8c8084079 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction +libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions new file mode 100644 index 000000000..437c4da28 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions @@ -0,0 +1,13 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h new file mode 100644 index 000000000..e0718780c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux/Alpha version. + Copyright (C) 1993-1998,2000,2002,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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 24576 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h new file mode 100644 index 000000000..0f3bf838e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Machine-specific pthread type layouts. Alpha version. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 56 +#define __SIZEOF_PTHREAD_MUTEX_T 40 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 56 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 32 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + unsigned int __nusers; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + int __spins; + __pthread_list_t __list; +#define __PTHREAD_MUTEX_HAVE_PREV 1 + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h new file mode 100644 index 000000000..6dadfda20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h @@ -0,0 +1,37 @@ +/* Machine-specific POSIX semaphore type layouts. Alpha version. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +# define __SIZEOF_SEM_T 32 + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S new file mode 100644 index 000000000..eea1cbeed --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <sysdeps/unix/sysv/linux/alpha/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c new file mode 100644 index 000000000..6a51e73da --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation. */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c new file mode 100644 index 000000000..ca85fc008 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + NULL, NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h new file mode 100644 index 000000000..fd4a7ca4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h @@ -0,0 +1,217 @@ +/* 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 Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define __NR_futex 394 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S new file mode 100644 index 000000000..ec5d175be --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S @@ -0,0 +1,43 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS \ + /* Load the current cached pid value across the vfork. */ \ + rduniq; \ + ldl a2, PID_OFFSET(v0); \ + mov v0, a1; \ + /* Write back its negation, to indicate that the pid value is \ + uninitialized in the the child, and in the window between \ + here and the point at which we restore the value. */ \ + negl a2, t0; \ + stl t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + + /* If we're back in the parent, restore the saved pid. */ + beq v0, 1f + stl a2, PID_OFFSET(a1) +1: ret + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c new file mode 100644 index 000000000..79a3c47ae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c @@ -0,0 +1,96 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + int tmp; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + newval = __fork_generation | 1; + __asm __volatile ( + "1: ldl_l %0, %2\n" + " and %0, 2, %1\n" + " bne %1, 2f\n" + " mov %3, %1\n" + " stl_c %1, %2\n" + " beq %1, 1b\n" + "2: mb" + : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) + : "r" (newval), "m" (*once_control)); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + /* Add one to *once_control to take the bottom 2 bits from 01 to 10. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c new file mode 100644 index 000000000..27fd817e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c @@ -0,0 +1,5 @@ +/* ??? This is an ass-backwards way to do this. We should simply define + the acquire/release semantics of atomic_exchange_and_add. And even if + we don't do this, we should be using atomic_full_barrier or otherwise. */ +#define __lll_rel_instr "mb" +#include "../sem_post.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h new file mode 100644 index 000000000..f3f7718e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef PROF +# define PSEUDO_PROF \ + .set noat; \ + lda AT, _mcount; \ + jsr AT, (AT), _mcount; \ + .set at +# else +# define PSEUDO_PROF +# endif + +/* ??? Assumes that nothing comes between PSEUDO and PSEUDO_END + besides "ret". */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .globl name; \ + .align 4; \ + .type name, @function; \ + .usepv name, std; \ + cfi_startproc; \ +__LABEL(name) \ + ldgp gp, 0(pv); \ + PSEUDO_PROF; \ + PSEUDO_PREPARE_ARGS \ + SINGLE_THREAD_P(t0); \ + bne t0, $pseudo_cancel; \ + lda v0, SYS_ify(syscall_name); \ + call_pal PAL_callsys; \ + bne a3, SYSCALL_ERROR_LABEL; \ +__LABEL($pseudo_ret) \ + .subsection 2; \ +__LABEL($pseudo_cancel) \ + subq sp, 64, sp; \ + cfi_def_cfa_offset(64); \ + stq ra, 0(sp); \ + cfi_offset(ra, -64); \ + SAVE_ARGS_##args; \ + CENABLE; \ + LOAD_ARGS_##args; \ + /* Save the CENABLE return value in RA. That register \ + is preserved across syscall and the real return \ + address is saved on the stack. */ \ + mov v0, ra; \ + lda v0, SYS_ify(syscall_name); \ + call_pal PAL_callsys; \ + stq v0, 8(sp); \ + mov ra, a0; \ + bne a3, $multi_error; \ + CDISABLE; \ + ldq ra, 0(sp); \ + ldq v0, 8(sp); \ + addq sp, 64, sp; \ + cfi_remember_state; \ + cfi_restore(ra); \ + cfi_def_cfa_offset(0); \ + ret; \ + cfi_restore_state; \ +__LABEL($multi_error) \ + CDISABLE; \ + ldq ra, 0(sp); \ + ldq v0, 8(sp); \ + addq sp, 64, sp; \ + cfi_restore(ra); \ + cfi_def_cfa_offset(0); \ +__LABEL($syscall_error) \ + SYSCALL_ERROR_HANDLER; \ + .previous + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ + .subsection 2; \ + cfi_endproc; \ + .size sym, .-sym + +# define SAVE_ARGS_0 /* Nothing. */ +# define SAVE_ARGS_1 SAVE_ARGS_0; stq a0, 8(sp) +# define SAVE_ARGS_2 SAVE_ARGS_1; stq a1, 16(sp) +# define SAVE_ARGS_3 SAVE_ARGS_2; stq a2, 24(sp) +# define SAVE_ARGS_4 SAVE_ARGS_3; stq a3, 32(sp) +# define SAVE_ARGS_5 SAVE_ARGS_4; stq a4, 40(sp) +# define SAVE_ARGS_6 SAVE_ARGS_5; stq a5, 48(sp) + +# define LOAD_ARGS_0 /* Nothing. */ +# define LOAD_ARGS_1 LOAD_ARGS_0; ldq a0, 8(sp) +# define LOAD_ARGS_2 LOAD_ARGS_1; ldq a1, 16(sp) +# define LOAD_ARGS_3 LOAD_ARGS_2; ldq a2, 24(sp) +# define LOAD_ARGS_4 LOAD_ARGS_3; ldq a3, 32(sp) +# define LOAD_ARGS_5 LOAD_ARGS_4; ldq a4, 40(sp) +# define LOAD_ARGS_6 LOAD_ARGS_5; ldq a5, 48(sp) + +# ifdef IS_IN_libpthread +# define __local_enable_asynccancel __pthread_enable_asynccancel +# define __local_disable_asynccancel __pthread_disable_asynccancel +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define __local_enable_asynccancel __libc_enable_asynccancel +# define __local_disable_asynccancel __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define __local_enable_asynccancel __librt_enable_asynccancel +# define __local_disable_asynccancel __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +# ifdef PIC +# define CENABLE bsr ra, __local_enable_asynccancel !samegp +# define CDISABLE bsr ra, __local_disable_asynccancel !samegp +# else +# define CENABLE jsr ra, __local_enable_asynccancel; ldgp ra, 0(gp) +# define CDISABLE jsr ra, __local_disable_asynccancel; ldgp ra, 0(gp) +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P \ + __builtin_expect (__local_multiple_threads == 0, 1) +# elif defined(PIC) +# define SINGLE_THREAD_P(reg) ldl reg, __local_multiple_threads(gp) !gprel +# else +# define SINGLE_THREAD_P(reg) \ + ldah reg, __local_multiple_threads(gp) !gprelhigh; \ + ldl reg, __local_multiple_threads(reg) !gprellow +# endif +# else +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + call_pal PAL_rduniq; \ + ldl reg, MULTIPLE_THREADS_OFFSET($0) +# endif +# endif + +#else + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S new file mode 100644 index 000000000..f0c39982c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S @@ -0,0 +1,46 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS \ + /* Load the current cached pid value across the vfork. */ \ + rduniq; \ + ldl a2, PID_OFFSET(v0); \ + mov v0, a1; \ + /* If the cached value is initialized (nonzero), then write \ + back its negation, or INT_MIN, to indicate that the pid \ + value is uninitialized in the the child, and in the window \ + between here and the point at which we restore the value. */ \ + ldah t0, -0x8000; \ + negl a2, t1; \ + cmovne a2, t1, t0; \ + stl t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + + /* If we're back in the parent, restore the saved pid. */ + beq v0, 1f + stl a2, PID_OFFSET(a1) +1: ret + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch new file mode 100644 index 000000000..2256d6b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch @@ -0,0 +1,56 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c lowlevellock.c \ + pt-__syscall_rt_sigaction.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -marm +# We always compile it in arm mode because of SAVE_PID macro +# This macro should be alternatively implemented in THUMB +# assembly. +ASFLAGS-vfork.S = -marm + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/arm +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/arm + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJ) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: + $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h new file mode 100644 index 000000000..49a935a52 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -0,0 +1,136 @@ +/* Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdint.h> +#include <sysdep.h> + + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +void __arm_link_error (void); + +#ifdef __thumb__ + +/* Note that to allow efficient implementation the arguemtns are reversed + relative to atomic_exchange_acq. */ +int __thumb_swpb (int newvalue, void *mem) + attribute_hidden; +unsigned int __thumb_swp (unsigned int newvalue, void *mem) + attribute_hidden; +unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *mem) + attribute_hidden; + +#define atomic_exchange_acq(mem, newvalue) \ + ({ __typeof (*mem) result; \ + if (sizeof (*mem) == 1) \ + result = __thumb_swpb (newvalue, mem); \ + else if (sizeof (*mem) == 4) \ + result = __thumb_swp (newvalue, mem); \ + else \ + { \ + result = 0; \ + abort (); \ + } \ + result; }) + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ((__typeof (oldval)) __thumb_cmpxchg (oldval, newval, mem)) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#else +/* ARM mode. */ + +#define atomic_exchange_acq(mem, newvalue) \ + ({ __typeof (*mem) _xchg_result; \ + if (sizeof (*mem) == 1) \ + __asm__ __volatile__ ("swpb %0, %1, [%2]" \ + : "=&r,&r" (_xchg_result) \ + : "r,0" (newvalue), "r,r" (mem) : "memory"); \ + else if (sizeof (*mem) == 4) \ + __asm__ __volatile__ ("swp %0, %1, [%2]" \ + : "=&r,&r" (_xchg_result) \ + : "r,0" (newvalue), "r,r" (mem) : "memory"); \ + else \ + { \ + _xchg_result = 0; \ + abort (); \ + } \ + _xchg_result; }) + +/* Atomic compare and exchange. This sequence relies on the kernel to + provide a compare and exchange operation which is atomic on the + current architecture, either via cleverness on pre-ARMv6 or via + ldrex / strex on ARMv6. */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +/* It doesn't matter what register is used for a_oldval2, but we must + specify one to work around GCC PR rtl-optimization/21223. Otherwise + it may cause a_oldval or a_tmp to be moved to a different register. */ + +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ register __typeof (oldval) a_oldval asm ("r0"); \ + register __typeof (oldval) a_newval asm ("r1") = (newval); \ + register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register __typeof (oldval) a_tmp asm ("r3"); \ + register __typeof (oldval) a_oldval2 asm ("r4") = (oldval); \ + __asm__ __volatile__ \ + ("0:\tldr\t%1,[%3]\n\t" \ + "cmp\t%1, %4\n\t" \ + "bne\t1f\n\t" \ + "mov\t%0, %4\n\t" \ + "mov\t%1, #0xffff0fff\n\t" \ + "mov\tlr, pc\n\t" \ + "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + "bcc\t0b\n\t" \ + "mov\t%1, %4\n\t" \ + "1:" \ + : "=&r" (a_oldval), "=&r" (a_tmp) \ + : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2) \ + : "ip", "lr", "cc", "memory"); \ + a_tmp; }) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __arm_link_error (); oldval; }) + +#endif /* __thumb__ */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h new file mode 100644 index 000000000..ea8d6a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h new file mode 100644 index 000000000..3fc647d31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S new file mode 100644 index 000000000..23227eb24 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include "../../../../../../../libc/sysdeps/linux/arm/clone.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c new file mode 100644 index 000000000..2d4355980 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c new file mode 100644 index 000000000..1c8f4c43a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Phil Blundell <pb@nexus.co.uk>, 2005 + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + NULL, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c new file mode 100644 index 000000000..74be18855 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c @@ -0,0 +1,118 @@ +/* low level locking for pthread library. Generic futex-using version. + Copyright (C) 2003, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + struct timespec rt; + + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Upgrade the lock. */ + if (atomic_exchange_acq (futex, 2) == 0) + return 0; + + do + { + struct timeval tv; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_exchange_acq (futex, 2) != 0); + + return 0; +} + + +/* These don't get included in libc.so */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h new file mode 100644 index 000000000..79f3ddeca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h @@ -0,0 +1,339 @@ +/* Copyright (C) 2005, 2006 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 Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + __ret; \ + }) + +#define lll_robust_mutex_dead(futexv) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + __ret; \ + }) + + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_WAKE_OP, (nr_wake), \ + (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + __ret; \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock (int *futex) +{ + int flag = 1, old; +#ifdef __thumb__ + old = atomic_exchange_acq (futex, flag); + if (old < 1) + flag = 0; + else if (old > 1) + flag = atomic_exchange_acq (futex, old); +#else + __asm__ __volatile__ ( + "\tswp %[old], %[flag], [%[futex]] @ try to take the lock\n" + "\tcmp %[old], #1 @ check old lock value\n" + "\tmovlo %[flag], #0 @ if we got it, return 0\n" + "\tswphi %[flag], %[old], [%[futex]] @ if it was contested,\n" + " @ restore the contested flag,\n" + " @ and check whether that won." + : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) + : : "memory" ); +#endif + + return flag; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock (int *futex) +{ + int flag = 2, old; +#ifdef __thumb__ + old = atomic_exchange_acq (futex, flag); + if (old < 1) + flag = 0; + else if (old > 1) + flag = atomic_exchange_acq (futex, old); +#else + __asm__ __volatile__ ( + "\tswp %[old], %[flag], [%[futex]] @ try to take the lock\n" + "\tcmp %[old], #1 @ check old lock value\n" + "\tmovlo %[flag], #0 @ if we got it, return 0\n" + "\tswphi %[flag], %[old], [%[futex]] @ if it was contested,\n" + " @ restore the contested flag,\n" + " @ and check whether that won." + : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) + : : "memory" ); +#endif + + return flag; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_mutex_trylock(int *futex, int id) +{ + return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_mutex_trylock(lock, id) \ + __lll_robust_mutex_trylock (&(lock), id) + +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock (int *futex) +{ + int val = atomic_exchange_acq (futex, 1); + + if (__builtin_expect (val != 0, 0)) + { + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2); + } +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_lock (int *futex, int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_lock_wait (futex); + return result; +} +#define lll_robust_mutex_lock(futex, id) \ + __lll_robust_mutex_lock (&(futex), id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + int val = atomic_exchange_acq (futex, 2); + + if (__builtin_expect (val != 0, 0)) + { + while (atomic_exchange_acq (futex, 2) != 0) + lll_futex_wait (futex, 2); + } +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +#define lll_robust_mutex_cond_lock(futex, id) \ + __lll_robust_mutex_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + int val = atomic_exchange_acq (futex, 1); + + if (__builtin_expect (val != 0, 0)) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_timedlock (int *futex, const struct timespec *abstime, + int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_timedlock_wait (futex, abstime); + return result; +} +#define lll_robust_mutex_timedlock(futex, abstime, id) \ + __lll_robust_mutex_timedlock (&(futex), abstime, id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_robust_mutex_unlock (int *futex, int mask) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val & mask, 0)) + lll_futex_wake (futex, 1); +} +#define lll_robust_mutex_unlock(futex) \ + __lll_robust_mutex_unlock(&(futex), FUTEX_WAITERS) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..7b8352243 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c new file mode 100644 index 000000000..5a48a9b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/arm/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c new file mode 100644 index 000000000..08710f1c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c @@ -0,0 +1,5 @@ +#include <sys/syscall.h> +#include <sys/time.h> + +int gettimeofday (struct timeval *, struct timezone *) attribute_hidden; +_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S new file mode 100644 index 000000000..9764e9ee2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + str lr, [sp, #-4]!; /* Save LR. */ \ + mov r0, #0xffff0fff; /* Point to the high page. */ \ + mov lr, pc; /* Save our return address. */ \ + sub pc, r0, #31; /* Jump to the TLS entry. */ \ + ldr lr, [sp], #4; /* Restore LR. */ \ + mov r2, r0; /* Save the TLS addr in r2. */ \ + ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ + rsb r0, r3, #0; /* Negate it. */ \ + str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + cmp r0, #0; /* If we are the parent... */ \ + strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + +#INCLUDE <../../../../../../../LIBC/SYSDEPS/LINUX/ARM/VFORK.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c new file mode 100644 index 000000000..c8925810c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c @@ -0,0 +1,99 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + +unsigned long int __fork_generation attribute_hidden; + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + do + { + newval = __fork_generation | 1; + oldval = *once_control; + if (oldval & 2) + break; + } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + /* Say that the initialisation is done. */ + *once_control = __fork_generation | 2; + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) + +#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__) +/* When statically linked, if pthread_create is used, this file + will be brought in. The exception handling code in GCC assumes + that if pthread_create is available, so are these. */ +const void *include_pthread_getspecific attribute_hidden = pthread_getspecific; +const void *include_pthread_setspecific attribute_hidden = pthread_setspecific; +const void *include_pthread_key_create attribute_hidden = pthread_key_create; +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h new file mode 100644 index 000000000..350d9af50 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,153 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of + cancellation; but they're really only accurate at the point of the + syscall. The ARM unwind directives are not rich enough without adding + a custom personality function. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + PSEUDO_PROLOGUE; \ + .type __##syscall_name##_nocancel,%function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + PSEUDO_RET; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name); \ + SINGLE_THREAD_P; \ + DOARGS_##args; \ + bne .Lpseudo_cancel; \ + DO_CALL (syscall_name, 0); \ + UNDOARGS_##args; \ + cmn r0, $4096; \ + PSEUDO_RET; \ + .Lpseudo_cancel: \ + .fnstart; \ + DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE; \ + mov ip, r0; /* put mask in safe place. */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + ldr r7, =SYS_ify (syscall_name); \ + swi 0x0; /* do the call. */ \ + .fnend; /* Past here we can't easily unwind. */ \ + mov r7, r0; /* save syscall return value. */ \ + mov r0, ip; /* get mask back. */ \ + CDISABLE; \ + mov r0, r7; /* retrieve return value. */ \ + RESTORE_LR_##args; \ + UNDOARGS_##args; \ + cmn r0, $4096; + +/* DOARGS pushes four bytes on the stack for five arguments, eight bytes for + six arguments, and nothing for fewer. In order to preserve doubleword + alignment, sometimes we must save an extra register. */ + +# define RESTART_UNWIND .fnend; .fnstart; .save {r7, lr} + +# define DOCARGS_0 stmfd sp!, {r7, lr}; .save {r7, lr} +# define UNDOCARGS_0 +# define RESTORE_LR_0 ldmfd sp!, {r7, lr}; + +# define DOCARGS_1 stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_1 ldr r0, [sp], #8; RESTART_UNWIND +# define RESTORE_LR_1 RESTORE_LR_0 + +# define DOCARGS_2 stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_2 ldmfd sp!, {r0, r1}; RESTART_UNWIND +# define RESTORE_LR_2 RESTORE_LR_0 + +# define DOCARGS_3 stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_3 ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_3 RESTORE_LR_0 + +# define DOCARGS_4 stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_4 ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_4 RESTORE_LR_0 + +# define DOCARGS_5 .save {r4}; stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_5 ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4}; .save {r7, lr}; .pad #4 +# define RESTORE_LR_5 ldmfd sp!, {r4, r7, lr} + +# define DOCARGS_6 .save {r4, r5}; stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_6 ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4, r5}; .save {r7, lr} +# define RESTORE_LR_6 RESTORE_LR_0 + +# ifdef IS_IN_libpthread +# define CENABLE bl PLTJMP(__pthread_enable_asynccancel) +# define CDISABLE bl PLTJMP(__pthread_disable_asynccancel) +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE bl PLTJMP(__libc_enable_asynccancel) +# define CDISABLE bl PLTJMP(__libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE bl PLTJMP(__librt_enable_asynccancel) +# define CDISABLE bl PLTJMP(__librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P \ + ldr ip, 1b; \ +2: \ + ldr ip, [pc, ip]; \ + teq ip, #0; +# define PSEUDO_PROLOGUE \ + 1: .word __local_multiple_threads - 2f - 8; +# endif +# else +/* There is no __local_multiple_threads for librt, so use the TCB. */ +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define PSEUDO_PROLOGUE +# define SINGLE_THREAD_P \ + stmfd sp!, {r0, lr}; \ + bl __aeabi_read_tp; \ + ldr ip, [r0, #MULTIPLE_THREADS_OFFSET]; \ + ldmfd sp!, {r0, lr}; \ + teq ip, #0 +# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P +# endif +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h new file mode 100644 index 000000000..23c2bfc8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -0,0 +1,334 @@ +/* Copyright (C) 1992, 93, 1995-2000, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. + ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_ARM_SYSDEP_H +#define _LINUX_ARM_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality. */ +#include <sysdeps/arm/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SWI_BASE (0x900000) +#define SYS_ify(syscall_name) (__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in R0 + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can safely + test with -4095. */ + +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); \ + cmn r0, $4096; + +#define PSEUDO_RET \ + RETINSTR(cc, lr); \ + b PLTJMP(SYSCALL_ERROR) +#undef ret +#define ret PSEUDO_RET + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); + +#define PSEUDO_RET_NOERRNO \ + DO_RET (lr); + +#undef ret_NOERRNO +#define ret_NOERRNO PSEUDO_RET_NOERRNO + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +/* The function has to return the error code. */ +#undef PSEUDO_ERRVAL +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + rsb r0, r0, #0 + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL PSEUDO_RET_NOERRNO + +#if NOT_IN_libc +# define SYSCALL_ERROR __local_syscall_error +# ifdef RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + ldr r1, 1f; \ + rsb r0, r0, #0; \ +0: str r0, [pc, r1]; \ + mvn r0, #0; \ + DO_RET(lr); \ +1: .word C_SYMBOL_NAME(rtld_errno) - 0b - 8; +# else +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + str lr, [sp, #-4]!; \ + str r0, [sp, #-4]!; \ + bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \ + ldr r1, [sp], #4; \ + rsb r1, r1, #0; \ + str r1, [r0]; \ + mvn r0, #0; \ + ldr pc, [sp], #4; +# endif +#else +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +# define SYSCALL_ERROR __syscall_error +#endif + +/* Linux takes system call args in registers: + syscall number in the SWI instruction + arg 1 r0 + arg 2 r1 + arg 3 r2 + arg 4 r3 + arg 5 r4 (this is different from the APCS convention) + arg 6 r5 + arg 7 r6 + + The compiler is going to form a call by coming here, through PSEUDO, with + arguments + syscall number in the DO_CALL macro + arg 1 r0 + arg 2 r1 + arg 3 r2 + arg 4 r3 + arg 5 [sp] + arg 6 [sp+4] + arg 7 [sp+8] + + We need to shuffle values between R4..R6 and the stack so that the + caller's v1..v3 and stack frame are not corrupted, and the kernel + sees the right arguments. + +*/ + +#undef DO_CALL +#if defined(__ARM_EABI__) +#define DO_CALL(syscall_name, args) \ + DOARGS_##args \ + mov ip, r7; \ + ldr r7, =SYS_ify (syscall_name); \ + swi 0x0; \ + mov r7, ip; \ + UNDOARGS_##args +#else +#define DO_CALL(syscall_name, args) \ + DOARGS_##args \ + swi SYS_ify (syscall_name); \ + UNDOARGS_##args +#endif + +#define DOARGS_0 /* nothing */ +#define DOARGS_1 /* nothing */ +#define DOARGS_2 /* nothing */ +#define DOARGS_3 /* nothing */ +#define DOARGS_4 /* nothing */ +#define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; +#define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; +#define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; + +#define UNDOARGS_0 /* nothing */ +#define UNDOARGS_1 /* nothing */ +#define UNDOARGS_2 /* nothing */ +#define UNDOARGS_3 /* nothing */ +#define UNDOARGS_4 /* nothing */ +#define UNDOARGS_5 ldr r4, [sp], $4; +#define UNDOARGS_6 ldmfd sp!, {r4, r5}; +#define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; + +#else /* not __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ + _sys_result = (unsigned int) -1; \ + } \ + (int) _sys_result; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +#undef INTERNAL_SYSCALL_RAW +#if defined(__thumb__) +/* Hide the use of r7 from the compiler, this would be a lot + * easier but for the fact that the syscalls can exceed 255. + * For the moment the LOAD_ARG_7 is sacrificed. + * We can't use push/pop inside the asm because that breaks + * unwinding (ie. thread cancellation). + */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + int _sys_buf[2]; \ + register int _a1 __asm__ ("a1"); \ + register int *_v3 __asm__ ("v3") = _sys_buf; \ + LOAD_ARGS_##nr (args) \ + *_v3 = (int) (name); \ + __asm__ __volatile__ ("str r7, [v3, #4]\n" \ + "\tldr r7, [v3]\n" \ + "\tswi 0 @ syscall " #name "\n" \ + "\tldr r7, [v3, #4]" \ + : "=r" (_a1) \ + : "r" (_v3) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#elif defined(__ARM_EABI__) +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({unsigned int _sys_result; \ + { \ + register int _a1 __asm__ ("r0"), _nr __asm__ ("r7"); \ + LOAD_ARGS_##nr (args) \ + _nr = name; \ + __asm__ __volatile__ ("swi 0x0 @ syscall " #name \ + : "=r" (_a1) \ + : "r" (_nr) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#else /* !defined(__ARM_EABI__) */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + register int _a1 __asm__ ("a1"); \ + LOAD_ARGS_##nr (args) \ + __asm__ __volatile__ ("swi %1 @ syscall " #name \ + : "=r" (_a1) \ + : "i" (name) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) +#endif + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args) + +#undef INTERNAL_SYSCALL_ARM +#define INTERNAL_SYSCALL_ARM(name, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args) + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((unsigned int) (val) >= 0xfffff001u) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) + +#define LOAD_ARGS_0() +#define ASM_ARGS_0 +#define LOAD_ARGS_1(a1) \ + _a1 = (int) (a1); \ + LOAD_ARGS_0 () +#define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) +#define LOAD_ARGS_2(a1, a2) \ + register int _a2 __asm__ ("a2") = (int) (a2); \ + LOAD_ARGS_1 (a1) +#define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) +#define LOAD_ARGS_3(a1, a2, a3) \ + register int _a3 __asm__ ("a3") = (int) (a3); \ + LOAD_ARGS_2 (a1, a2) +#define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) +#define LOAD_ARGS_4(a1, a2, a3, a4) \ + register int _a4 __asm__ ("a4") = (int) (a4); \ + LOAD_ARGS_3 (a1, a2, a3) +#define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) +#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ + register int _v1 __asm__ ("v1") = (int) (a5); \ + LOAD_ARGS_4 (a1, a2, a3, a4) +#define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) +#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ + register int _v2 __asm__ ("v2") = (int) (a6); \ + LOAD_ARGS_5 (a1, a2, a3, a4, a5) +#define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) +#define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ + register int _v3 __asm__ ("v3") = (int) (a7); \ + LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) +#define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) + +#if defined(__ARM_EABI__) +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + INTERNAL_SYSCALL_RAW(number, err, nr, args) +#else +/* We can't implement non-constant syscalls directly since the syscall + number is normally encoded in the instruction. So use SYS_syscall. */ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + INTERNAL_SYSCALL_NCS_##nr (number, err, args) + +#define INTERNAL_SYSCALL_NCS_0(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 1, number, args) +#define INTERNAL_SYSCALL_NCS_1(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 2, number, args) +#define INTERNAL_SYSCALL_NCS_2(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 3, number, args) +#define INTERNAL_SYSCALL_NCS_3(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 4, number, args) +#define INTERNAL_SYSCALL_NCS_4(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 5, number, args) +#define INTERNAL_SYSCALL_NCS_5(number, err, args...) \ + INTERNAL_SYSCALL (syscall, err, 6, number, args) +#endif + +#endif /* __ASSEMBLER__ */ + +#endif /* linux/arm/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c new file mode 100644 index 000000000..206202809 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <string.h> +#include <unwind.h> +#include <unistd.h> +#include <pthreadP.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); +static _Unwind_Reason_Code (*libgcc_s_forcedunwind) + (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); +static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *); + +void +pthread_cancel_init (void) +{ + void *resume, *personality, *forcedunwind, *getcfa; + void *handle; + + if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) + return; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + if (handle == NULL + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL + || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) + == NULL + || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT + || ARCH_CANCEL_INIT (handle) +#endif + ) + { +# define STR_N_LEN(str) str, strlen (str) + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, + STR_N_LEN ("libgcc_s.so.1 must be installed for pthread_cancel to work\n")); + abort (); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; + libgcc_s_forcedunwind = forcedunwind; + libgcc_s_getcfa = getcfa; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +asm ( +#ifdef __thumb__ +" .code 32" +#endif +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" bx r3\n" +"4: bl pthread_cancel_init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +" .code 16" +#endif +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_personality (state, ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, + void *stop_argument) +{ + if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) + pthread_cancel_init (); + return libgcc_s_getcfa (context); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c new file mode 100644 index 000000000..99b15746a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <unwind.h> + +#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + +static void init (void) __attribute_used__; + +static void +init (void) +{ + void *resume, *personality; + void *handle; + + handle = __libc_dlopen ("libgcc_s.so.1"); + + if (handle == NULL + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) { + fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + abort (); + } + + libgcc_s_resume = resume; + libgcc_s_personality = personality; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +__asm__ ( +#ifdef __thumb__ +" .code 32\n" +#endif +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" bx r3\n" +"4: bl init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +" .code 16\n" +#endif + +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + if (__builtin_expect (libgcc_s_personality == NULL, 0)) + init (); + return libgcc_s_personality (state, ue_header, context); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h new file mode 100644 index 000000000..d625fb288 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h @@ -0,0 +1,274 @@ +/* Header file for the ARM EABI unwinder + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Paul Brook + + This file is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combine + executable.) + + This file 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* Language-independent unwinder header public defines. This contains both + ABI defined objects, and GNU support routines. */ + +#ifndef UNWIND_ARM_H +#define UNWIND_ARM_H + +#define __ARM_EABI_UNWINDER__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); + typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); + typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); + typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); + typedef _Unwind_Word _uw; + typedef unsigned _uw64 __attribute__((mode(__DI__))); + typedef unsigned _uw16 __attribute__((mode(__HI__))); + typedef unsigned _uw8 __attribute__((mode(__QI__))); + + typedef enum + { + _URC_OK = 0, /* operation completed successfully */ + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9 /* unspecified failure of some kind */ + } + _Unwind_Reason_Code; + + typedef enum + { + _US_VIRTUAL_UNWIND_FRAME = 0, + _US_UNWIND_FRAME_STARTING = 1, + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16 + } + _Unwind_State; + + /* Provided only for for compatibility with existing code. */ + typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 +#define _UA_END_OF_STACK 16 +#define _URC_NO_REASON _URC_OK + + typedef struct _Unwind_Control_Block _Unwind_Control_Block; + typedef struct _Unwind_Context _Unwind_Context; + typedef _uw _Unwind_EHT_Header; + + + /* UCB: */ + + struct _Unwind_Control_Block + { +#ifdef _LIBC + /* For the benefit of code which assumes this is a scalar. All + glibc ever does is clear it. */ + _uw64 exception_class; +#else + char exception_class[8]; +#endif + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); + /* Unwinder cache, private fields for the unwinder's use */ + struct + { + _uw reserved1; /* Forced unwind stop fn, 0 if not forced */ + _uw reserved2; /* Personality routine address */ + _uw reserved3; /* Saved callsite address */ + _uw reserved4; /* Forced unwind stop arg */ + _uw reserved5; + } + unwinder_cache; + /* Propagation barrier cache (valid after phase 1): */ + struct + { + _uw sp; + _uw bitpattern[5]; + } + barrier_cache; + /* Cleanup cache (preserved over cleanup): */ + struct + { + _uw bitpattern[4]; + } + cleanup_cache; + /* Pr cache (for pr's benefit): */ + struct + { + _uw fnstart; /* function start address */ + _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ + _uw additional; /* additional data */ + _uw reserved1; + } + pr_cache; + long long int :0; /* Force alignment to 8-byte boundary */ + }; + + /* Virtual Register Set*/ + + typedef enum + { + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ + _UVRSC_FPA = 2, /* fpa */ + _UVRSC_WMMXD = 3, /* Intel WMMX data register */ + _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + } + _Unwind_VRS_RegClass; + + typedef enum + { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 + } + _Unwind_VRS_DataRepresentation; + + typedef enum + { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 + } + _Unwind_VRS_Result; + + /* Frame unwinding state. */ + typedef struct + { + /* The current word (bytes packed msb first). */ + _uw data; + /* Pointer to the next word of data. */ + _uw *next; + /* The number of bytes left in this word. */ + _uw8 bytes_left; + /* The number of words pointed to by ptr. */ + _uw8 words_left; + } + __gnu_unwind_state; + + typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *); + + _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation); + + + /* Support functions for the PR. */ +#define _Unwind_Exception _Unwind_Control_Block + typedef char _Unwind_Exception_Class[8]; + + void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); + + /* These two should never be used. */ + _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); + + /* Interface functions: */ + _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); + void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + + typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int, _Unwind_Action, _Unwind_Exception_Class, + _Unwind_Control_Block *, struct _Unwind_Context *, void *); + _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *); + _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); + void _Unwind_Complete(_Unwind_Control_Block *ucbp); + void _Unwind_DeleteException (_Unwind_Exception *); + + _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, + _Unwind_Context *); + _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, + __gnu_unwind_state *); + + /* Decode an R_ARM_TARGET2 relocation. */ + static inline _Unwind_Word + _Unwind_decode_target2 (_Unwind_Word ptr) + { + _Unwind_Word tmp; + + tmp = *(_Unwind_Word *) ptr; + /* Zero values are always NULL. */ + if (!tmp) + return 0; + +#if defined(linux) || defined(__NetBSD__) + /* Pc-relative indirect. */ + tmp += ptr; + tmp = *(_Unwind_Word *) tmp; +#elif defined(__symbian__) + /* Absolute pointer. Nothing more to do. */ +#else + /* Pc-relative pointer. */ + tmp += ptr; +#endif + return tmp; + } + + static inline _Unwind_Word + _Unwind_GetGR (_Unwind_Context *context, int regno) + { + _uw val; + _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + return val; + } + + /* Return the address of the instruction, not the actual IP value. */ +#define _Unwind_GetIP(context) \ + (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + + static inline void + _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) + { + _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + } + + /* The dwarf unwinder doesn't understand arm/thumb state. We assume the + landing pad uses the same instruction set as the call site. */ +#define _Unwind_SetIP(context, val) \ + _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined UNWIND_ARM_H */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S new file mode 100644 index 000000000..935a4e904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S @@ -0,0 +1,39 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + str lr, [sp, #-4]!; /* Save LR. */ \ + mov r0, #0xffff0fff; /* Point to the high page. */ \ + mov lr, pc; /* Save our return address. */ \ + sub pc, r0, #31; /* Jump to the TLS entry. */ \ + ldr lr, [sp], #4; /* Restore LR. */ \ + mov r2, r0; /* Save the TLS addr in r2. */ \ + ldr r3, [r2, #PID_OFFSET]; /* Load the saved PID. */ \ + rsbs r0, r3, #0; /* Negate it. */ \ + moveq r0, #0x80000000; /* Use 0x80000000 if it was 0. */ \ + str r0, [r2, #PID_OFFSET] /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + cmp r0, #0; /* If we are the parent... */ \ + strne r3, [r2, #PID_OFFSET] /* ... restore the saved PID. */ + +#include "../../../../../../../libc/sysdeps/linux/arm/vfork.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h new file mode 100644 index 000000000..b639ba44a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux version. + Copyright (C) 1993-1998,2000,2002,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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 16384 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h new file mode 100644 index 000000000..92c2d3282 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -0,0 +1,178 @@ +/* Define POSIX options for Linux. + Copyright (C) 1996-2001, 2002, 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _POSIX_OPT_H +#define _POSIX_OPT_H 1 + +/* Job control is supported. */ +#define _POSIX_JOB_CONTROL 1 + +/* Processes have a saved set-user-ID and a saved set-group-ID. */ +#define _POSIX_SAVED_IDS 1 + +/* Priority scheduling is supported. */ +#define _POSIX_PRIORITY_SCHEDULING 200112L + +/* Synchronizing file data is supported. */ +#define _POSIX_SYNCHRONIZED_IO 200112L + +/* The fsync function is present. */ +#define _POSIX_FSYNC 200112L + +/* Mapping of files to memory is supported. */ +#define _POSIX_MAPPED_FILES 200112L + +/* Locking of all memory is supported. */ +#define _POSIX_MEMLOCK 200112L + +/* Locking of ranges of memory is supported. */ +#define _POSIX_MEMLOCK_RANGE 200112L + +/* Setting of memory protections is supported. */ +#define _POSIX_MEMORY_PROTECTION 200112L + +/* Only root can change owner of file. */ +#define _POSIX_CHOWN_RESTRICTED 1 + +/* `c_cc' member of 'struct termios' structure can be disabled by + using the value _POSIX_VDISABLE. */ +#define _POSIX_VDISABLE '\0' + +/* Filenames are not silently truncated. */ +#define _POSIX_NO_TRUNC 1 + +/* X/Open realtime support is available. */ +#define _XOPEN_REALTIME 1 + +/* XPG4.2 shared memory is supported. */ +#define _XOPEN_SHM 1 + +/* Tell we have POSIX threads. */ +#define _POSIX_THREADS 200112L + +/* We have the reentrant functions described in POSIX. */ +#define _POSIX_REENTRANT_FUNCTIONS 1 +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +/* We provide priority scheduling for threads. */ +#define _POSIX_THREAD_PRIORITY_SCHEDULING 200112L + +/* We support user-defined stack sizes. */ +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* We support user-defined stacks. */ +#define _POSIX_THREAD_ATTR_STACKADDR 200112L + +/* We support POSIX.1b semaphores. */ +#define _POSIX_SEMAPHORES 200112L + +/* Real-time signals are supported. */ +#define _POSIX_REALTIME_SIGNALS 200112L + +/* We support asynchronous I/O. */ +#define _POSIX_ASYNCHRONOUS_IO 200112L +#define _POSIX_ASYNC_IO 1 +/* Alternative name for Unix98. */ +#define _LFS_ASYNCHRONOUS_IO 1 +/* Support for prioritization is also available. */ +#define _POSIX_PRIORITIZED_IO 200112L + +/* The LFS support in asynchronous I/O is also available. */ +#define _LFS64_ASYNCHRONOUS_IO 1 + +/* The rest of the LFS is also available. */ +#define _LFS_LARGEFILE 1 +#define _LFS64_LARGEFILE 1 +#define _LFS64_STDIO 1 + +/* POSIX shared memory objects are implemented. */ +#define _POSIX_SHARED_MEMORY_OBJECTS 200112L + +/* CPU-time clocks support needs to be checked at runtime. */ +#define _POSIX_CPUTIME 0 + +/* Clock support in threads must be also checked at runtime. */ +#define _POSIX_THREAD_CPUTIME 0 + +/* GNU libc provides regular expression handling. */ +#define _POSIX_REGEXP 1 + +/* Reader/Writer locks are available. */ +#define _POSIX_READER_WRITER_LOCKS 200112L + +/* We have a POSIX shell. */ +#define _POSIX_SHELL 1 + +/* We support the Timeouts option. */ +#define _POSIX_TIMEOUTS 200112L + +/* We support spinlocks. */ +#define _POSIX_SPIN_LOCKS 200112L + +/* The `spawn' function family is supported. */ +#define _POSIX_SPAWN 200112L + +/* We have POSIX timers. */ +#define _POSIX_TIMERS 200112L + +/* The barrier functions are available. */ +#define _POSIX_BARRIERS 200112L + +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L + +/* Thread process-shared synchronization is supported. */ +#define _POSIX_THREAD_PROCESS_SHARED 200112L + +/* The monotonic clock might be available. */ +#define _POSIX_MONOTONIC_CLOCK 0 + +/* The clock selection interfaces are available. */ +#define _POSIX_CLOCK_SELECTION 200112L + +/* Advisory information interfaces are available. */ +#define _POSIX_ADVISORY_INFO 200112L + +/* IPv6 support is available. */ +#define _POSIX_IPV6 200112L + +/* Raw socket support is available. */ +#define _POSIX_RAW_SOCKETS 200112L + +/* We have at least one terminal. */ +#define _POSIX2_CHAR_TERM 200112L + +/* Neither process nor thread sporadic server interfaces is available. */ +#define _POSIX_SPORADIC_SERVER -1 +#define _POSIX_THREAD_SPORADIC_SERVER -1 + +/* trace.h is not available. */ +#define _POSIX_TRACE -1 +#define _POSIX_TRACE_EVENT_FILTER -1 +#define _POSIX_TRACE_INHERIT -1 +#define _POSIX_TRACE_LOG -1 + +/* Typed memory objects are not available. */ +#define _POSIX_TYPED_MEMORY_OBJECTS -1 + +/* No support for priority inheritance or protection so far. */ +#define _POSIX_THREAD_PRIO_INHERIT -1 +#define _POSIX_THREAD_PRIO_PROTECT -1 + +#endif /* posix_opt.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S new file mode 100644 index 000000000..cf50a1eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __close_nocancel (int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END(__libc_close) + +libc_hidden_def (__close_nocancel) +libc_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libc_hidden_weak (__close) +weak_alias (__libc_close, close) +libc_hidden_weak (close) + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S new file mode 100644 index 000000000..441843fa0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libc_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libc_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libc_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S new file mode 100644 index 000000000..cd0e1b879 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_creat, creat, 2) +ret +PSEUDO_END(__libc_creat) +libc_hidden_def (__libc_creat) +weak_alias (__libc_creat, creat) +libc_hidden_weak (creat) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c new file mode 100644 index 000000000..9149efe58 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE pd + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S new file mode 100644 index 000000000..bb996fecf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S @@ -0,0 +1,23 @@ +/* Copyright (C) 1991,92,97,99,2002 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +PSEUDO (__exit_thread, exit, 1) + /* Shouldn't get here. */ +PSEUDO_END(__exit_thread) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c new file mode 100644 index 000000000..a84b5c237 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,220 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sysdep.h> +#include <tls.h> +#include "fork.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <errno.h> + +unsigned long int *__fork_generation_pointer; + + + +/* The single linked list of all currently registered for handlers. */ +struct fork_handler *__fork_handlers; + + +static void +fresetlockfiles (void) +{ + FILE *fp; +#ifdef __USE_STDIO_FUTEXES__ + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) + STDIO_INIT_MUTEX(fp->__lock); +#else + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) + pthread_mutex_init(&fp->__lock, &attr); + + pthread_mutexattr_destroy(&attr); +#endif +} + +extern __typeof(fork) __libc_fork; +pid_t __libc_fork (void) +{ + pid_t pid; + struct used_handler + { + struct fork_handler *handler; + struct used_handler *next; + } *allp = NULL; + + /* Run all the registered preparation handlers. In reverse order. + While doing this we build up a list of all the entries. */ + struct fork_handler *runp; + while ((runp = __fork_handlers) != NULL) + { + unsigned int oldval = runp->refcntr; + + if (oldval == 0) + /* This means some other thread removed the list just after + the pointer has been loaded. Try again. Either the list + is empty or we can retry it. */ + continue; + + /* Bump the reference counter. */ + if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr, + oldval + 1, oldval)) + /* The value changed, try again. */ + continue; + + /* We bumped the reference counter for the first entry in the + list. That means that none of the following entries will + just go away. The unloading code works in the order of the + list. + + While executing the registered handlers we are building a + list of all the entries so that we can go backward later on. */ + while (1) + { + /* Execute the handler if there is one. */ + if (runp->prepare_handler != NULL) + runp->prepare_handler (); + + /* Create a new element for the list. */ + struct used_handler *newp + = (struct used_handler *) alloca (sizeof (*newp)); + newp->handler = runp; + newp->next = allp; + allp = newp; + + /* Advance to the next handler. */ + runp = runp->next; + if (runp == NULL) + break; + + /* Bump the reference counter for the next entry. */ + atomic_increment (&runp->refcntr); + } + + /* We are done. */ + break; + } + + __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + +#ifndef NDEBUG + pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +#endif + + /* We need to prevent the getpid() code to update the PID field so + that, if a signal arrives in the child very early and the signal + handler uses getpid(), the value returned is correct. */ + pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); + THREAD_SETMEM (THREAD_SELF, pid, -parentpid); + +#ifdef ARCH_FORK + pid = ARCH_FORK (); +#else +# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used" + pid = INLINE_SYSCALL (fork, 0); +#endif + + + if (pid == 0) + { + struct pthread *self = THREAD_SELF; + + assert (THREAD_GETMEM (self, tid) != ppid); + + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += 4; + + /* Adjust the PID field for the new process. */ + THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); + +#if HP_TIMING_AVAIL + /* The CPU clock of the thread and process have to be set to zero. */ + hp_timing_t now; + HP_TIMING_NOW (now); + THREAD_SETMEM (self, cpuclock_offset, now); + GL(dl_cpuclock_offset) = now; +#endif + + /* Reset the file list. These are recursive mutexes. */ + fresetlockfiles (); + + /* Reset locks in the I/O code. */ + STDIO_INIT_MUTEX(_stdio_openlist_add_lock); + + /* Run the handlers registered for the child. */ + while (allp != NULL) + { + if (allp->handler->child_handler != NULL) + allp->handler->child_handler (); + + /* Note that we do not have to wake any possible waiter. + This is the only thread in the new process. */ + --allp->handler->refcntr; + + /* XXX We could at this point look through the object pool + and mark all objects not on the __fork_handlers list as + unused. This is necessary in case the fork() happened + while another thread called dlclose() and that call had + to create a new list. */ + + allp = allp->next; + } + + /* Initialize the fork lock. */ + __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER; + } + else + { + assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); + + /* Restore the PID value. */ + THREAD_SETMEM (THREAD_SELF, pid, parentpid); + + /* We execute this even if the 'fork' call failed. */ + __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + + /* Run the handlers registered for the parent. */ + while (allp != NULL) + { + if (allp->handler->parent_handler != NULL) + allp->handler->parent_handler (); + + if (atomic_decrement_and_test (&allp->handler->refcntr) + && allp->handler->need_signal) + lll_futex_wake (allp->handler->refcntr, 1); + + allp = allp->next; + } + } + + return pid; +} +weak_alias(__libc_fork,__fork) +libc_hidden_proto(fork) +weak_alias(__libc_fork,fork) +libc_hidden_weak(fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h new file mode 100644 index 000000000..bcdf6217c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <lowlevellock.h> + +/* The fork generation counter, defined in libpthread. */ +extern unsigned long int __fork_generation attribute_hidden; + +/* Pointer to the fork generation counter in the thread library. */ +extern unsigned long int *__fork_generation_pointer attribute_hidden; + +/* Lock to protect allocation and deallocation of fork handlers. */ +extern lll_lock_t __fork_lock attribute_hidden; + +/* Elements of the fork handler lists. */ +struct fork_handler +{ + struct fork_handler *next; + void (*prepare_handler) (void); + void (*parent_handler) (void); + void (*child_handler) (void); + void *dso_handle; + unsigned int refcntr; + int need_signal; +}; + +/* The single linked list of all currently registered for handlers. */ +extern struct fork_handler *__fork_handlers; + + +/* Function to call to unregister fork handlers. */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers. */ +extern int __register_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void), + void *dso_handle); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c new file mode 100644 index 000000000..9a4f51c9d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <tls.h> +#include <sysdep.h> + + +extern __typeof(getpid) __getpid; +#ifndef NOT_IN_libc +static __always_inline pid_t really_getpid (pid_t oldval); + +static __always_inline pid_t really_getpid (pid_t oldval) +{ + if (__builtin_expect (oldval == 0, 1)) + { + pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); + if (__builtin_expect (selftid != 0, 1)) + return selftid; + } + + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); + + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + if (oldval == 0) + THREAD_SETMEM (THREAD_SELF, tid, result); + return result; +} +#endif + +pid_t __getpid (void) +{ +#ifdef NOT_IN_libc + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +#else + pid_t result = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (result <= 0, 0)) + result = really_getpid (result); +#endif + return result; +} +libc_hidden_proto(getpid) +weak_alias(__getpid, getpid) +libc_hidden_weak(getpid) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch new file mode 100644 index 000000000..06c0bd8b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch @@ -0,0 +1,73 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 + + +libpthread_SSRC = pt-vfork.S clone.S pthread_spin_unlock.S pthread_once.S +libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +libpthread_SSRC += i486/lowlevellock.S i486/pthread_barrier_wait.S i486/pthread_cond_signal.S i486/pthread_cond_broadcast.S \ + i486/pthread_cond_timedwait.S i486/pthread_cond_wait.S i486/sem_post.S i486/sem_timedwait.S \ + i486/sem_trywait.S i486/sem_wait.S i486/pthread_rwlock_rdlock.S i486/pthread_rwlock_wrlock.S \ + i486/pthread_rwlock_timedrdlock.S i486/pthread_rwlock_timedwrlock.S i486/pthread_rwlock_unlock.S + +libc_a_SSRC += i486/libc-lowlevellock.S + + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h new file mode 100644 index 000000000..0ec6e5534 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -0,0 +1,170 @@ +/* Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +/* Extra attributes for the cleanup functions. */ +#define __cleanup_fct_attribute __attribute ((regparm (1))) + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h new file mode 100644 index 000000000..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S new file mode 100644 index 000000000..9c7c46467 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/i386/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c new file mode 100644 index 000000000..35719be96 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* The "thread register" gets initialized from a segment descriptor. + Initialize such a descriptor first. */ +#define PREPARE_CREATE \ + union user_desc_init desc; \ + \ + /* Describe the thread-local storage segment. */ \ + \ + /* The 'entry_number' field. The first three bits of the segment \ + register value select the GDT, ignore them. We get the index \ + from the value of the %gs register in the current thread. */ \ + desc.vals[0] = TLS_GET_GS () >> 3; \ + /* The 'base_addr' field. Pointer to the TCB. */ \ + desc.vals[1] = (unsigned long int) pd; \ + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \ + desc.vals[2] = 0xfffff; \ + /* Collapsed value of the bitfield: \ + .seg_32bit = 1 \ + .contents = 0 \ + .read_exec_only = 0 \ + .limit_in_pages = 1 \ + .seg_not_present = 0 \ + .useable = 1 */ \ + desc.vals[3] = 0x51 + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE &desc.desc + + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c new file mode 100644 index 000000000..b874538b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sysdep.h> +#include <tls.h> + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S new file mode 100644 index 000000000..223b11108 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* In libc.so we do not unconditionally use the lock prefix. Only if + the application is using threads. */ +#ifndef UP +# define LOCK \ + cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \ + je,pt 0f; \ + lock; \ +0: +#endif + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S new file mode 100644 index 000000000..955e119ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -0,0 +1,283 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + + .text + +#ifndef LOCK +# ifdef UP +# define LOCK +# else +# define LOCK lock +# endif +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 16 +__lll_mutex_lock_wait: + pushl %edx + pushl %ebx + pushl %esi + + movl $2, %edx + movl %ecx, %ebx + xorl %esi, %esi /* No timeout. */ + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + + cmpl %edx, %eax /* NB: %edx == 2 */ + jne 2f + +1: movl $SYS_futex, %eax + ENTER_KERNEL + +2: movl %edx, %eax + xchgl %eax, (%ebx) /* NB: lock is implied */ + + testl %eax, %eax + jnz,pn 1b + + popl %esi + popl %ebx + popl %edx + ret + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 16 +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + cmpl $1000000000, 4(%edx) + jae 3f + + pushl %edi + pushl %esi + pushl %ebx + pushl %ebp + + /* Stack frame for the timespec and timeval structs. */ + subl $8, %esp + + movl %ecx, %ebp + movl %edx, %edi + +1: + /* Get current time. */ + movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 4f + addl $1000000000, %edx + subl $1, %ecx +4: testl %ecx, %ecx + js 5f /* Time is already up. */ + + /* Store relative timeout. */ + movl %ecx, (%esp) + movl %edx, 4(%esp) + + movl %ebp, %ebx + + movl $1, %eax + movl $2, %edx + LOCK + cmpxchgl %edx, (%ebx) + + testl %eax, %eax + je 8f + + /* Futex call. */ + movl %esp, %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx + +8: /* NB: %edx == 2 */ + xorl %eax, %eax + LOCK + cmpxchgl %edx, (%ebx) + + jnz 7f + +6: addl $8, %esp + popl %ebp + popl %ebx + popl %esi + popl %edi + ret + + /* Check whether the time expired. */ +7: cmpl $-ETIMEDOUT, %ecx + je 5f + + /* Make sure the current holder knows we are going to sleep. */ + movl %edx, %eax + xchgl %eax, (%ebx) + testl %eax, %eax + jz 6b + jmp 1b + +3: movl $EINVAL, %eax + ret + +5: movl $ETIMEDOUT, %eax + jmp 6b + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 16 +lll_unlock_wake_cb: + pushl %ebx + pushl %ecx + pushl %edx + + movl 20(%esp), %ebx + LOCK + subl $1, (%ebx) + je 1f + + movl $FUTEX_WAKE, %ecx + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + movl $0, (%ebx) + ENTER_KERNEL + +1: popl %edx + popl %ecx + popl %ebx + ret + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 16 +__lll_mutex_unlock_wake: + pushl %ebx + pushl %ecx + pushl %edx + + movl %eax, %ebx + movl $0, (%eax) + movl $FUTEX_WAKE, %ecx + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + ENTER_KERNEL + + popl %edx + popl %ecx + popl %ebx + ret + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 16 +__lll_timedwait_tid: + pushl %edi + pushl %esi + pushl %ebx + pushl %ebp + + movl %eax, %ebp + movl %edx, %edi + subl $8, %esp + + /* Get current time. */ +2: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 5f + addl $1000000000, %edx + subl $1, %ecx +5: testl %ecx, %ecx + js 6f /* Time is already up. */ + + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + + movl (%ebp), %edx + testl %edx, %edx + jz 4f + + movl %esp, %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %ebp, %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + + cmpl $0, (%ebx) + jne 1f +4: xorl %eax, %eax + +3: addl $8, %esp + popl %ebp + popl %ebx + popl %esi + popl %edi + ret + +1: cmpl $-ETIMEDOUT, %eax + jne 2b +6: movl $ETIMEDOUT, %eax + jmp 3b + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S new file mode 100644 index 000000000..2af9e38cd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S @@ -0,0 +1,162 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 16 +pthread_barrier_wait: + pushl %ebx + + movl 8(%esp), %ebx + + /* Get the mutex. */ + movl $1, %edx + xorl %eax, %eax + LOCK + cmpxchgl %edx, MUTEX(%ebx) + jnz 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: subl $1, LEFT(%ebx) + je 3f + + /* There are more threads to come. */ + pushl %esi + +#if CURR_EVENT == 0 + movl (%ebx), %edx +#else + movl CURR_EVENT(%ebx), %edx +#endif + + /* Release the mutex. */ + LOCK + subl $1, MUTEX(%ebx) + jne 6f + + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ +7: xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + xorl %esi, %esi +8: movl $SYS_futex, %eax + ENTER_KERNEL + + /* Don't return on spurious wakeups. The syscall does not change + any register except %eax so there is no need to reload any of + them. */ +#if CURR_EVENT == 0 + cmpl %edx, (%ebx) +#else + cmpl %edx, CURR_EVENT(%ebx) +#endif + je,pn 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%ebx), %ecx + LOCK + xaddl %edx, LEFT(%ebx) + subl $1, %ecx + cmpl %ecx, %edx + jne,pt 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + subl $1, MUTEX(%ebx) + jne 9f + + /* Note: %esi is still zero. */ +10: movl %esi, %eax /* != PTHREAD_BARRIER_SERIAL_THREAD */ + + popl %esi + popl %ebx + ret + + /* The necessary number of threads arrived. */ +3: +#if CURR_EVENT == 0 + addl $1, (%ebx) +#else + addl $1, CURR_EVENT(%ebx) +#endif + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%ebx), %ecx + LOCK + xaddl %edx, LEFT(%ebx) + subl $1, %ecx + cmpl %ecx, %edx + jne,pt 5f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + subl $1, MUTEX(%ebx) + jne 4f + +5: orl $-1, %eax /* == PTHREAD_BARRIER_SERIAL_THREAD */ + + popl %ebx + ret + +1: leal MUTEX(%ebx), %ecx + call __lll_mutex_lock_wait + jmp 2b + +4: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 5b + +6: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 7b + +9: leal MUTEX(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 10b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S new file mode 100644 index 000000000..6e8ffe6f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S @@ -0,0 +1,161 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 16 +__pthread_cond_broadcast: + + pushl %ebx + pushl %esi + pushl %edi + pushl %ebp + + movl 20(%esp), %ebx + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + +2: addl $cond_futex, %ebx + movl total_seq+4-cond_futex(%ebx), %eax + movl total_seq-cond_futex(%ebx), %ebp + cmpl wakeup_seq+4-cond_futex(%ebx), %eax + ja 3f + jb 4f + cmpl wakeup_seq-cond_futex(%ebx), %ebp + jna 4f + + /* Cause all currently waiting threads to recognize they are + woken up. */ +3: movl %ebp, wakeup_seq-cond_futex(%ebx) + movl %eax, wakeup_seq-cond_futex+4(%ebx) + movl %ebp, woken_seq-cond_futex(%ebx) + movl %eax, woken_seq-cond_futex+4(%ebx) + addl %ebp, %ebp + addl $1, broadcast_seq-cond_futex(%ebx) + movl %ebp, (%ebx) + + /* Get the address of the mutex used. */ + movl dep_mutex-cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK + subl $1, cond_lock-cond_futex(%ebx) + jne 7f + + /* Don't use requeue for pshared condvars. */ +8: cmpl $-1, %edi + je 9f + + /* Wake up all threads. */ + movl $FUTEX_CMP_REQUEUE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %esi + movl $1, %edx + /* Get the address of the futex involved. */ +# if MUTEX_FUTEX != 0 + addl $MUTEX_FUTEX, %edi +# endif +/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for sysenter. + ENTER_KERNEL */ + int $0x80 + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + cmpl $0xfffff001, %eax + jae 9f + +10: xorl %eax, %eax + popl %ebp + popl %edi + popl %esi + popl %ebx + ret + + .align 16 + /* Unlock. */ +4: LOCK + subl $1, cond_lock-cond_futex(%ebx) + jne 5f + +6: xorl %eax, %eax + popl %ebp + popl %edi + popl %esi + popl %ebx + ret + + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +5: leal cond_lock-cond_futex(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 6b + + /* Unlock in loop requires waekup. */ +7: leal cond_lock-cond_futex(%ebx), %eax + call __lll_mutex_unlock_wake + jmp 8b + +9: /* The futex requeue functionality is not available. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + jmp 10b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S new file mode 100644 index 000000000..11650c8e1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S @@ -0,0 +1,110 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 16 +__pthread_cond_signal: + + pushl %ebx + pushl %edi + + movl 12(%esp), %edi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%edi) +#else + cmpxchgl %edx, cond_lock(%edi) +#endif + jnz 1f + +2: leal cond_futex(%edi), %ebx + movl total_seq+4(%edi), %eax + movl total_seq(%edi), %ecx + cmpl wakeup_seq+4(%edi), %eax +#if cond_lock != 0 + /* Must use leal to preserve the flags. */ + leal cond_lock(%edi), %edi +#endif + ja 3f + jb 4f + cmpl wakeup_seq-cond_futex(%ebx), %ecx + jbe 4f + + /* Bump the wakeup number. */ +3: addl $1, wakeup_seq-cond_futex(%ebx) + adcl $0, wakeup_seq-cond_futex+4(%ebx) + addl $1, (%ebx) + + /* Wake up one thread. */ + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $1, %edx + ENTER_KERNEL + + /* Unlock. Note that at this point %edi always points to + cond_lock. */ +4: LOCK + subl $1, (%edi) + jne 5f + +6: xorl %eax, %eax + popl %edi + popl %ebx + ret + + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %edi, %ecx +#else + leal cond_lock(%edi), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: movl %edi, %eax + call __lll_mutex_unlock_wake + jmp 6b + .size __pthread_cond_signal, .-__pthread_cond_signal diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S new file mode 100644 index 000000000..b8f0d2e4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -0,0 +1,465 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 16 +__pthread_cond_timedwait: +.LSTARTCODE: + pushl %ebp +.Lpush_ebp: + pushl %edi +.Lpush_edi: + pushl %esi +.Lpush_esi: + pushl %ebx +.Lpush_ebx: + + movl 20(%esp), %ebx + movl 28(%esp), %ebp + + cmpl $1000000000, 4(%ebp) + movl $EINVAL, %eax + jae 18f + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ +2: cmpl $-1, dep_mutex(%ebx) + movl 24(%esp), %eax + je 17f + movl %eax, dep_mutex(%ebx) + + /* Unlock the mutex. */ +17: xorl %edx, %edx + call __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 16f + + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) + addl $1, cond_futex(%ebx) + addl $(1 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 24 + subl $FRAME_SIZE, %esp +.Lsubl: + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl broadcast_seq(%ebx), %eax + movl %edi, 12(%esp) + movl %edx, 16(%esp) + movl %eax, 20(%esp) + + /* Get the current time. */ +8: movl %ebx, %edx +#ifdef __NR_clock_gettime + /* Get the clock number. */ + movl cond_nwaiters(%ebx), %ebx + andl $((1 << clock_bits) - 1), %ebx + /* Only clocks 0 and 1 are allowed so far. Both are handled in the + kernel. */ + leal 4(%esp), %ecx + movl $__NR_clock_gettime, %eax + ENTER_KERNEL +# ifndef __ASSUME_POSIX_TIMERS + cmpl $-ENOSYS, %eax + je 19f +# endif + movl %edx, %ebx + + /* Compute relative timeout. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl 8(%esp), %edx +#else + /* Get the current time. */ + leal 4(%esp), %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + movl %edx, %ebx + + /* Compute relative timeout. */ + movl 8(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl %eax, %edx +#endif + jns 12f + addl $1000000000, %edx + subl $1, %ecx +12: testl %ecx, %ecx + movl $-ETIMEDOUT, %esi + js 6f + + /* Store relative timeout. */ +21: movl %ecx, 4(%esp) + movl %edx, 8(%esp) + + movl cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 3f + +.LcleanupSTART: +4: call __pthread_enable_asynccancel + movl %eax, (%esp) + + leal 4(%esp), %esi + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %edi, %edx + addl $cond_futex, %ebx +.Ladd_cond_futex: + movl $SYS_futex, %eax + ENTER_KERNEL + subl $cond_futex, %ebx +.Lsub_cond_futex: + movl %eax, %esi + + movl (%esp), %eax + call __pthread_disable_asynccancel +.LcleanupEND: + + /* Lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 5f + +6: movl broadcast_seq(%ebx), %eax + cmpl 20(%esp), %eax + jne 23f + + movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + + cmpl 16(%esp), %edx + jne 7f + cmpl 12(%esp), %edi + je 15f + +7: cmpl %ecx, %edx + jne 9f + cmp %eax, %edi + jne 9f + +15: cmpl $-ETIMEDOUT, %esi + jne 8b + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + addl $1, cond_futex(%ebx) + movl $ETIMEDOUT, %esi + jmp 14f + +23: xorl %esi, %esi + jmp 24f + +9: xorl %esi, %esi +14: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +24: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 25f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 25f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + +25: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movl 24+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + addl $FRAME_SIZE, %esp +.Laddl: + + /* We return the result of the mutex_lock operation if it failed. */ + testl %eax, %eax +#ifdef HAVE_CMOV + cmovel %esi, %eax +#else + jne 22f + movl %esi, %eax +22: +#endif + +18: popl %ebx +.Lpop_ebx: + popl %esi +.Lpop_esi: + popl %edi +.Lpop_edi: + popl %ebp +.Lpop_ebp: + + ret + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +.LSbl2: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +16: +.LSbl3: + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 18b + + movl %eax, %esi +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + movl %esi, %eax + jmp 18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS + /* clock_gettime not available. */ +.LSbl4: +19: leal 4(%esp), %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + movl %edx, %ebx + + /* Compute relative timeout. */ + movl 8(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx + subl %eax, %edx + jns 20f + addl $1000000000, %edx + subl $1, %ecx +20: testl %ecx, %ecx + movl $-ETIMEDOUT, %esi + js 6b + jmp 21b +#endif + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + + .type __condvar_tw_cleanup2, @function +__condvar_tw_cleanup2: + subl $cond_futex, %ebx +.LSbl5: + .size __condvar_tw_cleanup2, .-__condvar_tw_cleanup2 + .type __condvar_tw_cleanup, @function +__condvar_tw_cleanup: + movl %eax, %esi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jz 1f + +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + +1: movl broadcast_seq(%ebx), %eax + cmpl 20(%esp), %eax + jne 3f + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + addl $1, cond_futex(%ebx) + + addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +3: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorl %edi, %edi + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 4f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + movl $1, %edi + +4: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + je 2f + +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testl %edi, %edi + jnz 5f + addl $cond_futex, %ebx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %edx + ENTER_KERNEL + +5: movl 24+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + + movl %esi, (%esp) +.LcallUR: + call _Unwind_Resume + hlt +.LENDCODE: + .size __condvar_tw_cleanup, .-__condvar_tw_cleanup diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S new file mode 100644 index 000000000..377a7340f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S @@ -0,0 +1,357 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 16 +__pthread_cond_wait: +.LSTARTCODE: + + pushl %edi +.Lpush_edi: + pushl %esi +.Lpush_esi: + pushl %ebx +.Lpush_ebx: + + xorl %esi, %esi + movl 16(%esp), %ebx + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 1f + + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ +2: cmpl $-1, dep_mutex(%ebx) + movl 20(%esp), %eax + je 15f + movl %eax, dep_mutex(%ebx) + + /* Unlock the mutex. */ +15: xorl %edx, %edx + call __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 12f + + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) + addl $1, cond_futex(%ebx) + addl $(1 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 16 + subl $FRAME_SIZE, %esp +.Lsubl: + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl broadcast_seq(%ebx), %eax + movl %edi, 4(%esp) + movl %edx, 8(%esp) + movl %eax, 12(%esp) + +8: movl cond_futex(%ebx), %edi + + /* Unlock. */ + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 3f + +.LcleanupSTART: +4: call __pthread_enable_asynccancel + movl %eax, (%esp) + + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %edi, %edx + addl $cond_futex, %ebx +.Ladd_cond_futex: + movl $SYS_futex, %eax + ENTER_KERNEL + subl $cond_futex, %ebx +.Lsub_cond_futex: + + movl (%esp), %eax + call __pthread_disable_asynccancel +.LcleanupEND: + + /* Lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jnz 5f + +6: movl broadcast_seq(%ebx), %eax + cmpl 12(%esp), %eax + jne 16f + + movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + + cmpl 8(%esp), %edx + jne 7f + cmpl 4(%esp), %edi + je 8b + +7: cmpl %ecx, %edx + jne 9f + cmp %eax, %edi + je 8b + +9: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + + /* Unlock */ +16: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 17f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 17f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + +17: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 10f + +11: movl 20+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + addl $FRAME_SIZE, %esp +.Laddl: + +14: popl %ebx +.Lpop_ebx: + popl %esi +.Lpop_esi: + popl %edi +.Lpop_edi: + + /* We return the result of the mutex_lock operation. */ + ret + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +3: +.LSbl2: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +12: +.LSbl3: + LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + jne 14b + + movl %eax, %esi +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + movl %esi, %eax + jmp 14b + .size __pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + + .type __condvar_w_cleanup2, @function +__condvar_w_cleanup2: + subl $cond_futex, %ebx + .size __condvar_w_cleanup2, .-__condvar_w_cleanup2 +.LSbl4: + .type __condvar_w_cleanup, @function +__condvar_w_cleanup: + movl %eax, %esi + + /* Get internal lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, cond_lock(%ebx) +#endif + jz 1f + +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + +1: movl broadcast_seq(%ebx), %eax + cmpl 12(%esp), %eax + jne 3f + + addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + addl $1, cond_futex(%ebx) + + addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + +3: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorl %edi, %edi + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 4f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + subl $cond_nwaiters, %ebx + movl $1, %edi + +4: LOCK +#if cond_lock == 0 + subl $1, (%ebx) +#else + subl $1, cond_lock(%ebx) +#endif + je 2f + +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testl %edi, %edi + jnz 5f + addl $cond_futex, %ebx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + movl $0x7fffffff, %edx + ENTER_KERNEL + +5: movl 20+FRAME_SIZE(%esp), %eax + call __pthread_mutex_cond_lock + + movl %esi, (%esp) +.LcallUR: + call _Unwind_Resume + hlt +.LENDCODE: + .size __condvar_w_cleanup, .-__condvar_w_cleanup diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..aec79f07e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S @@ -0,0 +1,175 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 16 +__pthread_rwlock_rdlock: + pushl %esi + pushl %ebx + + xorl %esi, %esi + movl 12(%esp), %ebx + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 1f + +2: movl WRITER(%ebx), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%ebx) + je 5f + cmpl $0, FLAGS(%ebx) + je 5f + +3: addl $1, READERS_QUEUED(%ebx) + je 4f + + movl READERS_WAKEUP(%ebx), %edx + + LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 10f + +11: addl $READERS_WAKEUP, %ebx + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + + subl $READERS_WAKEUP, %ebx + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 12f + +13: subl $1, READERS_QUEUED(%ebx) + jmp 2b + +5: xorl %ecx, %ecx + addl $1, NR_READERS(%ebx) + je 8f +9: LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 6f +7: + + movl %ecx, %eax + popl %ebx + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b + /* Deadlock detected. */ + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: subl $1, NR_READERS(%ebx) + movl $EAGAIN, %ecx + jmp 9b + + /* Overflow. */ +4: subl $1, READERS_QUEUED(%ebx) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..3717d7ef5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S @@ -0,0 +1,214 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 16 +pthread_rwlock_timedrdlock: + pushl %esi + pushl %edi + pushl %ebx + pushl %ebp + subl $8, %esp + + movl 28(%esp), %ebp + movl 32(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 1f + +2: movl WRITER(%ebp), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%ebp) + je 5f + cmpl $0, FLAGS(%ebp) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpl $1000000000, 4(%edi) + jae 19f + + addl $1, READERS_QUEUED(%ebp) + je 4f + + movl READERS_WAKEUP(%ebp), %esi + + LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 10f + + /* Get current time. */ +11: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 15f + addl $1000000000, %edx + subl $1, %ecx +15: testl %ecx, %ecx + js 16f /* Time is already up. */ + + /* Futex call. */ + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl %esi, %edx + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %esp, %esi + leal READERS_WAKEUP(%ebp), %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx +17: + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 12f + +13: subl $1, READERS_QUEUED(%ebp) + cmpl $-ETIMEDOUT, %ecx + jne 2b + +18: movl $ETIMEDOUT, %ecx + jmp 9f + + +5: xorl %ecx, %ecx + addl $1, NR_READERS(%ebp) + je 8f +9: LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 6f + +7: movl %ecx, %eax + + addl $8, %esp + popl %ebp + popl %ebx + popl %edi + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: subl $1, NR_READERS(%ebp) + movl $EAGAIN, %ecx + jmp 9b + + /* Overflow. */ +4: subl $1, READERS_QUEUED(%ebp) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + +16: movl $-ETIMEDOUT, %ecx + jmp 17b + +19: movl $EINVAL, %ecx + jmp 9b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..09c9e30ca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S @@ -0,0 +1,207 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 16 +pthread_rwlock_timedwrlock: + pushl %esi + pushl %edi + pushl %ebx + pushl %ebp + subl $8, %esp + + movl 28(%esp), %ebp + movl 32(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 1f + +2: movl WRITER(%ebp), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%ebp) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpl $1000000000, 4(%edi) + jae 19f + + addl $1, WRITERS_QUEUED(%ebp) + je 4f + + movl WRITERS_WAKEUP(%ebp), %esi + + LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 10f + + /* Get current time. */ +11: movl %esp, %ebx + xorl %ecx, %ecx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 15f + addl $1000000000, %edx + subl $1, %ecx +15: testl %ecx, %ecx + js 16f /* Time is already up. */ + + /* Futex call. */ + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl %esi, %edx + xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %esp, %esi + leal WRITERS_WAKEUP(%ebp), %ebx + movl $SYS_futex, %eax + ENTER_KERNEL + movl %eax, %ecx +17: + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebp) +#else + cmpxchgl %edx, MUTEX(%ebp) +#endif + jnz 12f + +13: subl $1, WRITERS_QUEUED(%ebp) + cmpl $-ETIMEDOUT, %ecx + jne 2b + +18: movl $ETIMEDOUT, %ecx + jmp 9f + + +5: xorl %ecx, %ecx + movl %gs:TID, %eax + movl %eax, WRITER(%ebp) +9: LOCK +#if MUTEX == 0 + subl $1, (%ebp) +#else + subl $1, MUTEX(%ebp) +#endif + jne 6f + +7: movl %ecx, %eax + + addl $8, %esp + popl %ebp + popl %ebx + popl %edi + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID, %eax + jne 3b +20: movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +4: subl $1, WRITERS_QUEUED(%ebp) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebp, %eax +#else + leal MUTEX(%ebp), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebp, %ecx +#else + leal MUTEX(%ebp), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + +16: movl $-ETIMEDOUT, %ecx + jmp 17b + +19: movl $EINVAL, %ecx + jmp 9b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S new file mode 100644 index 000000000..597c82fa8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S @@ -0,0 +1,140 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 16 +__pthread_rwlock_unlock: + pushl %ebx + pushl %edi + + movl 12(%esp), %edi + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%edi) +#else + cmpxchgl %edx, MUTEX(%edi) +#endif + jnz 1f + +2: cmpl $0, WRITER(%edi) + jne 5f + subl $1, NR_READERS(%edi) + jnz 6f + +5: movl $0, WRITER(%edi) + + movl $1, %ecx + leal WRITERS_WAKEUP(%edi), %ebx + movl %ecx, %edx + cmpl $0, WRITERS_QUEUED(%edi) + jne 0f + + /* If also no readers waiting nothing to do. */ + cmpl $0, READERS_QUEUED(%edi) + je 6f + + movl $0x7fffffff, %edx + leal READERS_WAKEUP(%edi), %ebx + +0: addl $1, (%ebx) + LOCK +#if MUTEX == 0 + subl $1, (%edi) +#else + subl $1, MUTEX(%edi) +#endif + jne 7f + +8: movl $SYS_futex, %eax + ENTER_KERNEL + + xorl %eax, %eax + popl %edi + popl %ebx + ret + + .align 16 +6: LOCK +#if MUTEX == 0 + subl $1, (%edi) +#else + subl $1, MUTEX(%edi) +#endif + jne 3f + +4: xorl %eax, %eax + popl %edi + popl %ebx + ret + +1: +#if MUTEX == 0 + movl %edi, %ecx +#else + leal MUTEX(%edx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +3: +#if MUTEX == 0 + movl %edi, %eax +#else + leal MUTEX(%edx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + +7: +#if MUTEX == 0 + movl %edi, %eax +#else + leal MUTEX(%edx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 8b + + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..bb384a267 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 16 +__pthread_rwlock_wrlock: + pushl %esi + pushl %ebx + + xorl %esi, %esi + movl 12(%esp), %ebx + + /* Get the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 1f + +2: movl WRITER(%ebx), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%ebx) + je 5f + +3: addl $1, WRITERS_QUEUED(%ebx) + je 4f + + movl WRITERS_WAKEUP(%ebx), %edx + + LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 10f + +11: addl $WRITERS_WAKEUP, %ebx + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + + subl $WRITERS_WAKEUP, %ebx + + /* Reget the lock. */ + movl $1, %edx + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %edx, (%ebx) +#else + cmpxchgl %edx, MUTEX(%ebx) +#endif + jnz 12f + +13: subl $1, WRITERS_QUEUED(%ebx) + jmp 2b + +5: xorl %ecx, %ecx + movl %gs:TID, %eax + movl %eax, WRITER(%ebx) +9: LOCK +#if MUTEX == 0 + subl $1, (%ebx) +#else + subl $1, MUTEX(%ebx) +#endif + jne 6f +7: + + movl %ecx, %eax + popl %ebx + popl %esi + ret + +1: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + +14: cmpl %gs:TID , %eax + jne 3b + movl $EDEADLK, %ecx + jmp 9b + +6: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 7b + +4: subl $1, WRITERS_QUEUED(%ebx) + movl $EAGAIN, %ecx + jmp 9b + +10: +#if MUTEX == 0 + movl %ebx, %eax +#else + leal MUTEX(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movl %ebx, %ecx +#else + leal MUTEX(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 13b + .size __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S new file mode 100644 index 000000000..82f24c267 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S @@ -0,0 +1,96 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl __new_sem_post + .type __new_sem_post,@function + .align 16 +__new_sem_post: + pushl %ebx + + movl 8(%esp), %ebx + movl $1, %edx + LOCK + xaddl %edx, (%ebx) + + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + addl $1, %edx + ENTER_KERNEL + + testl %eax, %eax + js 1f + + xorl %eax, %eax + popl %ebx + ret + +1: +#ifdef PIC + call __i686.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl $EINVAL, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl $EINVAL, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl $EINVAL, (%eax) +#endif + + orl $-1, %eax + popl %ebx + ret + .size __new_sem_post,.-__new_sem_post +weak_alias(__new_sem_post, sem_post) + + +#ifdef PIC + .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits + .globl __i686.get_pc_thunk.bx + .hidden __i686.get_pc_thunk.bx + .type __i686.get_pc_thunk.bx,@function +__i686.get_pc_thunk.bx: + movl (%esp), %ebx; + ret + .size __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S new file mode 100644 index 000000000..f306e400d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S @@ -0,0 +1,193 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 16 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + movl %gs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 10f + + movl 4(%esp), %ecx + + movl (%ecx), %eax +2: testl %eax, %eax + je,pn 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ecx) + jne,pn 2b + + xorl %eax, %eax + ret + + /* Check whether the timeout value is valid. */ +1: pushl %esi + cfi_adjust_cfa_offset(4) + pushl %edi + cfi_adjust_cfa_offset(4) + pushl %ebx + cfi_adjust_cfa_offset(4) + subl $12, %esp + cfi_adjust_cfa_offset(12) + + movl 32(%esp), %edi + cfi_offset(7, -12) /* %edi */ + + /* Check for invalid nanosecond field. */ + cmpl $1000000000, 4(%edi) + movl $EINVAL, %esi + cfi_offset(6, -8) /* %esi */ + jae 6f + + cfi_offset(3, -16) /* %ebx */ +7: call __pthread_enable_asynccancel + movl %eax, 8(%esp) + + xorl %ecx, %ecx + movl %esp, %ebx + movl %ecx, %edx + movl $SYS_gettimeofday, %eax + ENTER_KERNEL + + /* Compute relative timeout. */ + movl 4(%esp), %eax + movl $1000, %edx + mul %edx /* Milli seconds to nano seconds. */ + movl (%edi), %ecx + movl 4(%edi), %edx + subl (%esp), %ecx + subl %eax, %edx + jns 5f + addl $1000000000, %edx + subl $1, %ecx +5: testl %ecx, %ecx + movl $ETIMEDOUT, %esi + js 6f /* Time is already up. */ + + movl %ecx, (%esp) /* Store relative timeout. */ + movl %edx, 4(%esp) + movl 28(%esp), %ebx + xorl %ecx, %ecx + movl %esp, %esi + movl $SYS_futex, %eax + xorl %edx, %edx + ENTER_KERNEL + movl %eax, %esi + + movl 8(%esp), %eax + call __pthread_disable_asynccancel + + testl %esi, %esi + je,pt 9f + cmpl $-EWOULDBLOCK, %esi + jne 3f + +9: movl (%ebx), %eax +8: testl %eax, %eax + je 7b + + leal -1(%eax), %ecx + LOCK + cmpxchgl %ecx, (%ebx) + jne,pn 8b + + addl $12, %esp + cfi_adjust_cfa_offset(-12) + xorl %eax, %eax + popl %ebx + cfi_adjust_cfa_offset(-4) + cfi_restore(3) + popl %edi + cfi_adjust_cfa_offset(-4) + cfi_restore(7) + popl %esi + cfi_adjust_cfa_offset(-4) + cfi_restore(6) + ret + + cfi_adjust_cfa_offset(24) + cfi_offset(6, -8) /* %esi */ + cfi_offset(7, -12) /* %edi */ + cfi_offset(3, -16) /* %ebx */ +3: negl %esi +6: +#ifdef PIC + call __i686.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl %esi, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl %esi, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl %esi, (%eax) +#endif + + addl $12, %esp + cfi_adjust_cfa_offset(-12) + orl $-1, %eax + popl %ebx + cfi_adjust_cfa_offset(-4) + cfi_restore(3) + popl %edi + cfi_adjust_cfa_offset(-4) + cfi_restore(7) + popl %esi + cfi_adjust_cfa_offset(-4) + cfi_restore(6) + ret + +10: /* Canceled. */ + movl $0xffffffff, %gs:RESULT + LOCK + orl $0x10, %gs:CANCELHANDLING + movl %gs:CLEANUP_JMP_BUF, %eax + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S new file mode 100644 index 000000000..1fd5186ad --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S @@ -0,0 +1,85 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + .text + + .globl __new_sem_trywait + .type __new_sem_trywait,@function + .align 16 +__new_sem_trywait: + movl 4(%esp), %ecx + + movl (%ecx), %eax +2: testl %eax, %eax + jz 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ecx) + jne,pn 2b + xorl %eax, %eax + ret + +1: +#ifdef PIC + call __i686.get_pc_thunk.cx +#else + movl $3f, %ecx +3: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ecx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ecx), %edx + addl %gs:0, %edx + movl $EAGAIN, (%edx) +# else + movl errno@gotntpoff(%ecx), %edx + movl $EAGAIN, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl $EAGAIN, (%eax) +#endif + orl $-1, %eax + ret + .size __new_sem_trywait,.-__new_sem_trywait +weak_alias(__new_sem_trywait, sem_trywait) + + +#ifdef PIC + .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits + .globl __i686.get_pc_thunk.cx + .hidden __i686.get_pc_thunk.cx + .type __i686.get_pc_thunk.cx,@function +__i686.get_pc_thunk.cx: + movl (%esp), %ecx; + ret + .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S new file mode 100644 index 000000000..baae42965 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S @@ -0,0 +1,134 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE 1 + + + .text + + .globl __new_sem_wait + .type __new_sem_wait,@function + .align 16 + cfi_startproc +__new_sem_wait: + /* First check for cancellation. */ + movl %gs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 5f + + pushl %ebx + cfi_adjust_cfa_offset(4) + pushl %esi + cfi_adjust_cfa_offset(4) + subl $4, %esp + cfi_adjust_cfa_offset(4) + + movl 16(%esp), %ebx + cfi_offset(3, -8) /* %ebx */ + + cfi_offset(6, -12) /* %esi */ +3: movl (%ebx), %eax +2: testl %eax, %eax + je,pn 1f + + leal -1(%eax), %edx + LOCK + cmpxchgl %edx, (%ebx) + jne,pn 2b + xorl %eax, %eax + + movl 4(%esp), %esi + cfi_restore(6) + movl 8(%esp), %ebx + cfi_restore(3) + addl $12, %esp + cfi_adjust_cfa_offset(-12) + ret + + cfi_adjust_cfa_offset(8) + cfi_offset(3, -8) /* %ebx */ + cfi_offset(6, -12) /* %esi */ +1: call __pthread_enable_asynccancel + movl %eax, (%esp) + + xorl %esi, %esi + movl $SYS_futex, %eax + movl %esi, %ecx + movl %esi, %edx + ENTER_KERNEL + movl %eax, %esi + + movl (%esp), %eax + call __pthread_disable_asynccancel + + testl %esi, %esi + je 3b + cmpl $-EWOULDBLOCK, %esi + je 3b + negl %esi +#ifdef PIC + call __i686.get_pc_thunk.bx +#else + movl $4f, %ebx +4: +#endif + addl $_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS + movl errno@gotntpoff(%ebx), %edx + addl %gs:0, %edx + movl %esi, (%edx) +# else + movl errno@gotntpoff(%ebx), %edx + movl %esi, %gs:(%edx) +# endif +#else + call __errno_location@plt + movl %esi, (%eax) +#endif + orl $-1, %eax + movl 4(%esp), %esi + cfi_restore(6) + movl 8(%esp), %ebx + cfi_restore(3) + addl $12, %esp + cfi_adjust_cfa_offset(-12) + ret + +5: /* Canceled. */ + movl $0xffffffff, %gs:RESULT + LOCK + orl $0x10, %gs:CANCELHANDLING + movl %gs:CLEANUP_JMP_BUF, %eax + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size __new_sem_wait,.-__new_sem_wait +weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S new file mode 100644 index 000000000..c0131555b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S new file mode 100644 index 000000000..5515e4895 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S new file mode 100644 index 000000000..07d481f37 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S new file mode 100644 index 000000000..0894f0546 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h new file mode 100644 index 000000000..785f2acf2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -0,0 +1,363 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +#include <tls.h> + +#ifndef LOCK_INSTR +# define LOCK_INSTR "lock;" +#endif + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + + +#ifdef PIC +# define LLL_EBX_LOAD "xchgl %2, %%ebx\n" +# define LLL_EBX_REG "D" +#else +# define LLL_EBX_LOAD +# define LLL_EBX_REG "b" +#endif + +#define LLL_ENTER_KERNEL "int $0x80\n\t" + +/* Delay in spinlock loop. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + + +#define lll_futex_wait(futex, val) \ + ({ \ + int __ret; \ + register __typeof (val) _val __asm__ ("edx") = (val); \ + __asm__ __volatile (LLL_EBX_LOAD \ + LLL_ENTER_KERNEL \ + LLL_EBX_LOAD \ + : "=a" (__ret) \ + : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \ + "c" (FUTEX_WAIT), "d" (_val), \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + + +#define lll_futex_wake(futex, nr) \ + ({ \ + int __ret; \ + register __typeof (nr) _nr __asm__ ("edx") = (nr); \ + __asm__ __volatile (LLL_EBX_LOAD \ + LLL_ENTER_KERNEL \ + LLL_EBX_LOAD \ + : "=a" (__ret) \ + : "0" (SYS_futex), LLL_EBX_REG (futex), \ + "c" (FUTEX_WAKE), "d" (_nr), \ + "i" (0) /* phony, to align next arg's number */, \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + + +/* Does not preserve %eax and %ecx. */ +extern int __lll_mutex_lock_wait (int val, int *__futex) + __attribute ((regparm (2))) attribute_hidden; +/* Does not preserve %eax, %ecx, and %edx. */ +extern int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) + __attribute ((regparm (3))) attribute_hidden; +/* Preserves all registers but %eax. */ +extern int __lll_mutex_unlock_wake (int *__futex) + __attribute ((regparm (1))) attribute_hidden; + + +/* NB: in the lll_mutex_trylock macro we simply return the value in %eax + after the cmpxchg instruction. In case the operation succeded this + value is zero. In case the operation failed, the cmpxchg instruction + has loaded the current value of the memory work which is guaranteed + to be nonzero. */ +#define lll_mutex_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_cond_trylock(futex) \ + ({ int ret; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_lock_%=,@function\n" \ + "_L_mutex_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex) \ + : "memory"); }) + + +/* Special version of lll_mutex_lock which causes the unlock function to + always wakeup waiters. */ +#define lll_mutex_cond_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_cond_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_cond_lock_%=,@function\n" \ + "_L_mutex_cond_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (2), "m" (futex) \ + : "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int result, ignore1, ignore2; \ + __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \ + "jnz _L_mutex_timedlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_timedlock_%=,@function\n" \ + "_L_mutex_timedlock_%=:\n\t" \ + "leal %3, %%ecx\n\t" \ + "movl %7, %%edx\n\t" \ + "call __lll_mutex_timedlock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\ + ".previous\n" \ + "1:" \ + : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \ + "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex), "m" (timeout) \ + : "memory"); \ + result; }) + + +#define lll_mutex_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile (LOCK_INSTR "subl $1,%0\n\t" \ + "jne _L_mutex_unlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_unlock_%=,@function\n" \ + "_L_mutex_unlock_%=:\n\t" \ + "leal %0, %%eax\n\t" \ + "call __lll_mutex_unlock_wake\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=m" (futex), "=&a" (ignore) \ + : "m" (futex) \ + : "memory"); }) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +extern int __lll_lock_wait (int val, int *__futex) + __attribute ((regparm (2))) attribute_hidden; +extern int __lll_unlock_wake (int *__futex) + __attribute ((regparm (1))) attribute_hidden; +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + + +#if defined NOT_IN_libc +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself. They avoid + the lock prefix when the thread library is not used. */ + + + +# define lll_trylock(futex) \ + ({ unsigned char ret; \ + __asm__ __volatile ("cmpl $0, %%gs:%P5\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgl %2, %1; setne %0" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); \ + ret; }) + + +# define lll_lock(futex) \ + (void) ({ int ignore1, ignore2; \ + __asm__ __volatile ("cmpl $0, %%gs:%P6\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgl %1, %2\n\t" \ + "jnz _L_mutex_lock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_lock_%=,@function\n" \ + "_L_mutex_lock_%=:\n\t" \ + "leal %2, %%ecx\n\t" \ + "call __lll_mutex_lock_wait\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ + : "0" (0), "1" (1), "m" (futex), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); }) + + +# define lll_unlock(futex) \ + (void) ({ int ignore; \ + __asm__ __volatile ("cmpl $0, %%gs:%P3\n\t" \ + "je,pt 0f\n\t" \ + "lock\n" \ + "0:\tsubl $1,%0\n\t" \ + "jne _L_mutex_unlock_%=\n\t" \ + ".subsection 1\n\t" \ + ".type _L_mutex_unlock_%=,@function\n" \ + "_L_mutex_unlock_%=:\n\t" \ + "leal %0, %%eax\n\t" \ + "call __lll_mutex_unlock_wake\n\t" \ + "jmp 1f\n\t" \ + ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ + ".previous\n" \ + "1:" \ + : "=m" (futex), "=&a" (ignore) \ + : "m" (futex), \ + "i" (offsetof (tcbhead_t, multiple_threads)) \ + : "memory"); }) +#endif + + +#define lll_islocked(futex) \ + (futex != LLL_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. + + The macro parameter must not have any side effect. */ +#define lll_wait_tid(tid) \ + ({ \ + int __ret; \ + register __typeof (tid) _tid __asm__ ("edx") = (tid); \ + if (_tid != 0) \ + __asm__ __volatile (LLL_EBX_LOAD \ + "1:\tmovl %1, %%eax\n\t" \ + LLL_ENTER_KERNEL \ + "cmpl $0, (%%ebx)\n\t" \ + "jne,pn 1b\n\t" \ + LLL_EBX_LOAD \ + : "=&a" (__ret) \ + : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \ + "c" (FUTEX_WAIT), "d" (_tid), \ + "i" (offsetof (tcbhead_t, sysinfo))); \ + __ret; }) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + __attribute__ ((regparm (2))) attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + __attribute ((regparm (2))) attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + __attribute ((regparm (1))) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h new file mode 100644 index 000000000..5bdba3f51 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces. Linux/NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) open (name, __VA_ARGS__) +#define __close_nocancel(fd) close (fd) +#define __read_nocancel(fd, buf, len) read (fd, buf, len) +#define __write_nocancel(fd, buf, len) write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ + waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ + __open_nocancel (name, flags) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + __close_nocancel (fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + __read_nocancel (fd, buf, n) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + __write_nocancel (fd, buf, n) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c new file mode 100644 index 000000000..620640ad6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/i386/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S new file mode 100644 index 000000000..939538927 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S @@ -0,0 +1,36 @@ +/* Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Schwab <schwab@gnu.org>. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + movl %gs:PID, %edx; \ + movl %edx, %eax; \ + negl %eax; \ + movl %eax, %gs:PID + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + testl %eax, %eax; \ + je 1f; \ + movl %edx, %gs:PID; \ +1: + +#include <../../../../../../../libc/sysdeps/linux/i386/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S new file mode 100644 index 000000000..97b4afbf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S @@ -0,0 +1,181 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unwindbuf.h> +#include <sysdep.h> + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + + + .globl __pthread_once + .type __pthread_once,@function + .align 16 + cfi_startproc +__pthread_once: + movl 4(%esp), %ecx + testl $2, (%ecx) + jz 1f + xorl %eax, %eax + ret + +1: pushl %ebx + cfi_adjust_cfa_offset (4) + cfi_rel_offset (3, 0) + pushl %esi + cfi_adjust_cfa_offset (4) + cfi_rel_offset (6, 0) + movl %ecx, %ebx + xorl %esi, %esi + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: movl (%ebx), %eax +#ifdef PIC + call __i686.get_pc_thunk.cx + addl $_GLOBAL_OFFSET_TABLE_, %ecx +#endif + +5: movl %eax, %edx + + testl $2, %eax + jnz 4f + + andl $3, %edx +#ifdef PIC + orl __fork_generation@GOTOFF(%ecx), %edx +#else + orl __fork_generation, %edx +#endif + orl $1, %edx + + LOCK + cmpxchgl %edx, (%ebx) + jnz 5b + + /* Check whether another thread already runs the initializer. */ + testl $1, %eax + jz 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xorl %edx, %eax + testl $0xfffffffc, %eax + jnz 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl $SYS_futex, %eax + ENTER_KERNEL + jmp 6b + +3: /* Call the initializer function after setting up the + cancellation handler. Note that it is not possible here + to use the unwind-based cleanup handling. This would require + that the user-provided function and all the code it calls + is compiled with exceptions. Unfortunately this cannot be + guaranteed. */ + subl $UNWINDBUFSIZE+8, %esp + cfi_adjust_cfa_offset (UNWINDBUFSIZE+8) + movl %ecx, %ebx /* PIC register value. */ + + leal 8+UWJMPBUF(%esp), %eax + movl $0, 4(%esp) + movl %eax, (%esp) + call __sigsetjmp@PLT + testl %eax, %eax + jne 7f + + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET(__pthread_register_cancel) + + /* Call the user-provided initialization function. */ + call *24+UNWINDBUFSIZE(%esp) + + /* Pop the cleanup handler. */ + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET(__pthread_unregister_cancel) + addl $UNWINDBUFSIZE+8, %esp + cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8) + + /* Sucessful run of the initializer. Signal that we are done. */ + movl 12(%esp), %ebx + LOCK + addl $1, (%ebx) + + /* Wake up all other threads. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + +4: popl %esi + cfi_adjust_cfa_offset (-4) + cfi_restore (6) + popl %ebx + cfi_adjust_cfa_offset (-4) + cfi_restore (3) + xorl %eax, %eax + ret + +7: /* __sigsetjmp returned for the second time. */ + movl 20+UNWINDBUFSIZE(%esp), %ebx + cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) + cfi_offset (3, -8) + cfi_offset (6, -12) + movl $0, (%ebx) + + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %ecx + movl $SYS_futex, %eax + ENTER_KERNEL + + leal 8(%esp), %eax + call HIDDEN_JUMPTARGET (__pthread_unwind_next) + /* NOTREACHED */ + hlt + cfi_endproc + .size __pthread_once,.-__pthread_once + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + +#ifdef PIC + .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits + .globl __i686.get_pc_thunk.cx + .hidden __i686.get_pc_thunk.cx + .type __i686.get_pc_thunk.cx,@function +__i686.get_pc_thunk.cx: + movl (%esp), %ecx; + ret + .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c new file mode 100644 index 000000000..d36e5373d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..8bae0fd31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h new file mode 100644 index 000000000..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h @@ -0,0 +1,24 @@ +/* Determine whether the host has multiple processors. SH version. + Copyright (C) 2002 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +static inline int +is_smp_system (void) +{ + return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h new file mode 100644 index 000000000..f32c5bd20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h @@ -0,0 +1,139 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \ + jne L(pseudo_cancel); \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + L(pseudo_cancel): \ + CENABLE \ + SAVE_OLDTYPE_##args \ + PUSHCARGS_##args \ + DOCARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + ENTER_KERNEL; \ + POPCARGS_##args; \ + POPSTATE_##args \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +# define SAVE_OLDTYPE_0 movl %eax, %ecx; +# define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0 +# define SAVE_OLDTYPE_2 pushl %eax; cfi_adjust_cfa_offset (4); +# define SAVE_OLDTYPE_3 SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_4 SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_5 SAVE_OLDTYPE_2 + +# define PUSHCARGS_0 /* No arguments to push. */ +# define DOCARGS_0 /* No arguments to frob. */ +# define POPCARGS_0 /* No arguments to pop. */ +# define _PUSHCARGS_0 /* No arguments to push. */ +# define _POPCARGS_0 /* No arguments to pop. */ + +# define PUSHCARGS_1 movl %ebx, %edx; cfi_register (ebx, edx); PUSHCARGS_0 +# define DOCARGS_1 _DOARGS_1 (4) +# define POPCARGS_1 POPCARGS_0; movl %edx, %ebx; cfi_restore (ebx); +# define _PUSHCARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); _PUSHCARGS_0 +# define _POPCARGS_1 _POPCARGS_0; popl %ebx; \ + cfi_adjust_cfa_offset (-4); cfi_restore (ebx); + +# define PUSHCARGS_2 PUSHCARGS_1 +# define DOCARGS_2 _DOARGS_2 (12) +# define POPCARGS_2 POPCARGS_1 +# define _PUSHCARGS_2 _PUSHCARGS_1 +# define _POPCARGS_2 _POPCARGS_1 + +# define PUSHCARGS_3 _PUSHCARGS_2 +# define DOCARGS_3 _DOARGS_3 (20) +# define POPCARGS_3 _POPCARGS_3 +# define _PUSHCARGS_3 _PUSHCARGS_2 +# define _POPCARGS_3 _POPCARGS_2 + +# define PUSHCARGS_4 _PUSHCARGS_4 +# define DOCARGS_4 _DOARGS_4 (28) +# define POPCARGS_4 _POPCARGS_4 +# define _PUSHCARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (esi, 0); _PUSHCARGS_3 +# define _POPCARGS_4 _POPCARGS_3; popl %esi; \ + cfi_adjust_cfa_offset (-4); cfi_restore (esi); + +# define PUSHCARGS_5 _PUSHCARGS_5 +# define DOCARGS_5 _DOARGS_5 (36) +# define POPCARGS_5 _POPCARGS_5 +# define _PUSHCARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (edi, 0); _PUSHCARGS_4 +# define _POPCARGS_5 _POPCARGS_4; popl %edi; \ + cfi_adjust_cfa_offset (-4); cfi_restore (edi); + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel; +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel; +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel; +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif +# define POPSTATE_0 \ + pushl %eax; cfi_adjust_cfa_offset (4); movl %ecx, %eax; \ + CDISABLE; popl %eax; cfi_adjust_cfa_offset (-4); +# define POPSTATE_1 POPSTATE_0 +# define POPSTATE_2 xchgl (%esp), %eax; CDISABLE; popl %eax; \ + cfi_adjust_cfa_offset (-4); +# define POPSTATE_3 POPSTATE_2 +# define POPSTATE_4 POPSTATE_3 +# define POPSTATE_5 POPSTATE_4 + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h new file mode 100644 index 000000000..f9343cc93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h @@ -0,0 +1,336 @@ +/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_I386_SYSDEP_H +#define _LINUX_I386_SYSDEP_H 1 + +#include <sys/syscall.h> +#include <sysdeps/i386/sysdep.h> + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SYS_ify(syscall_name) __NR_##syscall_name + +#if defined USE_DL_SYSINFO \ + && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define I386_USE_SYSENTER 1 +#else +# undef I386_USE_SYSENTER +#endif + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in %eax + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can savely + test with -4095. */ + +/* We don't want the label for the error handle to be global when we define + it here. */ +#ifdef PIC +# define SYSCALL_ERROR_LABEL 0f +#else +# define SYSCALL_ERROR_LABEL syscall_error +#endif + +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + cmpl $-4095, %eax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args) + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +#define ret_NOERRNO ret + +/* The function has to return the error code. */ +#undef PSEUDO_ERRVAL +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (syscall_name, args); \ + negl %eax + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL ret + +#ifndef PIC +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +#else + +# ifdef RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG(cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + movl %edx, rtld_errno@GOTOFF(%ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); + +# elif defined _LIBC_REENTRANT + +# if USE___THREAD +# ifndef NOT_IN_libc +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG (cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +# ifndef NO_TLS_DIRECT_SEG_REFS +# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ + movl src, %gs:(destoff) +# else +# define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff) \ + addl %gs:0, destoff; \ + movl src, (destoff) +# endif +# else +# define SYSCALL_ERROR_HANDLER \ +0:pushl %ebx; \ + cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); \ + SETUP_PIC_REG (bx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ebx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + pushl %edx; \ + cfi_adjust_cfa_offset (4); \ + call __errno_location@PLT; \ + popl %ecx; \ + cfi_adjust_cfa_offset (-4); \ + popl %ebx; \ + cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebx); \ + movl %ecx, (%eax); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +/* A quick note: it is assumed that the call to `__errno_location' does + not modify the stack! */ +# endif +# else +/* Store (- %eax) into errno through the GOT. */ +# define SYSCALL_ERROR_HANDLER \ +0:SETUP_PIC_REG(cx); \ + addl $_GLOBAL_OFFSET_TABLE_, %ecx; \ + xorl %edx, %edx; \ + subl %eax, %edx; \ + movl errno@GOT(%ecx), %ecx; \ + movl %edx, (%ecx); \ + orl $-1, %eax; \ + jmp L(pseudo_end); +# endif /* _LIBC_REENTRANT */ +#endif /* PIC */ + + +/* The original calling convention for system calls on Linux/i386 is + to use int $0x80. */ +#ifdef I386_USE_SYSENTER +# ifdef SHARED +# define ENTER_KERNEL call *%gs:SYSINFO_OFFSET +# else +# define ENTER_KERNEL call *_dl_sysinfo +# endif +#else +# define ENTER_KERNEL int $0x80 +#endif + +/* Linux takes system call arguments in registers: + + syscall number %eax call-clobbered + arg 1 %ebx call-saved + arg 2 %ecx call-clobbered + arg 3 %edx call-clobbered + arg 4 %esi call-saved + arg 5 %edi call-saved + arg 6 %ebp call-saved + + The stack layout upon entering the function is: + + 24(%esp) Arg# 6 + 20(%esp) Arg# 5 + 16(%esp) Arg# 4 + 12(%esp) Arg# 3 + 8(%esp) Arg# 2 + 4(%esp) Arg# 1 + (%esp) Return address + + (Of course a function with say 3 arguments does not have entries for + arguments 4, 5, and 6.) + + The following code tries hard to be optimal. A general assumption + (which is true according to the data books I have) is that + + 2 * xchg is more expensive than pushl + movl + popl + + Beside this a neat trick is used. The calling conventions for Linux + tell that among the registers used for parameters %ecx and %edx need + not be saved. Beside this we may clobber this registers even when + they are not used for parameter passing. + + As a result one can see below that we save the content of the %ebx + register in the %edx register when we have less than 3 arguments + (2 * movl is less expensive than pushl + popl). + + Second unlike for the other registers we don't save the content of + %ecx and %edx when we have more than 1 and 2 registers resp. + + The code below might look a bit long but we have to take care for + the pipelined processors (i586). Here the `pushl' and `popl' + instructions are marked as NP (not pairable) but the exception is + two consecutive of these instruction. This gives no penalty on + other processors though. */ + +#undef DO_CALL +#define DO_CALL(syscall_name, args) \ + PUSHARGS_##args \ + DOARGS_##args \ + movl $SYS_ify (syscall_name), %eax; \ + ENTER_KERNEL \ + POPARGS_##args + +#define PUSHARGS_0 /* No arguments to push. */ +#define DOARGS_0 /* No arguments to frob. */ +#define POPARGS_0 /* No arguments to pop. */ +#define _PUSHARGS_0 /* No arguments to push. */ +#define _DOARGS_0(n) /* No arguments to frob. */ +#define _POPARGS_0 /* No arguments to pop. */ + +#define PUSHARGS_1 movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0 +#define DOARGS_1 _DOARGS_1 (4) +#define POPARGS_1 POPARGS_0; movl %edx, %ebx; L(RESTBX1): +#define _PUSHARGS_1 pushl %ebx; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0 +#define _DOARGS_1(n) movl n(%esp), %ebx; _DOARGS_0(n-4) +#define _POPARGS_1 _POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebx); L(POPBX1): + +#define PUSHARGS_2 PUSHARGS_1 +#define DOARGS_2 _DOARGS_2 (8) +#define POPARGS_2 POPARGS_1 +#define _PUSHARGS_2 _PUSHARGS_1 +#define _DOARGS_2(n) movl n(%esp), %ecx; _DOARGS_1 (n-4) +#define _POPARGS_2 _POPARGS_1 + +#define PUSHARGS_3 _PUSHARGS_2 +#define DOARGS_3 _DOARGS_3 (16) +#define POPARGS_3 _POPARGS_3 +#define _PUSHARGS_3 _PUSHARGS_2 +#define _DOARGS_3(n) movl n(%esp), %edx; _DOARGS_2 (n-4) +#define _POPARGS_3 _POPARGS_2 + +#define PUSHARGS_4 _PUSHARGS_4 +#define DOARGS_4 _DOARGS_4 (24) +#define POPARGS_4 _POPARGS_4 +#define _PUSHARGS_4 pushl %esi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3 +#define _DOARGS_4(n) movl n(%esp), %esi; _DOARGS_3 (n-4) +#define _POPARGS_4 _POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \ + cfi_restore (esi); L(POPSI1): + +#define PUSHARGS_5 _PUSHARGS_5 +#define DOARGS_5 _DOARGS_5 (32) +#define POPARGS_5 _POPARGS_5 +#define _PUSHARGS_5 pushl %edi; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4 +#define _DOARGS_5(n) movl n(%esp), %edi; _DOARGS_4 (n-4) +#define _POPARGS_5 _POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \ + cfi_restore (edi); L(POPDI1): + +#define PUSHARGS_6 _PUSHARGS_6 +#define DOARGS_6 _DOARGS_6 (40) +#define POPARGS_6 _POPARGS_6 +#define _PUSHARGS_6 pushl %ebp; cfi_adjust_cfa_offset (4); \ + cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5 +#define _DOARGS_6(n) movl n(%esp), %ebp; _DOARGS_5 (n-4) +#define _POPARGS_6 _POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \ + cfi_restore (ebp); L(POPBP1): + +#endif /* __ASSEMBLER__ */ + + +/* Pointer mangling support. */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp + earlier than the descriptor is initialized. Using a global variable + is too complicated here since we have no PC-relative addressing mode. */ +#else +# ifdef __ASSEMBLER__ +# define PTR_MANGLE(reg) xorl %gs:POINTER_GUARD, reg; \ + roll $9, reg +# define PTR_DEMANGLE(reg) rorl $9, reg; \ + xorl %gs:POINTER_GUARD, reg +# else +# define PTR_MANGLE(var) asm ("xorl %%gs:%c2, %0\n" \ + "roll $9, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# define PTR_DEMANGLE(var) asm ("rorl $9, %0\n" \ + "xorl %%gs:%c2, %0" \ + : "=r" (var) \ + : "0" (var), \ + "i" (offsetof (tcbhead_t, \ + pointer_guard))) +# endif +#endif + +#endif /* linux/i386/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S new file mode 100644 index 000000000..dc7fb2ec4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 1999, 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +/* Save the PID value. */ +#define SAVE_PID \ + movl %gs:PID, %edx; \ + movl %edx, %eax; \ + negl %eax; \ + jne 1f; \ + movl $0x80000000, %eax; \ +1: movl %eax, %gs:PID + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + testl %eax, %eax; \ + je 1f; \ + movl %edx, %gs:PID; \ +1: + + +#include <libc/sysdeps/linux/i386/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h new file mode 100644 index 000000000..07ee9d7dd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h @@ -0,0 +1,153 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _INTERNALTYPES_H +#define _INTERNALTYPES_H 1 + +#include <stdint.h> +#include <sched.h> + + +struct pthread_attr +{ + /* Scheduler parameters and priority. */ + struct sched_param schedparam; + int schedpolicy; + /* Various flags like detachstate, scope, etc. */ + int flags; + /* Size of guard area. */ + size_t guardsize; + /* Stack handling. */ + void *stackaddr; + size_t stacksize; + /* Affinity map. */ + cpu_set_t *cpuset; + size_t cpusetsize; +}; + +#define ATTR_FLAG_DETACHSTATE 0x0001 +#define ATTR_FLAG_NOTINHERITSCHED 0x0002 +#define ATTR_FLAG_SCOPEPROCESS 0x0004 +#define ATTR_FLAG_STACKADDR 0x0008 +#define ATTR_FLAG_OLDATTR 0x0010 +#define ATTR_FLAG_SCHED_SET 0x0020 +#define ATTR_FLAG_POLICY_SET 0x0040 + + +/* Mutex attribute data structure. */ +struct pthread_mutexattr +{ + /* Identifier for the kind of mutex. + + Bit 31 is set if the mutex is to be shared between processes. + + Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify + the type of the mutex. */ + int mutexkind; +}; + + +/* Conditional variable attribute data structure. */ +struct pthread_condattr +{ + /* Combination of values: + + Bit 0 : flag whether coditional variable will be shareable between + processes. + + Bit 1-7: clock ID. */ + int value; +}; + + +/* The __NWAITERS field is used as a counter and to house the number + of bits which represent the clock. COND_CLOCK_BITS is the number + of bits reserved for the clock. */ +#define COND_CLOCK_BITS 1 + + +/* Read-write lock variable attribute data structure. */ +struct pthread_rwlockattr +{ + int lockkind; + int pshared; +}; + + +/* Barrier data structure. */ +struct pthread_barrier +{ + unsigned int curr_event; + int lock; + unsigned int left; + unsigned int init_count; +}; + + +/* Barrier variable attribute data structure. */ +struct pthread_barrierattr +{ + int pshared; +}; + + +/* Thread-local data handling. */ +struct pthread_key_struct +{ + /* Sequence numbers. Even numbers indicated vacant entries. Note + that zero is even. We use uintptr_t to not require padding on + 32- and 64-bit machines. On 64-bit machines it helps to avoid + wrapping, too. */ + uintptr_t seq; + + /* Destructor for the data. */ + void (*destr) (void *); +}; + +/* Check whether an entry is unused. */ +#define KEY_UNUSED(p) (((p) & 1) == 0) +/* Check whether a key is usable. We cannot reuse an allocated key if + the sequence counter would overflow after the next destroy call. + This would mean that we potentially free memory for a key with the + same sequence. This is *very* unlikely to happen, A program would + have to create and destroy a key 2^31 times (on 32-bit platforms, + on 64-bit platforms that would be 2^63). If it should happen we + simply don't use this specific key anymore. */ +#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2))) + + +/* Handling of read-write lock data. */ +// XXX For now there is only one flag. Maybe more in future. +#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0) + + +/* Semaphore variable structure. */ +struct sem +{ + unsigned int count; +}; + + +/* Compatibility type for old conditional variable interfaces. */ +typedef struct +{ + pthread_cond_t *cond; +} pthread_cond_2_0_t; + +#endif /* internaltypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c new file mode 100644 index 000000000..c435eff30 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -0,0 +1,39 @@ +/* Clean up stack frames unwound by longjmp. Linux version. + Copyright (C) 1995, 1997, 2002, 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stddef.h> +#include <pthreadP.h> + +extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe); +#pragma weak __pthread_cleanup_upto + + +void +_longjmp_unwind (jmp_buf env, int val) +{ +#ifdef SHARED +# define fptr __libc_pthread_functions.ptr___pthread_cleanup_upto +#else +# define fptr __pthread_cleanup_upto +#endif + + if (fptr != NULL) + fptr (env->__jmpbuf, CURRENT_STACK_FRAME); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h new file mode 100644 index 000000000..9be630268 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h @@ -0,0 +1 @@ +#include <../../../../../../librt/kernel-posix-timers.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* No difference to lowlevellock.c, except we lose a couple of functions. */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c new file mode 100644 index 000000000..a96f17490 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> + +#ifndef NOT_IN_libc +# ifndef TLS_MULTIPLE_THREADS_IN_TCB +int __libc_multiple_threads attribute_hidden; +# endif +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c new file mode 100644 index 000000000..5d3bcb0d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <list.h> +#include "fork.h" +#include <tls.h> +#include <string.h> +#include <pthreadP.h> +#include <bits/libc-lock.h> + +libc_hidden_proto(memcpy) + +#ifdef TLS_MULTIPLE_THREADS_IN_TCB +void +#else +extern int __libc_multiple_threads attribute_hidden; + +int * +#endif +__libc_pthread_init (ptr, reclaim, functions) + unsigned long int *ptr; + void (*reclaim) (void); + const struct pthread_functions *functions; +{ + /* Remember the pointer to the generation counter in libpthread. */ + __fork_generation_pointer = ptr; + + /* Called by a child after fork. */ + __register_atfork (NULL, NULL, reclaim, NULL); + +#ifdef SHARED + /* We copy the content of the variable pointed to by the FUNCTIONS + parameter to one in libc.so since this means access to the array + can be done with one memory access instead of two. */ + memcpy (&__libc_pthread_functions, functions, + sizeof (__libc_pthread_functions)); +#endif + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB + return &__libc_multiple_threads; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym new file mode 100644 index 000000000..36e28eb2a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym @@ -0,0 +1,11 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include "internaltypes.h" + +-- + +CURR_EVENT offsetof (struct pthread_barrier, curr_event) +MUTEX offsetof (struct pthread_barrier, lock) +LEFT offsetof (struct pthread_barrier, left) +INIT_COUNT offsetof (struct pthread_barrier, init_count) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym new file mode 100644 index 000000000..c5e797806 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include <internaltypes.h> + +-- + +cond_lock offsetof (pthread_cond_t, __data.__lock) +cond_futex offsetof (pthread_cond_t, __data.__futex) +cond_nwaiters offsetof (pthread_cond_t, __data.__nwaiters) +total_seq offsetof (pthread_cond_t, __data.__total_seq) +wakeup_seq offsetof (pthread_cond_t, __data.__wakeup_seq) +woken_seq offsetof (pthread_cond_t, __data.__woken_seq) +dep_mutex offsetof (pthread_cond_t, __data.__mutex) +broadcast_seq offsetof (pthread_cond_t, __data.__broadcast_seq) +clock_bits COND_CLOCK_BITS diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c new file mode 100644 index 000000000..f93891431 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -0,0 +1,131 @@ +/* low level locking for pthread library. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + + +void +__lll_lock_wait (int *futex) +{ + do + { + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + do + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait. */ + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + + return 0; +} + + +/* These don't get included in libc.so */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym new file mode 100644 index 000000000..e82c878d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym @@ -0,0 +1,14 @@ +#include <stddef.h> +#include <stdio.h> +#include <bits/pthreadtypes.h> + +-- + +MUTEX offsetof (pthread_rwlock_t, __data.__lock) +NR_READERS offsetof (pthread_rwlock_t, __data.__nr_readers) +READERS_WAKEUP offsetof (pthread_rwlock_t, __data.__readers_wakeup) +WRITERS_WAKEUP offsetof (pthread_rwlock_t, __data.__writer_wakeup) +READERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_readers_queued) +WRITERS_QUEUED offsetof (pthread_rwlock_t, __data.__nr_writers_queued) +FLAGS offsetof (pthread_rwlock_t, __data.__flags) +WRITER offsetof (pthread_rwlock_t, __data.__writer) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S new file mode 100644 index 000000000..70a920ba1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libc_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libc_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch new file mode 100644 index 000000000..a7de215e2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch @@ -0,0 +1,49 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c + +libc_a_CSRC = fork.c + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/mips +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/mips + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: + $(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h new file mode 100644 index 000000000..f112b8a39 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,215 @@ +/* Machine-specific pthread type layouts. MIPS version. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <sgidefs.h> + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + +#if _MIPS_SIM == _ABI64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if _MIPS_SIM == _ABI64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if _MIPS_SIM == _ABI64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if _MIPS_SIM == _ABI64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..c4440f9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 000000000..d8a7c5539 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 000000000..7edb28794 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,216 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ + return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ + if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) + attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ + int val = atomic_exchange_rel (futex, 0); + if (__builtin_expect (val > 1, 0)) + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ + (void) atomic_exchange_rel (futex, 0); + lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S new file mode 100644 index 000000000..add405523 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <../../../../../../../libc/sysdeps/linux/mips/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 000000000..c02ffca93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <features.h> +#include <tls.h> + +/* Save the PID value. */ +#define SAVE_PID \ + READ_THREAD_POINTER(v1); /* Get the thread pointer. */ \ + lw a2, PID_OFFSET(v1); /* Load the saved PID. */ \ + subu a2, $0, a2; /* Negate it. */ \ + sw a2, PID_OFFSET(v1); /* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + beqz v0, 1f; /* If we are the parent... */ \ + READ_THREAD_POINTER(v1); /* Get the thread pointer. */ \ + lw a2, PID_OFFSET(v1); /* Load the saved PID. */ \ + subu a2, $0, a2; /* Re-negate it. */ \ + sw a2, PID_OFFSET(v1); /* Restore the PID. */ \ +1: + +#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 000000000..649b752f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 000000000..5fee89235 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +#ifdef __PIC__ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + L(pseudo_start): \ + cfi_startproc; \ + 99: la t9,__syscall_error; \ + jr t9; \ + .type __##syscall_name##_nocancel, @function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + .set noreorder; \ + .cpload t9; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + ENTRY (name) \ + .set noreorder; \ + .cpload t9; \ + .set reorder; \ + SINGLE_THREAD_P(v1); \ + bne zero, v1, L(pseudo_cancel); \ + .set noreorder; \ + li v0, SYS_ify(syscall_name); \ + syscall; \ + .set reorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + ret; \ + L(pseudo_cancel): \ + SAVESTK_##args; \ + sw ra, 28(sp); \ + cfi_rel_offset (ra, 28); \ + sw gp, 32(sp); \ + cfi_rel_offset (gp, 32); \ + PUSHARGS_##args; /* save syscall args */ \ + CENABLE; \ + lw gp, 32(sp); \ + sw v0, 44(sp); /* save mask */ \ + POPARGS_##args; /* restore syscall args */ \ + .set noreorder; \ + li v0, SYS_ify (syscall_name); \ + syscall; \ + .set reorder; \ + sw v0, 36(sp); /* save syscall result */ \ + sw a3, 40(sp); /* save syscall error flag */ \ + lw a0, 44(sp); /* pass mask as arg1 */ \ + CDISABLE; \ + lw gp, 32(sp); \ + lw v0, 36(sp); /* restore syscall result */ \ + lw a3, 40(sp); /* restore syscall error flag */ \ + lw ra, 28(sp); /* restore return address */ \ + .set noreorder; \ + bne a3, zero, SYSCALL_ERROR_LABEL; \ + RESTORESTK; \ + L(pseudo_end): \ + .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +#endif + +# define PUSHARGS_0 /* nothing to do */ +# define PUSHARGS_1 PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2 PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3 PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4 PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5 PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6 PUSHARGS_5 +# define PUSHARGS_7 PUSHARGS_6 + +# define POPARGS_0 /* nothing to do */ +# define POPARGS_1 POPARGS_0 lw a0, 0(sp); +# define POPARGS_2 POPARGS_1 lw a1, 4(sp); +# define POPARGS_3 POPARGS_2 lw a2, 8(sp); +# define POPARGS_4 POPARGS_3 lw a3, 12(sp); +# define POPARGS_5 POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6 POPARGS_5 +# define POPARGS_7 POPARGS_6 + + +# define STKSPACE 48 +# define SAVESTK_0 subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1 SAVESTK_0 +# define SAVESTK_2 SAVESTK_1 +# define SAVESTK_3 SAVESTK_2 +# define SAVESTK_4 SAVESTK_3 +# define SAVESTK_5 lw t0, 16(sp); \ + SAVESTK_0; \ + sw t0, 16(sp) + +# define SAVESTK_6 lw t0, 16(sp); \ + lw t1, 20(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp) + +# define SAVESTK_7 lw t0, 16(sp); \ + lw t1, 20(sp); \ + lw t2, 24(sp); \ + SAVESTK_0; \ + sw t0, 16(sp); \ + sw t1, 20(sp); \ + sw t2, 24(sp) + +# define RESTORESTK addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +/* We use jalr rather than jal. This means that the assembler will not + automatically restore $gp (in case libc has multiple GOTs) so we must + do it manually - which we have to do anyway since we don't use .cprestore. + It also shuts up the assembler warning about not using .cprestore. */ +# ifdef IS_IN_libpthread +# define CENABLE la t9, __pthread_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __pthread_disable_asynccancel; jalr t9; +# elif defined IS_IN_librt +# define CENABLE la t9, __librt_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __librt_disable_asynccancel; jalr t9; +# else +# define CENABLE la t9, __libc_enable_asynccancel; jalr t9; +# define CDISABLE la t9, __libc_disable_asynccancel; jalr t9; +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) \ + == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + READ_THREAD_POINTER(reg); \ + lw reg, MULTIPLE_THREADS_OFFSET(reg) +#endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h new file mode 100644 index 000000000..bfaab1f3a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h @@ -0,0 +1,302 @@ +/* Copyright (C) 2000, 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_MIPS_MIPS32_SYSDEP_H +#define _LINUX_MIPS_MIPS32_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality. */ +#include <sysdeps/mips/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#ifdef __STDC__ +# define SYS_ify(syscall_name) __NR_##syscall_name +#else +# define SYS_ify(syscall_name) __NR_/**/syscall_name +#endif + +#ifdef __ASSEMBLER__ + +/* We don't want the label for the error handler to be visible in the symbol + table when we define it here. */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 99b +#endif + +#else /* ! __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system + call. */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ INTERNAL_SYSCALL_DECL(err); \ + long result_var = INTERNAL_SYSCALL (name, err, nr, args); \ + if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) ) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \ + result_var = -1L; \ + } \ + result_var; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long err + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) ((long) (err)) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (val) + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t", \ + "i" (SYS_ify (name)), err, args) + +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ + internal_syscall##nr (= number, , "r" (__v0), err, args) +#undef internal_syscall0 +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall1 +#define internal_syscall1(ncs_init, cs_init, input, err, arg1) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set reorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall2 +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2) \ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall3 +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7"); \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "=r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall4 +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({ \ + long _sys_result; \ + \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + cs_init \ + "syscall\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +/* We need to use a frame pointer for the functions in which we + adjust $sp around the syscall, or debug information and unwind + information will be $sp relative and thus wrong during the syscall. As + of GCC 3.4.3, this is sufficient. */ +#define FORCE_FRAME_POINTER alloca (4) + +#undef internal_syscall5 +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall6 +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5), "r" ((long)arg6) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef internal_syscall7 +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({ \ + long _sys_result; \ + \ + FORCE_FRAME_POINTER; \ + { \ + register long __v0 __asm__("$2") ncs_init; \ + register long __a0 __asm__("$4") = (long) arg1; \ + register long __a1 __asm__("$5") = (long) arg2; \ + register long __a2 __asm__("$6") = (long) arg3; \ + register long __a3 __asm__("$7") = (long) arg4; \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t%6, 16($29)\n\t" \ + "sw\t%7, 20($29)\n\t" \ + "sw\t%8, 24($29)\n\t" \ + cs_init \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=r" (__v0), "+r" (__a3) \ + : input, "r" (__a0), "r" (__a1), "r" (__a2), \ + "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7) \ + : __SYSCALL_CLOBBERS); \ + err = __a3; \ + _sys_result = __v0; \ + } \ + _sys_result; \ +}) + +#undef __SYSCALL_CLOBBERS +#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ + "$14", "$15", "$24", "$25", "memory" + +#endif /* __ASSEMBLER__ */ + +#endif /* sysdeps/unix/sysv/linux/mips/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 000000000..9d16fee56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contribute by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> +#include <sys/socket.h> +#include <not-cancel.h> + + +#ifdef __NR_mq_notify + +/* Defined in the kernel headers: */ +#define NOTIFY_COOKIE_LEN 32 /* Length of the cookie used. */ +#define NOTIFY_WOKENUP 1 /* Code for notifcation. */ +#define NOTIFY_REMOVED 2 /* Code for closed message queue + of de-notifcation. */ + + +/* Data structure for the queued notification requests. */ +union notify_data +{ + struct + { + void (*fct) (union sigval); /* The function to run. */ + union sigval param; /* The parameter to pass. */ + pthread_attr_t *attr; /* Attributes to create the thread with. */ + /* NB: on 64-bit machines the struct as a size of 24 bytes. Which means + byte 31 can still be used for returning the status. */ + }; + char raw[NOTIFY_COOKIE_LEN]; +}; + + +/* Keep track of the initialization. */ +static pthread_once_t once = PTHREAD_ONCE_INIT; + + +/* The netlink socket. */ +static int netlink_socket = -1; + + +/* Barrier used to make sure data passed to the new thread is not + resused by the parent. */ +static pthread_barrier_t notify_barrier; + + +/* Modify the signal mask. We move this into a separate function so + that the stack space needed for sigset_t is not deducted from what + the thread can use. */ +static int +__attribute__ ((noinline)) +change_sigmask (int how, sigset_t *oss) +{ + sigset_t ss; + sigfillset (&ss); + return pthread_sigmask (how, &ss, oss); +} + + +/* The function used for the notification. */ +static void * +notification_function (void *arg) +{ + /* Copy the function and parameter so that the parent thread can go + on with its life. */ + volatile union notify_data *data = (volatile union notify_data *) arg; + void (*fct) (union sigval) = data->fct; + union sigval param = data->param; + + /* Let the parent go. */ + (void) pthread_barrier_wait (¬ify_barrier); + + /* Make the thread detached. */ + (void) pthread_detach (pthread_self ()); + + /* The parent thread has all signals blocked. This is probably a + bit surprising for this thread. So we unblock all of them. */ + (void) change_sigmask (SIG_UNBLOCK, NULL); + + /* Now run the user code. */ + fct (param); + + /* And we are done. */ + return NULL; +} + + +/* Helper thread. */ +static void * +helper_thread (void *arg) +{ + while (1) + { + union notify_data data; + + ssize_t n = recv (netlink_socket, &data, sizeof (data), + MSG_NOSIGNAL | MSG_WAITALL); + if (n < NOTIFY_COOKIE_LEN) + continue; + + if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP) + { + /* Just create the thread as instructed. There is no way to + report a problem with creating a thread. */ + pthread_t th; + if (__builtin_expect (pthread_create (&th, data.attr, + notification_function, &data) + == 0, 0)) + /* Since we passed a pointer to DATA to the new thread we have + to wait until it is done with it. */ + (void) pthread_barrier_wait (¬ify_barrier); + } + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) + /* The only state we keep is the copy of the thread attributes. */ + free (data.attr); + } + return NULL; +} + + +static void +reset_once (void) +{ + once = PTHREAD_ONCE_INIT; +} + + +static void +init_mq_netlink (void) +{ + /* This code might be called a second time after fork(). The file + descriptor is inherited from the parent. */ + if (netlink_socket == -1) + { + /* Just a normal netlink socket, not bound. */ + netlink_socket = socket (AF_NETLINK, SOCK_RAW, 0); + /* No need to do more if we have no socket. */ + if (netlink_socket == -1) + return; + + /* Make sure the descriptor is closed on exec. */ + if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0) + goto errout; + } + + int err = 1; + + /* Initialize the barrier. */ + if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0, + 0)) + { + /* Create the helper thread. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + /* We do not need much stack space, the bare minimum will be enough. */ + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Temporarily block all signals so that the newly created + thread inherits the mask. */ + sigset_t oss; + int have_no_oss = change_sigmask (SIG_BLOCK, &oss); + + pthread_t th; + err = pthread_create (&th, &attr, helper_thread, NULL); + + /* Reset the signal mask. */ + if (!have_no_oss) + pthread_sigmask (SIG_SETMASK, &oss, NULL); + + (void) pthread_attr_destroy (&attr); + + if (err == 0) + { + static int added_atfork; + + if (added_atfork == 0 + && pthread_atfork (NULL, NULL, reset_once) != 0) + { + /* The child thread will call recv() which is a + cancellation point. */ + (void) pthread_cancel (th); + err = 1; + } + else + added_atfork = 1; + } + } + + if (err != 0) + { + errout: + close_not_cancel_no_status (netlink_socket); + netlink_socket = -1; + } +} + + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ + /* Make sure the type is correctly defined. */ + assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN); + + /* Special treatment needed for SIGEV_THREAD. */ + if (notification == NULL || notification->sigev_notify != SIGEV_THREAD) + return INLINE_SYSCALL (mq_notify, 2, mqdes, notification); + + /* The kernel cannot directly start threads. This will have to be + done at userlevel. Since we cannot start threads from signal + handlers we have to create a dedicated thread which waits for + notifications for arriving messages and creates threads in + response. */ + + /* Initialize only once. */ + pthread_once (&once, init_mq_netlink); + + /* If we cannot create the netlink socket we cannot provide + SIGEV_THREAD support. */ + if (__builtin_expect (netlink_socket == -1, 0)) + { + __set_errno (ENOSYS); + return -1; + } + + /* Create the cookie. It will hold almost all the state. */ + union notify_data data; + memset (&data, '\0', sizeof (data)); + data.fct = notification->sigev_notify_function; + data.param = notification->sigev_value; + + if (notification->sigev_notify_attributes != NULL) + { + /* The thread attribute has to be allocated separately. */ + data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t)); + if (data.attr == NULL) + return -1; + + memcpy (data.attr, notification->sigev_notify_attributes, + sizeof (pthread_attr_t)); + } + + /* Construct the new request. */ + struct sigevent se; + se.sigev_notify = SIGEV_THREAD; + se.sigev_signo = netlink_socket; + se.sigev_value.sival_ptr = &data; + + /* Tell the kernel. */ + int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); + + /* If it failed, free the allocated memory. */ + if (__builtin_expect (retval != 0, 0)) + free (data.attr); + + return retval; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S new file mode 100644 index 000000000..074a0d717 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libc_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libc_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S new file mode 100644 index 000000000..71efe32f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libc_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libc_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libc_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h new file mode 100644 index 000000000..9418417b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h @@ -0,0 +1,60 @@ +/* Uncancelable versions of cancelable interfaces. Linux version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode)) +#define open_not_cancel_2(name, flags) \ + INLINE_SYSCALL (open, 2, (const char *) (name), (flags)) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + INLINE_SYSCALL (close, 1, fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + INLINE_SYSCALL (read, 3, (fd), (buf), (n)) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + INLINE_SYSCALL (write, 3, (fd), (buf), (n)) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S new file mode 100644 index 000000000..486686a22 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END(__libc_open) + +libc_hidden_def (__open_nocancel) +libc_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libc_hidden_weak (__open) +weak_alias (__libc_open, open) +libc_hidden_weak (open) + + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S new file mode 100644 index 000000000..3841018a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libc_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libc_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile new file mode 100644 index 000000000..e98c9bd86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine +libpthread-routines += sysdep diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions new file mode 100644 index 000000000..997784798 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions @@ -0,0 +1,5 @@ +libpthread { + GLIBC_2.3.4 { + longjmp; siglongjmp; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h new file mode 100644 index 000000000..c94ed0c38 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h @@ -0,0 +1,216 @@ +/* Machine-specific pthread type layouts. PowerPC version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE == 64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h new file mode 100644 index 000000000..8123b418b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Machine-specific POSIX semaphore type layouts. PowerPC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c new file mode 100644 index 000000000..e811ad74e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h new file mode 100644 index 000000000..1f2f481d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h @@ -0,0 +1,241 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> + + +#ifndef __NR_futex +# define __NR_futex 221 +#endif +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAIT, (val), (timespec)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, \ + (futexp), FUTEX_WAKE, (nr), 0); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, \ + (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ + (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +#ifdef UP +# define __lll_acq_instr "" +# define __lll_rel_instr "" +#else +# define __lll_acq_instr "isync" +# define __lll_rel_instr "sync" +#endif + +/* Set *futex to 1 if it is 0, atomically. Returns the old value */ +#define __lll_trylock(futex) \ + ({ int __val; \ + __asm __volatile ("1: lwarx %0,0,%2\n" \ + " cmpwi 0,%0,0\n" \ + " bne 2f\n" \ + " stwcx. %3,0,%2\n" \ + " bne- 1b\n" \ + "2: " __lll_acq_instr \ + : "=&r" (__val), "=m" (*futex) \ + : "r" (futex), "r" (1), "m" (*futex) \ + : "cr0", "memory"); \ + __val; \ + }) + +#define lll_mutex_trylock(lock) __lll_trylock (&(lock)) + +/* Set *futex to 2 if it is 0, atomically. Returns the old value */ +#define __lll_cond_trylock(futex) \ + ({ int __val; \ + __asm __volatile ("1: lwarx %0,0,%2\n" \ + " cmpwi 0,%0,0\n" \ + " bne 2f\n" \ + " stwcx. %3,0,%2\n" \ + " bne- 1b\n" \ + "2: " __lll_acq_instr \ + : "=&r" (__val), "=m" (*futex) \ + : "r" (futex), "r" (2), "m" (*futex) \ + : "cr0", "memory"); \ + __val; \ + }) +#define lll_mutex_cond_trylock(lock) __lll_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +#define lll_mutex_lock(lock) \ + (void) ({ \ + int *__futex = &(lock); \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ + 0) != 0) \ + __lll_lock_wait (__futex); \ + }) + +#define lll_mutex_cond_lock(lock) \ + (void) ({ \ + int *__futex = &(lock); \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\ + 0) != 0) \ + __lll_lock_wait (__futex); \ + }) + +extern int __lll_timedlock_wait + (int *futex, const struct timespec *) attribute_hidden; + +#define lll_mutex_timedlock(lock, abstime) \ + ({ \ + int *__futex = &(lock); \ + int __val = 0; \ + if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ + 0) != 0) \ + __val = __lll_timedlock_wait (__futex, abstime); \ + __val; \ + }) + +#define lll_mutex_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_rel (__futex, 0); \ + if (__builtin_expect (__val > 1, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_unlock_force(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + *__futex = 0; \ + __asm __volatile (__lll_rel_instr ::: "memory"); \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) + attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) + attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) + attribute_hidden; + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S new file mode 100644 index 000000000..e19579e84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S new file mode 100644 index 000000000..61651fd97 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(2) + neg 0,0 + stw 0,PID(2) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(2) + neg 0,0 + stw 0,PID(2) + + PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h new file mode 100644 index 000000000..84acf3843 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h @@ -0,0 +1,132 @@ +/* Cancellable system call stubs. Linux/PowerPC version. + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + cfi_startproc; \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + .Lpseudo_cancel: \ + stwu 1,-48(1); \ + cfi_adjust_cfa_offset (48); \ + mflr 9; \ + stw 9,52(1); \ + cfi_offset (lr, 4); \ + CGOTSETUP; \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + stw 3,16(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + stw 3,8(1); \ + stw 0,12(1); \ + lwz 3,16(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + lwz 4,52(1); \ + lwz 0,12(1); /* restore CR/R3. */ \ + lwz 3,8(1); \ + CGOTRESTORE; \ + mtlr 4; \ + mtcr 0; \ + addi 1,1,48; \ + cfi_endproc; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 stw 3,20(1); DOCARGS_0 +# define UNDOCARGS_1 lwz 3,20(1); UNDOCARGS_0 + +# define DOCARGS_2 stw 4,24(1); DOCARGS_1 +# define UNDOCARGS_2 lwz 4,24(1); UNDOCARGS_1 + +# define DOCARGS_3 stw 5,28(1); DOCARGS_2 +# define UNDOCARGS_3 lwz 5,28(1); UNDOCARGS_2 + +# define DOCARGS_4 stw 6,32(1); DOCARGS_3 +# define UNDOCARGS_4 lwz 6,32(1); UNDOCARGS_3 + +# define DOCARGS_5 stw 7,36(1); DOCARGS_4 +# define UNDOCARGS_5 lwz 7,36(1); UNDOCARGS_4 + +# define DOCARGS_6 stw 8,40(1); DOCARGS_5 +# define UNDOCARGS_6 lwz 8,40(1); UNDOCARGS_5 + +# define CGOTSETUP +# define CGOTRESTORE + +# ifdef IS_IN_libpthread +# define CENABLE bl __pthread_enable_asynccancel@local +# define CDISABLE bl __pthread_disable_asynccancel@local +# elif !defined NOT_IN_libc +# define CENABLE bl __libc_enable_asynccancel@local +# define CDISABLE bl __libc_disable_asynccancel@local +# elif defined IS_IN_librt +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel) +# if defined HAVE_AS_REL16 && defined PIC +# undef CGOTSETUP +# define CGOTSETUP \ + bcl 20,31,1f; \ + 1: stw 30,44(1); \ + mflr 30; \ + addis 30,30,_GLOBAL_OFFSET_TABLE-1b@ha; \ + addi 30,30,_GLOBAL_OFFSET_TABLE-1b@l +# undef CGOTRESTORE +# define CGOTRESTORE \ + lwz 30,44(1) +# endif +# else +# error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(2); \ + cmpwi 10,0 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S new file mode 100644 index 000000000..b7e2cf6e7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S @@ -0,0 +1,57 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(2) + cmpwi 0,0,0 + neg 0,0 + bne- 0,1f + lis 0,0x8000 +1: stw 0,PID(2) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(2) + /* Cannot use clrlwi. here, because cr0 needs to be preserved + until PSEUDO_RET. */ + clrlwi 4,0,1 + cmpwi 1,4,0 + beq- 1,1f + neg 4,0 +1: stw 4,PID(2) + + PSEUDO_RET + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S new file mode 100644 index 000000000..f87adf473 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S new file mode 100644 index 000000000..e5b7b535c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(13) + neg 0,0 + stw 0,PID(13) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(13) + neg 0,0 + stw 0,PID(13) + + PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h new file mode 100644 index 000000000..226aaafdc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -0,0 +1,121 @@ +/* Cancellable system call stubs. Linux/PowerPC64 version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DASHDASHPFX(str) .__##str +# else +# define DASHDASHPFX(str) __##str +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + ENTRY (name) \ + cfi_startproc; \ + SINGLE_THREAD_P; \ + bne- .Lpseudo_cancel; \ + .type DASHDASHPFX(syscall_name##_nocancel),@function; \ + .globl DASHDASHPFX(syscall_name##_nocancel); \ + DASHDASHPFX(syscall_name##_nocancel): \ + DO_CALL (SYS_ify (syscall_name)); \ + PSEUDO_RET; \ + .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel); \ + .Lpseudo_cancel: \ + stdu 1,-128(1); \ + cfi_adjust_cfa_offset (128); \ + mflr 9; \ + std 9,128+16(1); \ + cfi_offset (lr, 16); \ + DOCARGS_##args; /* save syscall args around CENABLE. */ \ + CENABLE; \ + std 3,72(1); /* store CENABLE return value (MASK). */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL (SYS_ify (syscall_name)); \ + mfcr 0; /* save CR/R3 around CDISABLE. */ \ + std 3,64(1); \ + std 0,8(1); \ + ld 3,72(1); /* pass MASK to CDISABLE. */ \ + CDISABLE; \ + ld 9,128+16(1); \ + ld 0,8(1); /* restore CR/R3. */ \ + ld 3,64(1); \ + mtlr 9; \ + mtcr 0; \ + addi 1,1,128; \ + cfi_endproc; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 std 3,80(1); DOCARGS_0 +# define UNDOCARGS_1 ld 3,80(1); UNDOCARGS_0 + +# define DOCARGS_2 std 4,88(1); DOCARGS_1 +# define UNDOCARGS_2 ld 4,88(1); UNDOCARGS_1 + +# define DOCARGS_3 std 5,96(1); DOCARGS_2 +# define UNDOCARGS_3 ld 5,96(1); UNDOCARGS_2 + +# define DOCARGS_4 std 6,104(1); DOCARGS_3 +# define UNDOCARGS_4 ld 6,104(1); UNDOCARGS_3 + +# define DOCARGS_5 std 7,112(1); DOCARGS_4 +# define UNDOCARGS_5 ld 7,112(1); UNDOCARGS_4 + +# define DOCARGS_6 std 8,120(1); DOCARGS_5 +# define UNDOCARGS_6 ld 8,120(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE bl JUMPTARGET(__pthread_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__pthread_disable_asynccancel) +# elif !defined NOT_IN_libc +# define CENABLE bl JUMPTARGET(__libc_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__libc_disable_asynccancel) +# elif defined IS_IN_librt +# define CENABLE bl JUMPTARGET(__librt_enable_asynccancel) +# define CDISABLE bl JUMPTARGET(__librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + lwz 10,MULTIPLE_THREADS_OFFSET(13); \ + cmpwi 10,0 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S new file mode 100644 index 000000000..018132136 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + lwz 0,PID(13) + cmpwi 0,0,0 + neg 0,0 + bne- 0,1f + lis 0,0x8000 +1: stw 0,PID(13) + + DO_CALL (SYS_ify (vfork)) + + cmpwi 1,3,0 + beqlr- 1 + + lwz 0,PID(13) + clrlwi 4,0,1 + cmpwi 1,4,0 + beq- 1,1f + neg 4,0 +1: stw 4,PID(13) + + PSEUDO_RET + +PSEUDO_END (__vfork) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c new file mode 100644 index 000000000..b6d6b3d55 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <bits/wordsize.h> +#include "pthreadP.h" + +void +__vmx_longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} + +void +__vmx_siglongjmp (jmp_buf env, int val) +{ + __libc_siglongjmp (env, val); +} +weak_alias(__vmx_longjmp, longjmp) +weak_alias(__vmx_siglongjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c new file mode 100644 index 000000000..e1afff8a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + int tmp; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + newval = __fork_generation | 1; + __asm __volatile ("1: lwarx %0,0,%3\n" + " andi. %1,%0,2\n" + " bne 2f\n" + " stwcx. %4,0,%3\n" + " bne 1b\n" + "2: isync" + : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) + : "r" (once_control), "r" (newval), "m" (*once_control) + : "cr0"); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval); + } + + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control to take the bottom 2 bits from 01 to 10. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c new file mode 100644 index 000000000..06b3bd0ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c @@ -0,0 +1,42 @@ +/* sem_post -- post to a POSIX semaphore. Powerpc version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ + int *futex = (int *) sem; + + __asm __volatile (__lll_rel_instr ::: "memory"); + int nr = atomic_increment_val (futex); + int err = lll_futex_wake (futex, nr); + if (__builtin_expect (err, 0) < 0) + { + __set_errno (-err); + return -1; + } + return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S new file mode 100644 index 000000000..24062101d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libpthread_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libpthread_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libpthread_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S new file mode 100644 index 000000000..ab32ca598 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END (__libc_close) +libpthread_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libpthread_hidden_weak (__close) +weak_alias (__libc_close, close) +libpthread_hidden_weak (close) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S new file mode 100644 index 000000000..b5124f8ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libpthread_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libpthread_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libpthread_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c new file mode 100644 index 000000000..0a8fd3cc2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/__syscall_fcntl.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c new file mode 100644 index 000000000..3e1b70f86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +extern int __libc_fork (void); + +pid_t +__fork (void) +{ + return __libc_fork (); +} +strong_alias (__fork, fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c new file mode 100644 index 000000000..6ec4821c7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/fsync.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c new file mode 100644 index 000000000..1d0d57870 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c @@ -0,0 +1,3 @@ +#include <pthreadP.h> +#define libc_hidden libpthread_hidden +#include <../../../../../../libc/sysdeps/linux/common/llseek.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S new file mode 100644 index 000000000..4db71722a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libpthread_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libpthread_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c new file mode 100644 index 000000000..3bb9d53df --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c @@ -0,0 +1,2 @@ +#define L_msgrcv +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c new file mode 100644 index 000000000..1566f65f4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c @@ -0,0 +1,2 @@ +#define L_msgsnd +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S new file mode 100644 index 000000000..640270ad9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libpthread_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libpthread_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S new file mode 100644 index 000000000..08d8f0150 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libpthread_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libpthread_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libpthread_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S new file mode 100644 index 000000000..39ed92cc7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END (__libc_open) +libpthread_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libpthread_hidden_weak (__open) +weak_alias (__libc_open, open) +libpthread_hidden_weak (open) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c new file mode 100644 index 000000000..2029539a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/open64.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S new file mode 100644 index 000000000..c6cb57180 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libpthread_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libpthread_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c new file mode 100644 index 000000000..f32c0a670 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c @@ -0,0 +1 @@ +#include "pread_write.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c new file mode 100644 index 000000000..7bee29784 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> +#include <bits/kernel-features.h> + +extern __typeof(raise) __raise; +int __raise (int sig) +{ +#if __ASSUME_TGKILL || defined __NR_tgkill + /* raise is an async-safe function. It could be called while the + fork function temporarily invalidated the PID field. Adjust for + that. */ + pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (pid < 0, 0)) + pid = -pid; +#endif + +#if __ASSUME_TGKILL + return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); +#else +# ifdef __NR_tgkill + int res = INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); + if (res != -1 || errno != ENOSYS) + return res; +# endif + return INLINE_SYSCALL (tkill, 2, THREAD_GETMEM (THREAD_SELF, tid), sig); +#endif +} +libc_hidden_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(raise) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S new file mode 100644 index 000000000..623ba27a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END (__libc_read) +libpthread_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libpthread_hidden_weak (__read) +weak_alias (__libc_read, read) +libpthread_hidden_weak (read) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S new file mode 100644 index 000000000..6d2e3c2d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libpthread_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libpthread_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libpthread_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S new file mode 100644 index 000000000..96aeeaa3d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libpthread_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libpthread_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libpthread_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S new file mode 100644 index 000000000..f7161e47c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libpthread_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libpthread_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libpthread_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S new file mode 100644 index 000000000..76bed39ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libpthread_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libpthread_hidden_weak (__send) +weak_alias (__libc_send, send) +libpthread_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S new file mode 100644 index 000000000..d17096eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libpthread_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libpthread_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libpthread_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S new file mode 100644 index 000000000..d07a71f8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libpthread_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libpthread_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libpthread_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c new file mode 100644 index 000000000..07c1f8233 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c @@ -0,0 +1 @@ +#include <../../../../../../libc/termios/tcdrain.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c new file mode 100644 index 000000000..a05c3eb49 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/wait.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c new file mode 100644 index 000000000..8461c3ff2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/waitpid.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S new file mode 100644 index 000000000..6bc666779 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END (__libc_write) +libpthread_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libpthread_hidden_weak (__write) +weak_alias (__libc_write, write) +libpthread_hidden_weak (write) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c new file mode 100644 index 000000000..5a3d418a9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/types.h> + + +int +__pthread_attr_getaffinity_new (const pthread_attr_t *attr, size_t cpusetsize, + cpu_set_t *cpuset) +{ + const struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (const struct pthread_attr *) attr; + + if (iattr->cpuset != NULL) + { + /* Check whether there are any bits set beyond the limits + the user requested. */ + size_t cnt; + for (cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt) + if (((char *) iattr->cpuset)[cnt] != 0) + return EINVAL; + + void *p = mempcpy (cpuset, iattr->cpuset, iattr->cpusetsize); + if (cpusetsize > iattr->cpusetsize) + memset (p, '\0', cpusetsize - iattr->cpusetsize); + } + else + /* We have no information. */ + memset (cpuset, -1, cpusetsize); + + return 0; +} +weak_alias(__pthread_attr_getaffinity_new, pthread_attr_getaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c new file mode 100644 index 000000000..e3414999c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <pthreadP.h> + + +/* Defined in pthread_setaffinity.c. */ +extern size_t __kernel_cpumask_size; +extern int __determine_cpumask_size (pid_t tid); + + +int +__pthread_attr_setaffinity_new (pthread_attr_t *attr, size_t cpusetsize, + const cpu_set_t *cpuset) +{ + struct pthread_attr *iattr; + + assert (sizeof (*attr) >= sizeof (struct pthread_attr)); + iattr = (struct pthread_attr *) attr; + + if (cpuset == NULL || cpusetsize == 0) + { + free (iattr->cpuset); + iattr->cpuset = NULL; + iattr->cpusetsize = 0; + } + else + { + if (__kernel_cpumask_size == 0) + { + int res = __determine_cpumask_size (THREAD_SELF->tid); + if (res != 0) + /* Some serious problem. */ + return res; + } + + /* Check whether the new bitmask has any bit set beyond the + last one the kernel accepts. */ + size_t cnt; + for (cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) + if (((char *) cpuset)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + if (iattr->cpusetsize != cpusetsize) + { + void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize); + if (newp == NULL) + return ENOMEM; + + iattr->cpuset = newp; + iattr->cpusetsize = cpusetsize; + } + + memcpy (iattr->cpuset, cpuset, cpusetsize); + } + + return 0; +} +weak_alias(__pthread_attr_setaffinity_new, pthread_attr_setaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c new file mode 100644 index 000000000..3ca9d7d94 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/param.h> +#include <sys/types.h> + + +int +__pthread_getaffinity_new (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid, + MIN (INT_MAX, cpusetsize), cpuset); + if (INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + /* Clean the rest of the memory the kernel didn't do. */ + memset ((char *) cpuset + res, '\0', cpusetsize - res); + + return 0; +} +strong_alias(__pthread_getaffinity_new, __pthread_getaffinity_np) +strong_alias(__pthread_getaffinity_new, pthread_getaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c new file mode 100644 index 000000000..5f9380814 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c @@ -0,0 +1,111 @@ +/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version + Copyright (C) 2000,2001,2002,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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthreadP.h> +#include <sys/time.h> +#include <tls.h> +#include <bits/kernel-features.h> +#include <kernel-posix-cpu-timers.h> + + +#if !(__ASSUME_POSIX_CPU_TIMERS > 0) +int __libc_missing_posix_cpu_timers attribute_hidden; +#endif +#if !(__ASSUME_POSIX_TIMERS > 0) +int __libc_missing_posix_timers attribute_hidden; +#endif + +int +pthread_getcpuclockid (threadid, clockid) + pthread_t threadid; + clockid_t *clockid; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + +#ifdef __NR_clock_getres + /* The clockid_t value is a simple computation from the TID. + But we do a clock_getres call to validate it if we aren't + yet sure we have the kernel support. */ + + const clockid_t tidclock = MAKE_THREAD_CPUCLOCK (pd->tid, CPUCLOCK_SCHED); + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +# if !(__ASSUME_POSIX_TIMERS > 0) + if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) + __libc_missing_posix_cpu_timers = 1; +# endif + if (!__libc_missing_posix_cpu_timers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_SYSCALL (clock_getres, err, 2, tidclock, NULL); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) +# endif + { + *clockid = tidclock; + return 0; + } + +# if !(__ASSUME_POSIX_CPU_TIMERS > 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) + { + /* The kernel doesn't support these clocks at all. */ + __libc_missing_posix_cpu_timers = 1; + } + else + return INTERNAL_SYSCALL_ERRNO (r, err); + } +# endif +#endif + +#ifdef CLOCK_THREAD_CPUTIME_ID + /* We need to store the thread ID in the CLOCKID variable together + with a number identifying the clock. We reserve the low 3 bits + for the clock ID and the rest for the thread ID. This is + problematic if the thread ID is too large. But 29 bits should be + fine. + + If some day more clock IDs are needed the ID part can be + enlarged. The IDs are entirely internal. */ + if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE)) + return ERANGE; + + /* Store the number. */ + *clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE); + + return 0; +#else + /* We don't have a timer for that. */ + return ENOENT; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c new file mode 100644 index 000000000..104472468 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +__pthread_kill (threadid, signo) + pthread_t threadid; + int signo; +{ + struct pthread *pd = (struct pthread *) threadid; + + /* Make sure the descriptor is valid. */ + if (INVALID_TD_P (pd)) + /* Not a valid thread handle. */ + return ESRCH; + + /* Disallow sending the signal we use for cancellation, timers, for + for the setxid implementation. */ + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + + /* One comment: The PID field in the TCB can temporarily be changed + (in fork). But this must not affect this code here. Since this + function would have to be called while the thread is executing + fork, it would have to happen in a signal handler. But this is + no allowed, pthread_kill is not guaranteed to be async-safe. */ + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, signo); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), + pd->tid, signo); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, signo); +#endif + + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +} +strong_alias (__pthread_kill, pthread_kill) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c new file mode 100644 index 000000000..047c64322 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c @@ -0,0 +1,8 @@ +#include <pthreadP.h> + +#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex) +#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock(mutex) +#define __pthread_mutex_lock __pthread_mutex_cond_lock +#define NO_INCR + +#include <pthread_mutex_lock.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c new file mode 100644 index 000000000..fa7b48904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <alloca.h> +#include <errno.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <sys/types.h> + + +size_t __kernel_cpumask_size; + + +/* Determine the current affinity. As a side affect we learn + about the size of the cpumask_t in the kernel. */ +int +__determine_cpumask_size (pid_t tid) +{ + INTERNAL_SYSCALL_DECL (err); + int res; + + size_t psize = 128; + void *p = alloca (psize); + + while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p), + INTERNAL_SYSCALL_ERROR_P (res, err) + && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL) + p = extend_alloca (p, psize, 2 * psize); + + if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err)) + return INTERNAL_SYSCALL_ERRNO (res, err); + + __kernel_cpumask_size = res; + + return 0; +} + + +int +__pthread_setaffinity_new (pthread_t th, size_t cpusetsize, + const cpu_set_t *cpuset) +{ + const struct pthread *pd = (const struct pthread *) th; + + INTERNAL_SYSCALL_DECL (err); + int res; + + if (__builtin_expect (__kernel_cpumask_size == 0, 0)) + { + res = __determine_cpumask_size (pd->tid); + if (res != 0) + return res; + } + + /* We now know the size of the kernel cpumask_t. Make sure the user + does not request to set a bit beyond that. */ + size_t cnt; + for (cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) + if (((char *) cpuset)[cnt] != '\0') + /* Found a nonzero byte. This means the user request cannot be + fulfilled. */ + return EINVAL; + + res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize, + cpuset); + return (INTERNAL_SYSCALL_ERROR_P (res, err) + ? INTERNAL_SYSCALL_ERRNO (res, err) + : 0); +} +weak_alias(__pthread_setaffinity_new, pthread_setaffinity_np) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c new file mode 100644 index 000000000..5aecffcf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <sched.h> + + +/* With the 1-on-1 model we implement this function is equivalent to + the 'sched_yield' function. */ +int +pthread_yield (void) +{ + return sched_yield (); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 000000000..de794e4ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <sysdep.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +extern __typeof(raise) __raise; +int __raise (int sig) +{ + struct pthread *pd = THREAD_SELF; +#if __ASSUME_TGKILL || defined __NR_tgkill + pid_t pid = THREAD_GETMEM (pd, pid); +#endif + pid_t selftid = THREAD_GETMEM (pd, tid); + if (selftid == 0) + { + /* This system call is not supposed to fail. */ +#ifdef INTERNAL_SYSCALL + INTERNAL_SYSCALL_DECL (err); + selftid = INTERNAL_SYSCALL (gettid, err, 0); +#else + selftid = INLINE_SYSCALL (gettid, 0); +#endif + THREAD_SETMEM (pd, tid, selftid); + +#if __ASSUME_TGKILL || defined __NR_tgkill + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + pid = selftid; +#endif + } +#if __ASSUME_TGKILL || defined __NR_tgkill + else + /* raise is an async-safe function. It could be called while the + fork/vfork function temporarily invalidated the PID field. Adjust for + that. */ + if (__builtin_expect (pid <= 0, 0)) + pid = (pid & INT_MAX) == 0 ? selftid : -pid; +#endif + +#if __ASSUME_TGKILL + return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +#else +# ifdef __NR_tgkill + int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); + if (res != -1 || errno != ENOSYS) + return res; +# endif + return INLINE_SYSCALL (tkill, 2, selftid, sig); +#endif +} +libc_hidden_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(raise) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S new file mode 100644 index 000000000..d3adfa84c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END(__libc_read) + +libc_hidden_def (__read_nocancel) +libc_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libc_hidden_weak (__read) +weak_alias (__libc_read, read) +libc_hidden_weak (read) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S new file mode 100644 index 000000000..95fa6516e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libc_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libc_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libc_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S new file mode 100644 index 000000000..d9cc1e9b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libc_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libc_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libc_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S new file mode 100644 index 000000000..c761b907c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libc_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libc_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libc_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c new file mode 100644 index 000000000..18b9893d9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "fork.h" + + +/* Lock to protect allocation and deallocation of fork handlers. */ +lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER; + + +/* Number of pre-allocated handler entries. */ +#define NHANDLER 48 + +/* Memory pool for fork handler structures. */ +static struct fork_handler_pool +{ + struct fork_handler_pool *next; + struct fork_handler mem[NHANDLER]; +} fork_handler_pool; + + +static struct fork_handler * +fork_handler_alloc (void) +{ + struct fork_handler_pool *runp = &fork_handler_pool; + struct fork_handler *result = NULL; + unsigned int i; + + do + { + /* Search for an empty entry. */ + for (i = 0; i < NHANDLER; ++i) + if (runp->mem[i].refcntr == 0) + goto found; + } + while ((runp = runp->next) != NULL); + + /* We have to allocate a new entry. */ + runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp)); + if (runp != NULL) + { + /* Enqueue the new memory pool into the list. */ + runp->next = fork_handler_pool.next; + fork_handler_pool.next = runp; + + /* We use the last entry on the page. This means when we start + searching from the front the next time we will find the first + entry unused. */ + i = NHANDLER - 1; + + found: + result = &runp->mem[i]; + result->refcntr = 1; + result->need_signal = 0; + } + + return result; +} + + +int +__register_atfork (prepare, parent, child, dso_handle) + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); + void *dso_handle; +{ + /* Get the lock to not conflict with other allocations. */ + lll_lock (__fork_lock); + + struct fork_handler *newp = fork_handler_alloc (); + + if (newp != NULL) + { + /* Initialize the new record. */ + newp->prepare_handler = prepare; + newp->parent_handler = parent; + newp->child_handler = child; + newp->dso_handle = dso_handle; + + newp->next = __fork_handlers; + __fork_handlers = newp; + } + + /* Release the lock. */ + lll_unlock (__fork_lock); + + return newp == NULL ? ENOMEM : 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c new file mode 100644 index 000000000..7f0b67918 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c @@ -0,0 +1,41 @@ +/* sem_post -- post to a POSIX semaphore. Generic futex-using version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ + int *futex = (int *) sem; + + int nr = atomic_increment_val (futex); + int err = lll_futex_wake (futex, nr); + if (__builtin_expect (err, 0) < 0) + { + __set_errno (-err); + return -1; + } + return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c new file mode 100644 index 000000000..79b11948c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c @@ -0,0 +1,97 @@ +/* sem_timedwait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> +#include <pthreadP.h> + + +int +sem_timedwait (sem_t *sem, const struct timespec *abstime) +{ + /* First check for cancellation. */ + CANCELLATION_P (THREAD_SELF); + + int *futex = (int *) sem; + int val; + int err; + + if (*futex > 0) + { + val = atomic_decrement_if_positive (futex); + if (val > 0) + return 0; + } + + err = -EINVAL; + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + goto error_return; + + do + { + struct timeval tv; + struct timespec rt; + int sec, nsec; + + /* Get the current time. */ + gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + sec = abstime->tv_sec - tv.tv_sec; + nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (nsec < 0) + { + nsec += 1000000000; + --sec; + } + + /* Already timed out? */ + err = -ETIMEDOUT; + if (sec < 0) + goto error_return; + + /* Do wait. */ + rt.tv_sec = sec; + rt.tv_nsec = nsec; + + /* Enable asynchronous cancellation. Required by the standard. */ + int oldtype = __pthread_enable_asynccancel (); + + err = lll_futex_timed_wait (futex, 0, &rt); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (oldtype); + + if (err != 0 && err != -EWOULDBLOCK) + goto error_return; + + val = atomic_decrement_if_positive (futex); + } + while (val <= 0); + + return 0; + + error_return: + __set_errno (-err); + return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c new file mode 100644 index 000000000..3cf1d9a8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c @@ -0,0 +1,44 @@ +/* sem_trywait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + + +int +__new_sem_trywait (sem_t *sem) +{ + int *futex = (int *) sem; + int val; + + if (*futex > 0) + { + val = atomic_decrement_if_positive (futex); + if (val > 0) + return 0; + } + + __set_errno (EAGAIN); + return -1; +} +weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c new file mode 100644 index 000000000..416d8634b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c @@ -0,0 +1,56 @@ +/* sem_wait -- wait on a semaphore. Generic futex-using version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> +#include <pthreadP.h> + + +int +__new_sem_wait (sem_t *sem) +{ + /* First check for cancellation. */ + CANCELLATION_P (THREAD_SELF); + + int *futex = (int *) sem; + int err; + + do + { + if (atomic_decrement_if_positive (futex) > 0) + return 0; + + /* Enable asynchronous cancellation. Required by the standard. */ + int oldtype = __pthread_enable_asynccancel (); + + err = lll_futex_wait (futex, 0); + + /* Disable asynchronous cancellation. */ + __pthread_disable_asynccancel (oldtype); + } + while (err == 0 || err == -EWOULDBLOCK); + + __set_errno (-err); + return -1; +} +weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S new file mode 100644 index 000000000..eb744c712 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libc_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libc_hidden_weak (__send) +weak_alias (__libc_send, send) +libc_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S new file mode 100644 index 000000000..4c41e01c1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libc_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libc_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libc_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S new file mode 100644 index 000000000..7cb5278e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libc_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libc_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libc_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch new file mode 100644 index 000000000..9bd7569c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch @@ -0,0 +1,84 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S pthread_once.S pthread_rwlock_wrlock.S \ + pthread_rwlock_rdlock.S pthread_rwlock_unlock.S \ + lowlevellock.S pthread_barrier_wait.S pthread_cond_broadcast.S \ + pthread_cond_signal.S \ + pthread_rwlock_timedwrlock.S pthread_rwlock_timedrdlock.S \ + sem_post.S sem_timedwait.S sem_trywait.S sem_wait.S + +libc_a_CSRC = fork.c +libc_a_SSRC = libc-lowlevellock.S clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_wrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_rdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_barrier_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_broadcast.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_signal.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_rwlock_timedwrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_timedrdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-sem_post.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_trywait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sh +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sh + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h new file mode 100644 index 000000000..969686dd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + pthread_t __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h new file mode 100644 index 000000000..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S new file mode 100644 index 000000000..918d57926 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sh/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c new file mode 100644 index 000000000..e17c0174b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + + +/* Get the real implementation. */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c new file mode 100644 index 000000000..dcedd2625 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sysdep.h> +#include <tls.h> + +/* TLS pointer argument is passed as the 5-th argument. */ +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S new file mode 100644 index 000000000..94a24b46e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S @@ -0,0 +1,19 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h new file mode 100644 index 000000000..062ce2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h @@ -0,0 +1,81 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef __ASSEMBLER__ + +#define _IMP1 #1 +#define _IMM1 #-1 +#define _IMM4 #-4 +#define _IMM6 #-6 +#define _IMM8 #-8 + +#define INC(mem, reg) \ + .align 2; \ + mova 99f, r0; \ + mov r15, r1; \ + mov _IMM6, r15; \ +98: mov.l mem, reg; \ + add _IMP1, reg; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define DEC(mem, reg) \ + .align 2; \ + mova 99f, r0; \ + mov r15, r1; \ + mov _IMM6, r15; \ +98: mov.l mem, reg; \ + add _IMM1, reg; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define XADD(reg, mem, new, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM4, r15; \ +98: mov.l mem, old; \ + mov old, new; \ + add reg, new; \ + mov.l new, mem; \ +99: mov r1, r15 + +#define XCHG(reg, mem, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM4, r15; \ +98: mov.l mem, old; \ + mov.l reg, mem; \ +99: mov r1, r15 + +#define CMPXCHG(reg, mem, new, old) \ + .align 2; \ + mova 99f, r0; \ + nop; \ + mov r15, r1; \ + mov _IMM8, r15; \ +98: mov.l mem, old; \ + cmp/eq old, reg; \ + bf 99f; \ + mov.l new, mem; \ +99: mov r1, r15 + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S new file mode 100644 index 000000000..a5c916bb7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S @@ -0,0 +1,296 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + .text + +#define SYS_gettimeofday __NR_gettimeofday + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 5 + /* void __lll_mutex_lock_wait (int val, int *__futex) */ +__lll_mutex_lock_wait: + mov #2, r6 + cmp/eq r4, r6 + mov r5, r4 + mov #0, r7 /* No timeout. */ + mov #FUTEX_WAIT, r5 + + bf 2f + +1: + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +2: + XCHG (r6, @r4, r2) + tst r2, r2 + bf 1b + + rts + nop + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 5 + /* int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) */ +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + mov.l @(4,r6), r1 + mov.l .L1g, r0 + cmp/hs r0, r1 + bt 3f + + mov.l r9, @-r15 + mov.l r8, @-r15 + mov r6, r9 + mov r5, r8 + + /* Stack frame for the timespec and timeval structs. */ + add #-8, r15 + +1: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(4,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 4f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +4: + cmp/pz r2 + bf 5f /* Time is already up. */ + + mov.l r2, @r15 /* Store relative timeout. */ + mov.l r3, @(4,r15) + + mov #1, r3 + mov #2, r6 + CMPXCHG (r3, @r8, r6, r2) + tst r2, r2 + bt 8f + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r4 + +8: + mov #0, r3 + CMPXCHG (r3, @r8, r6, r2) + bf/s 7f + mov #0, r0 + +6: + add #8, r15 + mov.l @r15+, r8 + rts + mov.l @r15+, r9 +7: + /* Check whether the time expired. */ + mov #-ETIMEDOUT, r1 + cmp/eq r5, r1 + bt 5f + + /* Make sure the current holder knows we are going to sleep. */ + XCHG (r2, @r8, r3) + tst r3, r3 + bt/s 6b + mov #0, r0 + bra 1b + nop +3: + rts + mov #EINVAL, r0 +5: + bra 6b + mov #ETIMEDOUT, r0 + +.L1k: + .word 1000 + .align 2 +.L1g: + .long 1000000000 + + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 5 +lll_unlock_wake_cb: + DEC (@r4, r2) + tst r2, r2 + bt 1f + + mov #FUTEX_WAKE, r5 + mov #1, r6 /* Wake one thread. */ + mov #0, r7 + mov.l r7, @r4 /* Stores 0. */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +1: + rts + nop + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 5 + /* void __lll_mutex_unlock_wake(int *__futex) */ +__lll_mutex_unlock_wake: + mov #FUTEX_WAKE, r5 + mov #1, r6 /* Wake one thread. */ + mov #0, r7 + mov.l r7, @r4 /* Stores 0. */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + rts + nop + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 5 +__lll_timedwait_tid: + mov.l r9, @-r15 + mov.l r8, @-r15 + mov r4, r8 + mov r5, r9 + + /* Stack frame for the timespec and timeval structs. */ + add #-8, r15 + +2: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(4,r15), r0 + mov.w .L1k2, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 5f + mov.l .L1g2, r1 + add r1, r3 + add #-1, r2 +5: + cmp/pz r2 + bf 6f /* Time is already up. */ + + mov.l r2, @r15 /* Store relative timeout. */ + mov.l r3, @(4,r15) + + mov.l @r8, r2 + tst r2, r2 + bt 4f + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov r2, r6 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l @r8, r2 + tst r2, r2 + bf 1f +4: + mov #0, r0 +3: + add #8, r15 + mov.l @r15+, r8 + rts + mov.l @r15+, r9 +1: + /* Check whether the time expired. */ + mov #-ETIMEDOUT, r1 + cmp/eq r0, r1 + bf 2b +6: + bra 3b + mov #ETIMEDOUT, r0 + +.L1k2: + .word 1000 + .align 2 +.L1g2: + .long 1000000000 + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h new file mode 100644 index 000000000..45339f5e0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h @@ -0,0 +1,294 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <syscall.h> +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + +extern int __lll_mutex_lock_wait (int val, int *__futex) attribute_hidden; +extern int __lll_mutex_timedlock_wait (int val, int *__futex, + const struct timespec *abstime) + attribute_hidden; +extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden; + + +#define lll_mutex_trylock(futex) \ + ({ unsigned char __result; \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%1,r2\n\ + cmp/eq r2,%3\n\ + bf 1f\n\ + mov.l %2,@%1\n\ + 1: mov r1,r15\n\ + mov #-1,%0\n\ + negc %0,%0"\ + : "=r" (__result) \ + : "r" (&(futex)), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "r0", "r1", "r2", "t", "memory"); \ + __result; }) + +#define lll_mutex_cond_trylock(futex) \ + ({ unsigned char __result; \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%1,r2\n\ + cmp/eq r2,%3\n\ + bf 1f\n\ + mov.l %2,@%1\n\ + 1: mov r1,r15\n\ + mov #-1,%0\n\ + negc %0,%0"\ + : "=r" (__result) \ + : "r" (&(futex)), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "r" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "r0", "r1", "r2", "t", "memory"); \ + __result; }) + +#define lll_mutex_lock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (1), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __lll_mutex_lock_wait (__result, __futex); }) + +/* Special version of lll_mutex_lock which causes the unlock function to + always wakeup waiters. */ +#define lll_mutex_cond_lock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (2), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __lll_mutex_lock_wait (__result, __futex); }) + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + nop\n\ + mov r15,r1\n\ + mov #-8,r15\n\ + 0: mov.l @%2,%0\n\ + tst %0,%0\n\ + bf 1f\n\ + mov.l %1,@%2\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (1), "r" (__futex) \ + : "r0", "r1", "t", "memory"); \ + if (__result) \ + __result = __lll_mutex_timedlock_wait (__result, __futex, timeout); \ + __result; }) + +#define lll_mutex_unlock(futex) \ + (void) ({ int __result, *__futex = &(futex); \ + __asm __volatile ("\ + .align 2\n\ + mova 1f,r0\n\ + mov r15,r1\n\ + mov #-6,r15\n\ + 0: mov.l @%1,%0\n\ + add #-1,%0\n\ + mov.l %0,@%1\n\ + 1: mov r1,r15"\ + : "=&r" (__result) : "r" (__futex) \ + : "r0", "r1", "memory"); \ + if (__result) \ + __lll_mutex_unlock_wake (__futex); }) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + + +# ifdef NEED_SYSCALL_INST_PAD +# define SYSCALL_WITH_INST_PAD "\ + trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0" +# else +# define SYSCALL_WITH_INST_PAD "\ + trapa #0x14" +# endif + +#define lll_futex_wait(futex, val) \ + do { \ + int __ignore; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAIT; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (val); \ + register unsigned long __r7 __asm ("r7") = 0; \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__ignore) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + } while (0) + +#define lll_futex_timed_wait(futex, val, timeout) \ + ({ \ + int __status; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAIT; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (val); \ + register unsigned long __r7 __asm ("r7") = (timeout); \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__status) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + __status; \ + }) + + +#define lll_futex_wake(futex, nr) \ + do { \ + int __ignore; \ + register unsigned long __r3 __asm ("r3") = SYS_futex; \ + register unsigned long __r4 __asm ("r4") = (unsigned long) (futex); \ + register unsigned long __r5 __asm ("r5") = FUTEX_WAKE; \ + register unsigned long __r6 __asm ("r6") = (unsigned long) (nr); \ + register unsigned long __r7 __asm ("r7") = 0; \ + __asm __volatile (SYSCALL_WITH_INST_PAD \ + : "=z" (__ignore) \ + : "r" (__r3), "r" (__r4), "r" (__r5), \ + "r" (__r6), "r" (__r7) \ + : "memory", "t"); \ + } while (0) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + +#define lll_trylock(futex) lll_mutex_trylock (futex) +#define lll_lock(futex) lll_mutex_lock (futex) +#define lll_unlock(futex) lll_mutex_unlock (futex) + +#define lll_islocked(futex) \ + (futex != LLL_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ + +extern int __lll_wait_tid (int *tid) attribute_hidden; +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) *__tid = &(tid); \ + while (*__tid != 0) \ + lll_futex_wait (__tid, *__tid); \ + } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h new file mode 100644 index 000000000..eb83653d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces. Linux/NPTL version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) __open (name, __VA_ARGS__) +#define __close_nocancel(fd) __close (fd) +#define __read_nocancel(fd, buf, len) __read (fd, buf, len) +#define __write_nocancel(fd, buf, len) __write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ + __waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open. */ +#define open_not_cancel(name, flags, mode) \ + __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ + __open_nocancel (name, flags) + +/* Uncancelable close. */ +#define close_not_cancel(fd) \ + __close_nocancel (fd) +#define close_not_cancel_no_status(fd) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read. */ +#define read_not_cancel(fd, buf, n) \ + __read_nocancel (fd, buf, n) + +/* Uncancelable write. */ +#define write_not_cancel(fd, buf, n) \ + __write_nocancel (fd, buf, n) + +/* Uncancelable writev. */ +#define writev_not_cancel_no_status(fd, iov, n) \ + (void) ({ INTERNAL_SYSCALL_DECL (err); \ + INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl. */ +#define fcntl_not_cancel(fd, cmd, val) \ + __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid. */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ + __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ + INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c new file mode 100644 index 000000000..5391d5cc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c @@ -0,0 +1,143 @@ +/* Special .init and .fini section support for SH. NPTL version. + Copyright (C) 2003 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 Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Library General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The Library General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + 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 Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This file is compiled into assembly code which is then munged by a sed + script into two files: crti.s and crtn.s. + + * crti.s puts a function prologue at the beginning of the + .init and .fini sections and defines global symbols for + those addresses, so they can be called as functions. + + * crtn.s puts the corresponding function epilogues + in the .init and .fini sections. */ + +__asm__ ("\n\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@TESTS_BEGIN*/\n\ +\n\ +/*@TESTS_END*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n\ + .section .init\n\ + .align 5\n\ + .global _init\n\ + .type _init,@function\n\ +_init:\n\ + mov.l r12,@-r15\n\ + mov.l r14,@-r15\n\ + sts.l pr,@-r15\n\ + mova .L22,r0\n\ + mov.l .L22,r12\n\ + add r0,r12\n\ + mova .L24,r0\n\ + mov.l .L24,r1\n\ + add r0,r1\n\ + jsr @r1\n\ + nop\n\ + mova .L23,r0\n\ + mov.l .L23,r1\n\ + add r0,r1\n\ + jsr @r1\n\ + mov r15,r14\n\ + bra 1f\n\ + nop\n\ + .align 2\n\ +.L22:\n\ + .long _GLOBAL_OFFSET_TABLE_\n\ +.L23:\n\ + .long __gmon_start__@PLT\n\ +.L24:\n\ + .long __pthread_initialize_minimal_internal@PLT\n\ +1:\n\ + ALIGN\n\ + END_INIT\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ + .section .init\n\ + mov r14,r15\n\ + lds.l @r15+,pr\n\ + mov.l @r15+,r14\n\ + rts \n\ + mov.l @r15+,r12\n\ + END_INIT\n\ + .section .text\n\ + .align 5\n\ + .weak __gmon_start__\n\ + .type __gmon_start__,@function\n\ +__gmon_start__:\n\ + mov.l r14,@-r15\n\ + mov r15,r14\n\ + mov r14,r15\n\ + rts \n\ + mov.l @r15+,r14\n\ + \n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ + .section .fini\n\ + .align 5\n\ + .global _fini\n\ + .type _fini,@function\n\ +_fini:\n\ + mov.l r12,@-r15\n\ + mov.l r14,@-r15\n\ + sts.l pr,@-r15\n\ + mova .L27,r0\n\ + mov.l .L27,r12\n\ + add r0,r12\n\ + mov r15,r14\n\ + ALIGN\n\ + END_FINI\n\ + bra 1f\n\ + nop\n\ + .align 2\n\ +.L27:\n\ + .long _GLOBAL_OFFSET_TABLE_\n\ +1:\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ + .section .fini\n\ + mov r14,r15\n\ + lds.l @r15+,pr\n\ + mov.l @r15+,r14\n\ + rts \n\ + mov.l @r15+,r12\n\ +\n\ + END_FINI\n\ + \n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\n\ +"); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S new file mode 100644 index 000000000..54f2281d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S @@ -0,0 +1,65 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + /* Save the PID value. */ + stc gbr, r2 + mov.w .L2, r0 + mov.l @(r0,r2), r4 + neg r4, r1 + mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + + /* Restore the old PID value in the parent. */ + tst r0, r0 + bt/s 2f + stc gbr, r2 + mov.w .L2, r0 + mov.l r4, @(r0,r2) + mov r1, r0 +2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 + tst r1, r1 // i.e. error in linux + bf .Lpseudo_end + SYSCALL_ERROR_HANDLER +.Lpseudo_end: + rts + nop +.L1: + .word __NR_vfork +.L2: + .word PID - TLS_PRE_TCB_SIZE + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S new file mode 100644 index 000000000..608c7364c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S @@ -0,0 +1,191 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 5 +pthread_barrier_wait: + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the mutex. */ + mov #0, r3 + mov #1, r4 + CMPXCHG (r3, @(MUTEX,r8), r4, r2) + bf 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: + mov.l @(LEFT,r8), r0 + add #-1, r0 + mov.l r0, @(LEFT,r8) + tst r0, r0 + bt 3f + + /* There are more threads to come. */ + mov.l @(CURR_EVENT,r8), r6 + + /* Release the mutex. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 6f +7: + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ + mov r8, r4 +#if CURR_EVENT != 0 + add #CURR_EVENT, r4 +#endif + mov #FUTEX_WAIT, r5 + mov #0, r7 +8: + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Don't return on spurious wakeups. The syscall does not change + any register except r0 so there is no need to reload any of + them. */ + mov.l @(CURR_EVENT,r8), r0 + cmp/eq r0, r6 + bt 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + INC (@(LEFT,r8), r2) + mov.l @(INIT_COUNT,r8), r4 + cmp/eq r2, r4 + bf 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 9f + +10: + mov #0, r0 /* != PTHREAD_BARRIER_SERIAL_THREAD */ + lds.l @r15+, pr + mov.l @r15+, r8 + rts + mov.l @r15+, r9 + +3: + /* The necessary number of threads arrived. */ + mov.l @(CURR_EVENT,r8), r1 + add #1, r1 + mov.l r1, @(CURR_EVENT,r8) + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + mov.l .Lall, r6 + mov r8, r4 +#if CURR_EVENT != 0 + add #CURR_EVENT, r4 +#endif + mov #0, r7 + mov #FUTEX_WAKE, r5 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + INC (@(LEFT,r8), r2) + mov.l @(INIT_COUNT,r8), r4 + cmp/eq r2, r4 + bf 5f + + /* Release the mutex. */ + DEC (@(MUTEX,r8), r2) + tst r2, r2 + bf 4f +5: + mov #-1, r0 /* == PTHREAD_BARRIER_SERIAL_THREAD */ + lds.l @r15+, pr + mov.l @r15+, r8 + rts + mov.l @r15+, r9 + +1: + mov r2, r4 + mov r8, r5 + mov.l .Lwait0, r1 + bsrf r1 + add #MUTEX, r5 +.Lwait0b: + bra 2b + nop + +4: + mov r8, r4 + mov.l .Lwake0, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake0b: + bra 5b + nop + +6: + mov r6, r9 + mov r8, r4 + mov.l .Lwake1, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake1b: + bra 7b + mov r9, r6 + +9: + mov r6, r9 + mov r8, r4 + mov.l .Lwake2, r1 + bsrf r1 + add #MUTEX, r4 +.Lwake2b: + bra 10b + mov r9, r6 + + .align 2 +.Lall: + .long 0x7fffffff +.Lwait0: + .long __lll_mutex_lock_wait-.Lwait0b +.Lwake0: + .long __lll_mutex_unlock_wake-.Lwake0b +.Lwake1: + .long __lll_mutex_unlock_wake-.Lwake1b +.Lwake2: + .long __lll_mutex_unlock_wake-.Lwake2b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S new file mode 100644 index 000000000..36eccf1e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S @@ -0,0 +1,210 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 5 +__pthread_cond_broadcast: + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 1f +2: + mov.l @(total_seq+4,r8),r0 + mov.l @(total_seq,r8),r1 + mov.l @(wakeup_seq+4,r8), r2 + cmp/hi r2, r0 + bt 3f + cmp/hi r0, r2 + bt 4f + mov.l @(wakeup_seq,r8), r2 + cmp/hi r2, r1 + bf 4f + +3: + /* Cause all currently waiting threads to recognize they are + woken up. */ + mov.l r1, @(wakeup_seq,r8) + mov.l r0, @(wakeup_seq+4,r8) + mov.l r1, @(woken_seq,r8) + mov.l r0, @(woken_seq+4,r8) + mov.l @(broadcast_seq,r8), r2 + add #1, r2 + mov.l r2, @(broadcast_seq,r8) + add r1, r1 + mov r1, r10 + mov.l r10, @(cond_futex,r8) + + /* Get the address of the mutex used. */ + mov.l @(dep_mutex,r8), r9 + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 7f + +8: + /* Don't use requeue for pshared condvars. */ + mov #-1, r0 + cmp/eq r0, r9 + mov r8, r4 + bt/s 9f + add #cond_futex, r4 + + /* Wake up all threads. */ + mov #FUTEX_CMP_REQUEUE, r5 + mov #1, r6 + mov #-1, r7 + shlr r7 /* r7 = 0x7fffffff */ + mov r9, r0 +# if MUTEX_FUTEX != 0 + add #MUTEX_FUTEX, r0 +# endif + mov r10, r1 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x16 + SYSCALL_INST_PAD + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + mov r0, r1 + mov #-12, r2 + shad r2, r1 + not r1, r1 + tst r1, r1 + mov r8, r4 + bt/s 9f + add #cond_futex, r4 + +10: + mov #0, r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + rts + mov.l @r15+, r10 + +4: + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 5f +6: + mov #0, r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + rts + mov.l @r15+, r10 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait5, r1 + bsrf r1 + mov r2, r4 +.Lmwait5b: + bra 2b + nop + +5: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake5, r1 + bsrf r1 + nop +.Lmwake5b: + bra 6b + nop + +7: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake6, r1 + bsrf r1 + nop +.Lmwake6b: + bra 8b + nop + +9: + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + bra 10b + nop + + .align 2 +.Lmwait5: + .long __lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: + .long __lll_mutex_unlock_wake-.Lmwake5b +.Lmwake6: + .long __lll_mutex_unlock_wake-.Lmwake6b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias (__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S new file mode 100644 index 000000000..d92f11cbb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S @@ -0,0 +1,135 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 5 +__pthread_cond_signal: + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 1f +2: + mov.l @(total_seq+4,r8),r0 + mov.l @(total_seq,r8),r1 + mov.l @(wakeup_seq+4,r8), r2 + cmp/hi r2, r0 + bt 3f + cmp/hi r0, r2 + bt 4f + mov.l @(wakeup_seq,r8), r2 + cmp/hi r2, r1 + bf 4f + +3: + /* Bump the wakeup number. */ + mov #1, r2 + mov #0, r3 + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + /* Wake up one thread. */ + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +4: + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 5f +6: + mov #0, r0 + lds.l @r15+, pr + rts + mov.l @r15+, r8 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait4, r1 + bsrf r1 + mov r2, r4 +.Lmwait4b: + bra 2b + nop + +5: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake4, r1 + bsrf r1 + nop +.Lmwake4b: + bra 6b + nop + + .align 2 +.Lmwait4: + .long __lll_mutex_lock_wait-.Lmwait4b +.Lmwake4: + .long __lll_mutex_unlock_wake-.Lmwake4b + .size __pthread_cond_signal, .-__pthread_cond_signal +weak_alias (__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S new file mode 100644 index 000000000..75ce425f8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S @@ -0,0 +1,768 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 5 +__pthread_cond_timedwait: +.LSTARTCODE: + mov.l r8, @-r15 +.Lpush_r8: + mov.l r9, @-r15 +.Lpush_r9: + mov.l r10, @-r15 +.Lpush_r10: + mov.l r11, @-r15 +.Lpush_r11: + mov.l r12, @-r15 +.Lpush_r12: + mov.l r13, @-r15 +.Lpush_r13: + sts.l pr, @-r15 +.Lpush_pr: + add #-64, r15 +.Lalloc: + mov r4, r8 + mov r5, r9 + mov r6, r13 +#ifdef PIC + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 +#endif + + mov.l @(4,r13), r0 + mov.l .L1g, r1 + cmp/hs r1, r0 + bf 0f + bra 18f + mov #EINVAL, r0 +0: + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 2f + bra 1f + nop +#ifdef PIC + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#endif + +2: + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ + mov.l @(dep_mutex,r8),r0 + cmp/eq #-1, r0 + bt 17f + mov.l r9, @(dep_mutex,r8) + +17: + /* Unlock the mutex. */ + mov.l .Lmunlock1, r1 + mov #0, r5 + bsrf r1 + mov r9, r4 +.Lmunlock1b: + + tst r0, r0 + bt 0f + bra 16f + nop +0: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(total_seq,r8) + mov.l r1,@(total_seq+4,r8) + mov.l @(cond_futex,r8), r0 + add r2, r0 + mov.l r0, @(cond_futex,r8) + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8), r0 + add r2, r0 + mov.l r0, @(cond_nwaiters,r8) + + /* Get and store current wakeup_seq value. */ + mov.l @(wakeup_seq,r8), r10 + mov.l @(wakeup_seq+4,r8), r11 + mov.l @(broadcast_seq,r8), r0 + mov.l r0, @(4,r15) + +8: + /* Get current time. */ +#ifdef __NR_clock_gettime + /* Get the clock number. */ + mov.l @(cond_nwaiters,r8), r4 + mov #((1 << clock_bits) - 1), r0 + and r0, r4 + /* Only clocks 0 and 1 are allowed. Both are handled in the + kernel. */ + mov r15, r5 + add #16, r5 + mov.w .L__NR_clock_gettime, r3 + trapa #0x12 + SYSCALL_INST_PAD +# ifndef __ASSUME_POSIX_TIMERS + cmp/eq #-ENOSYS, r0 + bt 19f +# endif + + /* Compute relative timeout. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + bra 0f + mov.l @(20,r15), r1 +.L__NR_clock_gettime: + .word __NR_clock_gettime + +# ifndef __ASSUME_POSIX_TIMERS +19: + mov r15, r4 + add #16, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(20,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + sts macl, r1 +#endif +0: +#else + mov r15, r4 + add #16, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + /* Compute relative timeout. */ + mov.l @(20,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Micro seconds to nano seconds. */ + mov.l @r13, r2 + mov.l @(4,r13), r3 + mov.l @(16,r15), r0 + sts macl, r1 +#endif + sub r0, r2 + clrt + subc r1, r3 + bf 12f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +12: + mov #-ETIMEDOUT, r1 + mov.l r1, @(12,r15) + cmp/pz r2 + bf 6f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @(16,r15) + mov.l r3, @(20,r15) + mov.l @(cond_futex,r8), r1 + mov.l r1, @(8,r15) + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 4f + bra 3f + nop +4: +.LcleanupSTART: + mov.l .Lenable1, r1 + bsrf r1 + nop +.Lenable1b: + mov.l r0, @r15 + + mov r15, r7 + add #16, r7 + mov #FUTEX_WAIT, r5 + mov.l @(8,r15), r6 + mov r8, r4 + add #cond_futex, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov.l r0, @(12,r15) + + mov.l .Ldisable1, r1 + bsrf r1 + mov.l @r15, r4 +.Ldisable1b: +.LcleanupEND: + + /* Lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 5f +6: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 23f + + mov.l @(woken_seq,r8), r0 + mov.l @(woken_seq+4,r8), r1 + + mov.l @(wakeup_seq,r8), r2 + mov.l @(wakeup_seq+4,r8), r3 + + cmp/eq r3, r11 + bf 7f + cmp/eq r2, r10 + bt 15f +7: + cmp/eq r1, r3 + bf 9f + cmp/eq r0, r2 + bf 9f +15: + mov.l @(12,r15),r0 + cmp/eq #-ETIMEDOUT, r0 + bf 8b + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + mov #ETIMEDOUT, r0 + bra 14f + mov.l r0, @(24,r15) + +23: + mov #0, r0 + bra 24f + mov.l r0, @(24,r15) + +9: + mov #0, r0 + mov.l r0, @(24,r15) +14: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +24: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 25f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 25f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +25: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 10f + +11: + mov r9, r4 + mov.l .Lmlocki1, r1 + bsrf r1 + nop +.Lmlocki1b: + + /* We return the result of the mutex_lock operation if it failed. */ + tst r0, r0 + bf 18f + mov.l @(24,r15), r0 + +18: + add #64, r15 + lds.l @r15+, pr + mov.l @r15+, r13 + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r10 + mov.l @r15+, r9 + rts + mov.l @r15+, r8 + +.L1k: + .word 1000 + .align 2 +.Lmunlock1: + .long __pthread_mutex_unlock_usercnt-.Lmunlock1b +.Lenable1: + .long __pthread_enable_asynccancel-.Lenable1b +.Ldisable1: + .long __pthread_disable_asynccancel-.Ldisable1b +.Lmlocki1: + .long __pthread_mutex_cond_lock-.Lmlocki1b +.L1g: + .long 1000000000 + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait2, r1 + bsrf r1 + mov r2, r4 +.Lmwait2b: + bra 2b + nop + +3: + /* Unlock in loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake2, r1 + bsrf r1 + nop +.Lmwake2b: + bra 4b + nop + +5: + /* Locking in loop failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait3, r1 + bsrf r1 + mov r2, r4 +.Lmwait3b: + bra 6b + nop + +10: + /* Unlock after loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake3, r1 + bsrf r1 + nop +.Lmwake3b: + bra 11b + nop + +16: + /* The initial unlocking of the mutex failed. */ + mov.l r0, @(24,r15) +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 17f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake4, r1 + bsrf r1 + nop +.Lmwake4b: +17: + bra 18b + mov.l @(24,r15), r0 + + .align 2 +.Lmwait2: + .long __lll_mutex_lock_wait-.Lmwait2b +.Lmwake2: + .long __lll_mutex_unlock_wake-.Lmwake2b +.Lmwait3: + .long __lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: + .long __lll_mutex_unlock_wake-.Lmwake3b +.Lmwake4: + .long __lll_mutex_unlock_wake-.Lmwake4b + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias (__pthread_cond_timedwait, pthread_cond_timedwait) + + + .type __condvar_tw_cleanup, @function +__condvar_tw_cleanup: + mov r4, r11 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 1f + nop + + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait5, r1 + bsrf r1 + mov r2, r4 +.Lmwait5b: + +1: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 3f + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +3: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov #0, r10 + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 4f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 4f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov #1, r10 + +4: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 2f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake5, r1 + bsrf r1 + nop +.Lmwake5b: + +2: + /* Wake up all waiters to make sure no signal gets lost. */ + tst r10, r10 + bf/s 5f + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +5: + mov.l .Lmlocki5, r1 + bsrf r1 + mov r9, r4 +.Lmlocki5b: + +.LcallUR: + mov.l .Lresume, r1 +#ifdef PIC + add r12, r1 +#endif + jsr @r1 + mov r11, r4 + sleep + + .align 2 +.Lmwait5: + .long __lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: + .long __lll_mutex_unlock_wake-.Lmwake5b +.Lmlocki5: + .long __pthread_mutex_cond_lock-.Lmlocki5b +.Lresume: +#ifdef PIC + .long _Unwind_Resume@GOTOFF +#else + .long _Unwind_Resume +#endif +.LENDCODE: + .size __condvar_tw_cleanup, .-__condvar_tw_cleanup + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff ! @LPStart format (omit) + .byte 0xff ! @TType format (omit) + .byte 0x0b ! call-site format + ! DW_EH_PE_sdata4 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .ualong .LcleanupSTART-.LSTARTCODE + .ualong .LcleanupEND-.LcleanupSTART + .ualong __condvar_tw_cleanup-.LSTARTCODE + .uleb128 0 + .ualong .LcallUR-.LSTARTCODE + .ualong .LENDCODE-.LcallUR + .ualong 0 + .uleb128 0 +.Lcstend: + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .ualong .LENDCIE-.LSTARTCIE ! Length of the CIE. +.LSTARTCIE: + .ualong 0 ! CIE ID. + .byte 1 ! Version number. +#ifdef SHARED + .string "zPLR" ! NUL-terminated augmentation + ! string. +#else + .string "zPL" ! NUL-terminated augmentation + ! string. +#endif + .uleb128 1 ! Code alignment factor. + .sleb128 -4 ! Data alignment factor. + .byte 0x11 ! Return address register + ! column. +#ifdef SHARED + .uleb128 7 ! Augmentation value length. + .byte 0x9b ! Personality: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4 + ! + DW_EH_PE_indirect + .ualong DW.ref.__gcc_personality_v0-. + .byte 0x1b ! LSDA Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. + .byte 0x1b ! FDE Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. +#else + .uleb128 6 ! Augmentation value length. + .byte 0x0 ! Personality: absolute + .ualong __gcc_personality_v0 + .byte 0x0 ! LSDA Encoding: absolute +#endif + .byte 0x0c ! DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0 + .align 2 +.LENDCIE: + + .ualong .LENDFDE-.LSTARTFDE ! Length of the FDE. +.LSTARTFDE: + .ualong .LSTARTFDE-.LSTARTFRAME ! CIE pointer. +#ifdef SHARED + .ualong .LSTARTCODE-. ! PC-relative start address + ! of the code. +#else + .ualong .LSTARTCODE ! Start address of the code. +#endif + .ualong .LENDCODE-.LSTARTCODE ! Length of the code. + .uleb128 4 ! Augmentation size +#ifdef SHARED + .ualong .LexceptSTART-. +#else + .ualong .LexceptSTART +#endif + .byte 0x4 + .ualong .Lpush_r8-.LSTARTCODE + .byte 0xe + .uleb128 4 + .byte 0x88 + .uleb128 1 + .byte 0x4 + .ualong .Lpush_r9-.Lpush_r8 + .byte 0xe + .uleb128 8 + .byte 0x89 + .uleb128 2 + .byte 0x4 + .ualong .Lpush_r10-.Lpush_r9 + .byte 0xe + .uleb128 12 + .byte 0x8a + .uleb128 3 + .byte 0x4 + .ualong .Lpush_r11-.Lpush_r10 + .byte 0xe + .uleb128 16 + .byte 0x8b + .uleb128 4 + .byte 0x4 + .ualong .Lpush_r12-.Lpush_r11 + .byte 0xe + .uleb128 20 + .byte 0x8c + .uleb128 5 + .byte 0x4 + .ualong .Lpush_r13-.Lpush_r12 + .byte 0xe + .uleb128 24 + .byte 0x8d + .uleb128 6 + .byte 0x4 + .ualong .Lpush_pr-.Lpush_r13 + .byte 0xe + .uleb128 28 + .byte 0x91 + .uleb128 7 + .byte 0x4 + .ualong .Lalloc-.Lpush_pr + .byte 0xe + .uleb128 92 + .align 2 +.LENDFDE: + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 4 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: + .long __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S new file mode 100644 index 000000000..50d98d395 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S @@ -0,0 +1,625 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelcond.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 5 +__pthread_cond_wait: +.LSTARTCODE: + mov.l r8, @-r15 +.Lpush_r8: + mov.l r9, @-r15 +.Lpush_r9: + mov.l r10, @-r15 +.Lpush_r10: + mov.l r11, @-r15 +.Lpush_r11: + mov.l r12, @-r15 +.Lpush_r12: + sts.l pr, @-r15 +.Lpush_pr: + add #-48, r15 +.Lalloc: + mov r4, r8 + mov r5, r9 +#ifdef PIC + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 +#endif + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 2f + bra 1f + nop +#ifdef PIC + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#endif + +2: + /* Store the reference to the mutex. If there is already a + different value in there this is a bad user bug. */ + mov.l @(dep_mutex,r8),r0 + cmp/eq #-1, r0 + bt 15f + mov.l r9, @(dep_mutex,r8) + +15: + /* Unlock the mutex. */ + mov.l .Lmunlock0, r1 + mov #0, r5 + bsrf r1 + mov r9, r4 +.Lmunlock0b: + + tst r0, r0 + bt 0f + bra 12f + nop +0: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(total_seq,r8) + mov.l r1,@(total_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8), r0 + add r2, r0 + mov.l r0, @(cond_nwaiters,r8) + + /* Get and store current wakeup_seq value. */ + mov.l @(wakeup_seq,r8), r10 + mov.l @(wakeup_seq+4,r8), r11 + mov.l @(broadcast_seq,r8), r0 + mov.l r0, @(4,r15) + +8: + mov.l @(cond_futex,r8),r0 + mov.l r0, @(8,r15) + + /* Unlock. */ +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 3f +4: +.LcleanupSTART: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov.l r0, @r15 + + mov #0, r7 + mov #FUTEX_WAIT, r5 + mov.l @(8,r15), r6 + mov r8, r4 + add #cond_futex, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + bsrf r1 + mov.l @r15, r4 +.Ldisable0b: +.LcleanupEND: + + /* Lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bf 5f +6: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 16f + + mov.l @(woken_seq,r8), r0 + mov.l @(woken_seq+4,r8), r1 + + mov.l @(wakeup_seq,r8), r2 + mov.l @(wakeup_seq+4,r8), r3 + + cmp/eq r3, r11 + bf 7f + cmp/eq r2, r10 + bt 8b +7: + cmp/eq r1, r3 + bf 9f + cmp/eq r0, r2 + bt 8b +9: + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +16: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 17f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 17f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +17: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 10f + +11: + mov.l .Lmlocki0, r1 + bsrf r1 + mov r9, r4 +.Lmlocki0b: + /* We return the result of the mutex_lock operation. */ + +14: + add #48, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r10 + mov.l @r15+, r9 + rts + mov.l @r15+, r8 + + .align 2 +.Lmunlock0: + .long __pthread_mutex_unlock_usercnt-.Lmunlock0b +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lmlocki0: + .long __pthread_mutex_cond_lock-.Lmlocki0b + +1: + /* Initial locking failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait0, r1 + bsrf r1 + mov r2, r4 +.Lmwait0b: + bra 2b + nop +3: + /* Unlock in loop requires waekup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake0, r1 + bsrf r1 + nop +.Lmwake0b: + bra 4b + nop + +5: + /* Locking in loop failed. */ + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait1, r1 + bsrf r1 + mov r2, r4 +.Lmwait1b: + bra 6b + nop + +10: + /* Unlock after loop requires wakeup. */ + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake1, r1 + bsrf r1 + nop +.Lmwake1b: + bra 11b + nop + +12: + /* The initial unlocking of the mutex failed. */ + mov.l r0, @(12,r15) +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bf 13f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake2, r1 + bsrf r1 + nop +.Lmwake2b: + +13: + bra 14b + mov.l @(12,r15), r0 + + .align 2 +.Lmwait0: + .long __lll_mutex_lock_wait-.Lmwait0b +.Lmwake0: + .long __lll_mutex_unlock_wake-.Lmwake0b +.Lmwait1: + .long __lll_mutex_lock_wait-.Lmwait1b +.Lmwake1: + .long __lll_mutex_unlock_wake-.Lmwake1b +.Lmwake2: + .long __lll_mutex_unlock_wake-.Lmwake2b + .size __pthread_cond_wait, .-__pthread_cond_wait +weak_alias (__pthread_cond_wait, pthread_cond_wait) + + + .type __condvar_w_cleanup, @function +__condvar_w_cleanup: + mov r4, r11 + + /* Get internal lock. */ + mov #0, r3 + mov #1, r4 +#if cond_lock != 0 + CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else + CMPXCHG (r3, @r8, r4, r2) +#endif + bt 1f + nop + + mov r8, r5 +#if cond_lock != 0 + add #cond_lock, r5 +#endif + mov.l .Lmwait3, r1 + bsrf r1 + mov r2, r4 +.Lmwait3b: + +1: + mov.l @(broadcast_seq,r8), r0 + mov.l @(4,r15), r1 + cmp/eq r0, r1 + bf 3f + + mov #1, r2 + mov #0, r3 + + clrt + mov.l @(wakeup_seq,r8),r0 + mov.l @(wakeup_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(wakeup_seq,r8) + mov.l r1,@(wakeup_seq+4,r8) + mov.l @(cond_futex,r8),r0 + add r2, r0 + mov.l r0,@(cond_futex,r8) + + clrt + mov.l @(woken_seq,r8),r0 + mov.l @(woken_seq+4,r8),r1 + addc r2, r0 + addc r3, r1 + mov.l r0,@(woken_seq,r8) + mov.l r1,@(woken_seq+4,r8) + +3: + mov #(1 << clock_bits), r2 + mov.l @(cond_nwaiters,r8),r0 + sub r2, r0 + mov.l r0,@(cond_nwaiters,r8) + + /* Wake up a thread which wants to destroy the condvar object. */ + mov #0, r10 + mov.l @(total_seq,r8),r0 + mov.l @(total_seq+4,r8),r1 + and r1, r0 + not r0, r0 + cmp/eq #0, r0 + bf/s 4f + mov #((1 << clock_bits) - 1), r1 + not r1, r1 + mov.l @(cond_nwaiters,r8),r0 + tst r1, r0 + bf 4f + + mov r8, r4 + add #cond_nwaiters, r4 + mov #FUTEX_WAKE, r5 + mov #1, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov #1, r10 + +4: +#if cond_lock != 0 + DEC (@(cond_lock,r8), r2) +#else + DEC (@r8, r2) +#endif + tst r2, r2 + bt 2f + + mov r8, r4 +#if cond_lock != 0 + add #cond_lock, r4 +#endif + mov.l .Lmwake3, r1 + bsrf r1 + nop +.Lmwake3b: + +2: + /* Wake up all waiters to make sure no signal gets lost. */ + tst r10, r10 + bf/s 5f + mov r8, r4 + add #cond_futex, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +5: + mov.l .Lmlocki3, r1 + bsrf r1 + mov r9, r4 +.Lmlocki3b: + +.LcallUR: + mov.l .Lresume, r1 +#ifdef PIC + add r12, r1 +#endif + jsr @r1 + mov r11, r4 + sleep + + .align 2 +.Lmwait3: + .long __lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: + .long __lll_mutex_unlock_wake-.Lmwake3b +.Lmlocki3: + .long __pthread_mutex_cond_lock-.Lmlocki3b +.Lresume: +#ifdef PIC + .long _Unwind_Resume@GOTOFF +#else + .long _Unwind_Resume +#endif +.LENDCODE: + .size __condvar_w_cleanup, .-__condvar_w_cleanup + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff ! @LPStart format (omit) + .byte 0xff ! @TType format (omit) + .byte 0x0b ! call-site format + ! DW_EH_PE_sdata4 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .ualong .LcleanupSTART-.LSTARTCODE + .ualong .LcleanupEND-.LcleanupSTART + .ualong __condvar_w_cleanup-.LSTARTCODE + .uleb128 0 + .ualong .LcallUR-.LSTARTCODE + .ualong .LENDCODE-.LcallUR + .ualong 0 + .uleb128 0 +.Lcstend: + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .ualong .LENDCIE-.LSTARTCIE ! Length of the CIE. +.LSTARTCIE: + .ualong 0 ! CIE ID. + .byte 1 ! Version number. +#ifdef SHARED + .string "zPLR" ! NUL-terminated augmentation + ! string. +#else + .string "zPL" ! NUL-terminated augmentation + ! string. +#endif + .uleb128 1 ! Code alignment factor. + .sleb128 -4 ! Data alignment factor. + .byte 0x11 ! Return address register + ! column. +#ifdef SHARED + .uleb128 7 ! Augmentation value length. + .byte 0x9b ! Personality: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4 + ! + DW_EH_PE_indirect + .ualong DW.ref.__gcc_personality_v0-. + .byte 0x1b ! LSDA Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. + .byte 0x1b ! FDE Encoding: DW_EH_PE_pcrel + ! + DW_EH_PE_sdata4. +#else + .uleb128 6 ! Augmentation value length. + .byte 0x0 ! Personality: absolute + .ualong __gcc_personality_v0 + .byte 0x0 ! LSDA Encoding: absolute +#endif + .byte 0x0c ! DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0 + .align 2 +.LENDCIE: + + .ualong .LENDFDE-.LSTARTFDE ! Length of the FDE. +.LSTARTFDE: + .ualong .LSTARTFDE-.LSTARTFRAME ! CIE pointer. +#ifdef SHARED + .ualong .LSTARTCODE-. ! PC-relative start address + ! of the code. +#else + .ualong .LSTARTCODE ! Start address of the code. +#endif + .ualong .LENDCODE-.LSTARTCODE ! Length of the code. + .uleb128 4 ! Augmentation size +#ifdef SHARED + .ualong .LexceptSTART-. +#else + .ualong .LexceptSTART +#endif + .byte 0x4 + .ualong .Lpush_r8-.LSTARTCODE + .byte 0xe + .uleb128 4 + .byte 0x88 + .uleb128 1 + .byte 0x4 + .ualong .Lpush_r9-.Lpush_r8 + .byte 0xe + .uleb128 8 + .byte 0x89 + .uleb128 2 + .byte 0x4 + .ualong .Lpush_r10-.Lpush_r9 + .byte 0xe + .uleb128 12 + .byte 0x8a + .uleb128 3 + .byte 0x4 + .ualong .Lpush_r11-.Lpush_r10 + .byte 0xe + .uleb128 16 + .byte 0x8b + .uleb128 4 + .byte 0x4 + .ualong .Lpush_r12-.Lpush_r11 + .byte 0xe + .uleb128 20 + .byte 0x8c + .uleb128 5 + .byte 0x4 + .ualong .Lpush_pr-.Lpush_r12 + .byte 0xe + .uleb128 24 + .byte 0x91 + .uleb128 6 + .byte 0x4 + .ualong .Lalloc-.Lpush_pr + .byte 0xe + .uleb128 72 + .align 2 +.LENDFDE: + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 4 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: + .long __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S new file mode 100644 index 000000000..2e8e6a1d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S @@ -0,0 +1,245 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unwindbuf.h> +#include <sysdep.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + .globl __pthread_once + .type __pthread_once,@function + .align 5 + cfi_startproc +__pthread_once: + mov.l @r4, r0 + tst #2, r0 + bt 1f + rts + mov #0, r0 + +1: + mov.l r12, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r12, 0) + mov.l r9, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r9, 0) + mov.l r8, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (r8, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset (4) + cfi_rel_offset (pr, 0) + mov r5, r8 + mov r4, r9 + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: + mov.l @r4, r1 + mova .Lgot, r0 + mov.l .Lgot, r12 + add r0, r12 + +5: + mov r1, r0 + + tst #2, r0 + bf 4f + + and #3, r0 + mov.l .Lfgen, r2 +#ifdef PIC + add r12, r2 +#endif + mov.l @r2, r3 + or r3, r0 + or #1, r0 + mov r0, r3 + mov r1, r5 + + CMPXCHG (r5, @r4, r3, r2) + bf 5b + + /* Check whether another thread already runs the initializer. */ + mov r2, r0 + tst #1, r0 + bt 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xor r3, r0 + mov #-4, r1 /* -4 = 0xfffffffc */ + tst r1, r0 + bf 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ + mov #FUTEX_WAIT, r5 + mov r3, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + bra 6b + nop + + .align 2 +.Lgot: + .long _GLOBAL_OFFSET_TABLE_ +#ifdef PIC +.Lfgen: + .long __fork_generation@GOTOFF +#else +.Lfgen: + .long __fork_generation +#endif + +3: + /* Call the initializer function after setting up the + cancellation handler. Note that it is not possible here + to use the unwind-based cleanup handling. This would require + that the user-provided function and all the code it calls + is compiled with exceptions. Unfortunately this cannot be + guaranteed. */ + add #-UNWINDBUFSIZE, r15 + cfi_adjust_cfa_offset (UNWINDBUFSIZE) + + mov.l .Lsigsetjmp, r1 + mov #UWJMPBUF, r4 + add r15, r4 + bsrf r1 + mov #0, r5 +.Lsigsetjmp0: + tst r0, r0 + bf 7f + + mov.l .Lcpush, r1 + bsrf r1 + mov r15, r4 +.Lcpush0: + + /* Call the user-provided initialization function. */ + jsr @r8 + nop + + /* Pop the cleanup handler. */ + mov.l .Lcpop, r1 + bsrf r1 + mov r15, r4 +.Lcpop0: + + add #UNWINDBUFSIZE, r15 + cfi_adjust_cfa_offset (-UNWINDBUFSIZE) + + /* Sucessful run of the initializer. Signal that we are done. */ + INC (@r9, r2) + /* Wake up all other threads. */ + mov r9, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + +4: + lds.l @r15+, pr + cfi_adjust_cfa_offset (-4) + cfi_restore (pr) + mov.l @r15+, r8 + cfi_adjust_cfa_offset (-4) + cfi_restore (r8) + mov.l @r15+, r9 + cfi_adjust_cfa_offset (-4) + cfi_restore (r9) + mov.l @r15+, r12 + cfi_adjust_cfa_offset (-4) + cfi_restore (r12) + rts + mov #0, r0 + +7: + /* __sigsetjmp returned for the second time. */ + cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) + cfi_offset (r12, -4) + cfi_offset (r9, -8) + cfi_offset (r8, -12) + cfi_offset (pr, -16) + mov #0, r7 + mov.l r7, @r9 + mov r9, r4 + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Lunext, r1 + bsrf r1 + mov r15, r4 +.Lunext0: + /* NOTREACHED */ + sleep + cfi_endproc + + .align 2 +.Lsigsetjmp: + .long __sigsetjmp@PLT-(.Lsigsetjmp0-.) +.Lcpush: + .long HIDDEN_JUMPTARGET(__pthread_register_cancel)-.Lcpush0 +.Lcpop: + .long HIDDEN_JUMPTARGET(__pthread_unregister_cancel)-.Lcpop0 +.Lunext: + .long HIDDEN_JUMPTARGET(__pthread_unwind_next)-.Lunext0 + .size __pthread_once,.-__pthread_once + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + + .type clear_once_control,@function + .align 5 +clear_once_control: + mov #0, r0 + mov.l r0, @r4 + + mov #FUTEX_WAKE, r5 + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + rts + nop + .size clear_once_control,.-clear_once_control diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..ce1ab37c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S @@ -0,0 +1,220 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 5 +__pthread_rwlock_rdlock: + mov.l r12, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bt 5f + mov.l @(FLAGS,r8), r0 + tst r0, r0 + bt 5f +3: + mov.l @(READERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(READERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(READERS_WAKEUP,r8), r9 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f +11: + mov r8, r4 + add #READERS_WAKEUP, r4 + mov #FUTEX_WAIT, r5 + mov r9, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Reget the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 12f +13: + mov.l @(READERS_QUEUED,r8), r0 + add #-1, r0 + bra 2b + mov.l r0, @(READERS_QUEUED,r8) + +5: + mov #0, r3 + mov.l @(NR_READERS,r8), r0 + add #1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bt 8f + +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r12 + rts + mov r3, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait0, r1 + bsrf r1 + nop +.Lwait0b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + /* Deadlock detected. */ + bra 9b + mov #EDEADLK, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake0, r1 + bsrf r1 + nop +.Lwake0b: + bra 7b + mov #0, r3 + +8: + /* Overflow. */ + mov.l @(NR_READERS,r8), r1 + add #-1, r1 + mov.l r1, @(NR_READERS,r8) + bra 9b + mov #EAGAIN, r3 + +4: + /* Overflow. */ + mov.l @(READERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(READERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake1, r1 + bsrf r1 + nop +.Lwake1b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait1, r1 + bsrf r1 + nop +.Lwait1b: + bra 13b + nop + + .align 2 +.Lwait0: + .long __lll_mutex_lock_wait-.Lwait0b +.Lwake0: + .long __lll_mutex_unlock_wake-.Lwake0b +.Lwait1: + .long __lll_mutex_lock_wait-.Lwait1b +.Lwake1: + .long __lll_mutex_unlock_wake-.Lwake1b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..8a4e7d3bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S @@ -0,0 +1,280 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 5 +pthread_rwlock_timedrdlock: + mov.l r12, @-r15 + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + add #-8, r15 + mov r4, r8 + mov r5, r9 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bt 5f + mov.l @(FLAGS,r8), r0 + tst r0, r0 + bt 5f +3: + /* Check the value of the timeout parameter. */ + mov.l .L1g0, r1 + mov.l @(4,r9), r0 + cmp/hs r1, r0 + bt 19f + + mov.l @(READERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(READERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(READERS_WAKEUP,r8), r10 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f + +11: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k0, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 15f + mov.l .L1g0, r1 + add r1, r3 + add #-1, r2 +15: + cmp/pz r2 + bf 16f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r15, r7 + mov #FUTEX_WAIT, r5 + mov r10, r6 + mov r8, r4 + add #READERS_WAKEUP, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r3 + +17: + /* Reget the lock. */ + mov #0, r5 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r5, @r8, r4, r2) +#else + CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif + bf 12f + +13: + mov.l @(READERS_QUEUED,r8), r0 + add #-1, r0 + mov.l r0, @(READERS_QUEUED,r8) + mov #-ETIMEDOUT, r0 + cmp/eq r0, r3 + bf 2b + +18: + bra 9f + mov #ETIMEDOUT, r3 + +5: + mov #0, r3 + mov.l @(NR_READERS,r8), r0 + add #1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bt 8f + +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + add #8,r15 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r12 + rts + mov r3, r0 + + .align 2 +.L1k0: + .long 1000 +.L1g0: + .long 1000000000 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait2, r1 + bsrf r1 + nop +.Lwait2b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + /* Deadlock detected. */ + bra 9b + mov #EDEADLK, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake2, r1 + bsrf r1 + nop +.Lwake2b: + bra 7b + mov #0, r3 + +8: + /* Overflow. */ + mov.l @(NR_READERS,r8), r1 + add #-1, r1 + mov.l r1, @(NR_READERS,r8) + bra 9b + mov #EAGAIN, r3 + +4: + /* Overflow. */ + mov.l @(READERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(READERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake3, r1 + bsrf r1 + nop +.Lwake3b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait3, r1 + bsrf r1 + nop +.Lwait3b: + bra 13b + nop + +16: + bra 17b + mov #-ETIMEDOUT, r3 + +19: + bra 9b + mov #EINVAL, r3 + + .align 2 +.Lwait2: + .long __lll_mutex_lock_wait-.Lwait2b +.Lwake2: + .long __lll_mutex_unlock_wake-.Lwake2b +.Lwait3: + .long __lll_mutex_lock_wait-.Lwait3b +.Lwake3: + .long __lll_mutex_unlock_wake-.Lwake3b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..6284140a6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S @@ -0,0 +1,265 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 5 +pthread_rwlock_timedwrlock: + mov.l r12, @-r15 + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + add #-8, r15 + mov r4, r8 + mov r5, r9 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(NR_READERS,r8), r0 + tst r0, r0 + bt 5f +3: + /* Check the value of the timeout parameter. */ + mov.l .L1g1, r1 + mov.l @(4,r9), r0 + cmp/hs r1, r0 + bt 19f + + mov.l @(WRITERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(WRITERS_WAKEUP,r8), r10 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f + +11: + /* Get current time. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k1, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 15f + mov.l .L1g1, r1 + add r1, r3 + add #-1, r2 +15: + cmp/pz r2 + bf 16f /* Time is already up. */ + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r15, r7 + mov #FUTEX_WAIT, r5 + mov r10, r6 + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + mov r0, r3 + +17: + /* Reget the lock. */ + mov #0, r5 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r5, @r8, r4, r2) +#else + CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif + bf 12f + +13: + mov.l @(WRITERS_QUEUED,r8), r0 + add #-1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + mov #-ETIMEDOUT, r0 + cmp/eq r0, r3 + bf 2b + +18: + bra 9f + mov #ETIMEDOUT, r3 + +19: + bra 9f + mov #EINVAL, r3 + +5: + mov #0, r3 + stc gbr, r0 + mov.w .Ltidoff, r1 + mov.l @(r0,r1), r0 + mov.l r0, @(WRITER,r8) +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + add #8,r15 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r12 + rts + mov r3, r0 + +.L1k1: + .word 1000 + .align 2 +.L1g1: + .long 1000000000 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait6, r1 + bsrf r1 + nop +.Lwait6b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + bra 9b + mov #EDEADLK, r3 +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake6, r1 + bsrf r1 + nop +.Lwake6b: + bra 7b + mov #0, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +4: + /* Overflow. */ + mov.l @(WRITERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(WRITERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake7, r1 + bsrf r1 + nop +.Lwake7b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait7, r1 + bsrf r1 + nop +.Lwait7b: + bra 13b + nop + +16: + bra 17b + mov #-ETIMEDOUT, r3 + + .align 2 +.Lwait6: + .long __lll_mutex_lock_wait-.Lwait6b +.Lwake6: + .long __lll_mutex_unlock_wake-.Lwake6b +.Lwait7: + .long __lll_mutex_lock_wait-.Lwait7b +.Lwake7: + .long __lll_mutex_unlock_wake-.Lwake7b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S new file mode 100644 index 000000000..74f32f8f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S @@ -0,0 +1,169 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 5 +__pthread_rwlock_unlock: + mov.l r12, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 5f + mov.l @(NR_READERS,r8), r0 + add #-1, r0 + mov.l r0, @(NR_READERS,r8) + tst r0, r0 + bf 6f +5: + mov #0, r0 + mov.l r0, @(WRITER,r8) + mov #1, r6 + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov.l @(WRITERS_QUEUED,r8), r0 + tst r0, r0 + bf 0f + + /* If also no readers waiting nothing to do. */ + mov.l @(READERS_QUEUED,r8), r0 + tst r0, r0 + bt 6f + + mov #-1, r6 + shlr r6 /* r6 = 0x7fffffff */ + mov r8, r4 + add #READERS_WAKEUP, r4 + +0: + mov.l @r4, r0 + add #1, r0 + mov.l r0, @r4 +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 7f + +8: + mov #FUTEX_WAKE, r5 + mov #SYS_futex, r3 + mov #0, r7 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 +6: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 3f +4: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait8, r1 + bsrf r1 + nop +.Lwait8b: + bra 2b + nop +3: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake8, r1 + bsrf r1 + nop +.Lwake8b: + bra 4b + nop + +7: + mov.l r4, @-r15 + mov.l r6, @-r15 + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake9, r1 + bsrf r1 + nop +.Lwake9b: + + mov.l @r15+, r6 + bra 8b + mov.l @r15+, r4 + + .align 2 +.Lwait8: + .long __lll_mutex_lock_wait-.Lwait8b +.Lwake8: + .long __lll_mutex_unlock_wake-.Lwake8b +.Lwake9: + .long __lll_mutex_unlock_wake-.Lwake9b + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..d071f7f03 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S @@ -0,0 +1,202 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 5 +__pthread_rwlock_wrlock: + mov.l r12, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + + /* Get the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 1f +2: + mov.l @(WRITER,r8), r0 + tst r0, r0 + bf 14f + mov.l @(NR_READERS,r8), r0 + tst r0, r0 + bt 5f +3: + mov.l @(WRITERS_QUEUED,r8), r0 + add #1, r0 + mov.l r0, @(WRITERS_QUEUED,r8) + tst r0, r0 + bt 4f + + mov.l @(WRITERS_WAKEUP,r8), r9 + +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 10f +11: + mov r8, r4 + add #WRITERS_WAKEUP, r4 + mov #FUTEX_WAIT, r5 + mov r9, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + /* Reget the lock. */ + mov #0, r3 + mov #1, r4 +#if MUTEX == 0 + CMPXCHG (r3, @r8, r4, r2) +#else + CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif + bf 12f +13: + mov.l @(WRITERS_QUEUED,r8), r0 + add #-1, r0 + bra 2b + mov.l r0, @(WRITERS_QUEUED,r8) + +5: + mov #0, r3 + stc gbr, r0 + mov.w .Ltidoff, r1 + mov.l @(r0,r1), r0 + mov.l r0, @(WRITER,r8) +9: +#if MUTEX == 0 + DEC (@r8, r2) +#else + DEC (@(MUTEX,r8), r2) +#endif + tst r2, r2 + bf 6f +7: + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r12 + rts + mov r3, r0 + +1: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait4, r1 + bsrf r1 + nop +.Lwait4b: + bra 2b + nop +14: + stc gbr, r1 + mov.w .Ltidoff, r2 + add r2, r1 + mov.l @r1, r1 + cmp/eq r1, r0 + bf 3b + bra 9b + mov #EDEADLK, r3 +6: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake4, r1 + bsrf r1 + nop +.Lwake4b: + bra 7b + mov #0, r3 + +.Ltidoff: + .word TID - TLS_PRE_TCB_SIZE + +4: + mov.l @(WRITERS_QUEUED,r8), r1 + add #-1, r1 + mov.l r1, @(WRITERS_QUEUED,r8) + bra 9b + mov #EAGAIN, r3 + +10: + mov r8, r4 +#if MUTEX != 0 + add #MUTEX, r4 +#endif + mov.l .Lwake5, r1 + bsrf r1 + nop +.Lwake5b: + bra 11b + nop + +12: + mov r8, r5 +#if MUTEX != 0 + add #MUTEX, r5 +#endif + mov r2, r4 + mov.l .Lwait5, r1 + bsrf r1 + nop +.Lwait5b: + bra 13b + nop + + .align 2 +.Lwait4: + .long __lll_mutex_lock_wait-.Lwait4b +.Lwake4: + .long __lll_mutex_unlock_wake-.Lwake4b +.Lwait5: + .long __lll_mutex_lock_wait-.Lwait5b +.Lwake5: + .long __lll_mutex_unlock_wake-.Lwake5b + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S new file mode 100644 index 000000000..9755b7e16 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S @@ -0,0 +1,84 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl __new_sem_post + .type __new_sem_post,@function + .align 5 +__new_sem_post: + INC (@r4, r6) + + mov #FUTEX_WAKE, r5 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + cmp/pz r0 + bf 1f + rts + mov #0, r0 + +1: + mov #EINVAL, r2 + mova .Lgot3, r0 + mov.l .Lgot3, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno3, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno3: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc3, r1 + bsrf r1 + nop +.Lerrloc3b: +#endif + mov.l r2, @r0 + lds.l @r15+, pr + mov.l @r15+, r12 + rts + mov #-1, r0 + + .align 2 +.Lgot3: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc3: + .long __errno_location@PLT-(.Lerrloc3b-.) +#endif + .size __new_sem_post,.-__new_sem_post + weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S new file mode 100644 index 000000000..40782fcaf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S @@ -0,0 +1,240 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 5 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + stc gbr, r0 + mov.w .Lchand, r1 + mov.l @(r0,r1), r0 + mov #0xf9, r1 + and r1, r0 + cmp/eq #8, r0 + bf 0f + bra 10f + stc gbr, r0 +0: + mov.l @r4, r0 +2: + tst r0, r0 + bt 1f + mov r0, r3 + mov r0, r6 + add #-1, r3 + CMPXCHG (r6, @r4, r3, r2) + bf/s 2b + mov r2, r0 + rts + mov #0, r0 + +1: + /* Check whether the timeout value is valid. */ + mov.l r8, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r8, 0) + mov.l r9, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r9, 0) + mov.l r10, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r10, 0) + mov.l r12, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r12, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (pr, 0) + add #-8, r15 + cfi_adjust_cfa_offset(8) + mov r4, r8 + mov r5, r9 + + /* Check for invalid nanosecond field. */ + mov.l @(4,r9), r0 + mov.l .L1g, r1 + cmp/hs r1, r0 + bt/s 6f + mov #EINVAL, r0 +7: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov r0, r10 + + /* Compute relative timeout. */ + mov r15, r4 + mov #0, r5 + mov #SYS_gettimeofday, r3 + trapa #0x12 + SYSCALL_INST_PAD + + mov.l @(4,r15), r0 + mov.w .L1k, r1 + dmulu.l r0, r1 /* Milli seconds to nano seconds. */ + mov.l @r9, r2 + mov.l @(4,r9), r3 + mov.l @r15, r0 + sts macl, r1 + sub r0, r2 + clrt + subc r1, r3 + bf 5f + mov.l .L1g, r1 + add r1, r3 + add #-1, r2 +5: + cmp/pz r2 + bf/s 6f /* Time is already up. */ + mov #ETIMEDOUT, r0 + + /* Store relative timeout. */ + mov.l r2, @r15 + mov.l r3, @(4,r15) + + /* Futex call. */ + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov #0, r6 + mov r15, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + mov r10, r4 + bsrf r1 + mov r0, r10 +.Ldisable0b: + mov r10, r0 + + tst r0, r0 + bt 9f + cmp/eq #-EWOULDBLOCK, r0 + bf 3f +9: + mov.l @r8, r0 +8: + tst r0, r0 + bt 7b + + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 8b + mov r2, r0 + + add #8, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + mov.l @r15+, r9 + mov.l @r15+, r8 + rts + mov #0, r0 + +3: + neg r0, r0 +6: + mov r0, r8 + mova .Lgot2, r0 + mov.l .Lgot2, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno2, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno2: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc2, r1 + bsrf r1 + nop +.Lerrloc2b: +#endif + mov.l r8, @r0 + add #8, r15 + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + mov.l @r15+, r9 + mov.l @r15+, r8 + rts + mov #-1, r0 + +10: + /* Canceled. */ + mov.w .Lresult, r1 + mov #-1, r2 + mov.l r2, @(r0,r1) + mov.w .Lchand, r0 + or.b #0x10, @(r0,gbr) + stc gbr, r0 + mov.w .Lclbuf, r1 + mov.l .Lunwind, r2 + braf r2 + mov.l @(r0,r1), r4 +.Lunwindb: + cfi_endproc + +.L1k: + .word 1000 +.Lchand: + .word CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: + .word RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: + .word CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE + .align 2 +.L1g: + .long 1000000000 +.Lgot2: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc2: + .long __errno_location@PLT-(.Lerrloc2b-.) +#endif +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lunwind: + .long HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S new file mode 100644 index 000000000..00c61f3bb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S @@ -0,0 +1,89 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + + + .text + + .globl __new_sem_trywait + .type __new_sem_trywait,@function + .align 5 +__new_sem_trywait: + mov.l r12, @-r15 + mov.l r8, @-r15 + sts.l pr, @-r15 + mov r4, r8 + mov.l @r8, r0 +2: + tst r0, r0 + bt 1f + + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 2b + mov r2, r0 + + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #0, r0 + +1: + mov #EAGAIN, r8 + mova .Lgot1, r0 + mov.l .Lgot1, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno1, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno1: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc1, r1 + bsrf r1 + nop +.Lerrloc1b: +#endif + mov.l r8, @r0 + lds.l @r15+, pr + mov.l @r15+, r8 + mov.l @r15+, r12 + rts + mov #-1, r0 + + .align 2 +.Lgot1: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc1: + .long __errno_location@PLT-(.Lerrloc1b-.) +#endif + .size __new_sem_trywait,.-__new_sem_trywait + weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S new file mode 100644 index 000000000..7d13fa130 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S @@ -0,0 +1,166 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday __NR_gettimeofday +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + .text + + .globl __new_sem_wait + .type __new_sem_wait,@function + .align 5 + cfi_startproc +__new_sem_wait: + /* First check for cancellation. */ + stc gbr, r0 + mov.w .Lchand, r1 + mov.l @(r0,r1), r0 + mov #0xf9, r1 + and r1, r0 + cmp/eq #8, r0 + bt 5f + + mov.l r8, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r8, 0) + mov.l r10, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r10, 0) + mov.l r12, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (r12, 0) + sts.l pr, @-r15 + cfi_adjust_cfa_offset(4) + cfi_rel_offset (pr, 0) + mov r4, r8 +3: + mov.l @r8, r0 +2: + tst r0, r0 + bt 1f + mov r0, r3 + mov r0, r4 + add #-1, r3 + CMPXCHG (r4, @r8, r3, r2) + bf/s 2b + mov r2, r0 + bra 9f + mov #0, r0 + +1: + mov.l .Lenable0, r1 + bsrf r1 + nop +.Lenable0b: + mov r0, r10 + + mov r8, r4 + mov #FUTEX_WAIT, r5 + mov #0, r6 + mov #0, r7 + mov #SYS_futex, r3 + extu.b r3, r3 + trapa #0x14 + SYSCALL_INST_PAD + + mov.l .Ldisable0, r1 + mov r10, r4 + bsrf r1 + mov r0, r10 +.Ldisable0b: + mov r10, r0 + + tst r0, r0 + bt 3b + cmp/eq #-EWOULDBLOCK, r0 + bt 3b + neg r0, r0 + + mov r0, r8 + mova .Lgot0, r0 + mov.l .Lgot0, r12 + add r0, r12 + +#if USE___THREAD + mov.l .Lerrno0, r0 + stc gbr, r1 + mov.l @(r0, r12), r0 + bra .Lexit + add r1, r0 + .align 2 +.Lerrno0: + .long errno@GOTTPOFF +.Lexit: +#else + mov.l .Lerrloc0, r1 + bsrf r1 + nop +.Lerrloc0b: +#endif + mov.l r8, @r0 + mov #-1, r0 +9: + lds.l @r15+, pr + mov.l @r15+, r12 + mov.l @r15+, r10 + rts + mov.l @r15+, r8 +5: + /* Canceled. */ + stc gbr, r0 + mov.w .Lresult, r1 + mov #-1, r2 + mov.l r2, @(r0,r1) + mov.w .Lchand, r0 + or.b #0x10, @(r0,gbr) + stc gbr, r0 + mov.w .Lclbuf, r1 + mov.l .Lunwind, r2 + braf r2 + mov.l @(r0,r1), r4 +.Lunwindb: + cfi_endproc + +.Lchand: + .word CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: + .word RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: + .word CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE + .align 2 +.Lgot0: + .long _GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc0: + .long __errno_location@PLT-(.Lerrloc0b-.) +#endif +.Lenable0: + .long __pthread_enable_asynccancel-.Lenable0b +.Ldisable0: + .long __pthread_disable_asynccancel-.Ldisable0b +.Lunwind: + .long HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb + .size __new_sem_wait,.-__new_sem_wait + weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h new file mode 100644 index 000000000..8cdcac556 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h @@ -0,0 +1,4 @@ +/* 4 instruction cycles not accessing cache and TLB are needed after + trapa instruction to avoid an SH-4 silicon bug. */ +#define NEED_SYSCALL_INST_PAD +#include <sysdeps/unix/sysv/linux/sh/lowlevellock.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h new file mode 100644 index 000000000..1aed1a14a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h @@ -0,0 +1,4 @@ +/* 4 instruction cycles not accessing cache and TLB are needed after + trapa instruction to avoid an SH-4 silicon bug. */ +#define NEED_SYSCALL_INST_PAD +#include_next <sysdep.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h new file mode 100644 index 000000000..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h @@ -0,0 +1,24 @@ +/* Determine whether the host has multiple processors. SH version. + Copyright (C) 2002 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +static inline int +is_smp_system (void) +{ + return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h new file mode 100644 index 000000000..dbaa44385 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h @@ -0,0 +1,247 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# define _IMM12 #-12 +# define _IMM16 #-16 +# define _IMP16 #16 +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + .Lpseudo_start: \ + SINGLE_THREAD_P; \ + bf .Lpseudo_cancel; \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bt .Lsyscall_error; \ + bra .Lpseudo_end; \ + nop; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + .Lpseudo_cancel: \ + sts.l pr,@-r15; \ + .LCFI0: \ + add _IMM16,r15; \ + SAVE_ARGS_##args; \ + .LCFI1: \ + CENABLE; \ + LOAD_ARGS_##args; \ + add _IMP16,r15; \ + .LCFI2: \ + lds.l @r15+,pr; \ + .LCFI3: \ + DO_CALL(syscall_name, args); \ + SYSCALL_INST_PAD; \ + sts.l pr,@-r15; \ + .LCFI4: \ + mov.l r0,@-r15; \ + .LCFI5: \ + CDISABLE; \ + mov.l @r15+,r0; \ + .LCFI6: \ + lds.l @r15+,pr; \ + .LCFI7: \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bf .Lpseudo_end; \ + .Lsyscall_error: \ + SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: \ + /* Create unwinding information for the syscall wrapper. */ \ + .section .eh_frame,"a",@progbits; \ + .Lframe1: \ + .ualong .LECIE1-.LSCIE1; \ + .LSCIE1: \ + .ualong 0x0; \ + .byte 0x1; \ + AUGMENTATION_STRING; \ + .uleb128 0x1; \ + .sleb128 -4; \ + .byte 0x11; \ + AUGMENTATION_PARAM; \ + .byte 0xc; \ + .uleb128 0xf; \ + .uleb128 0x0; \ + .align 2; \ + .LECIE1: \ + .LSFDE1: \ + .ualong .LEFDE1-.LASFDE1; \ + .LASFDE1: \ + .ualong .LASFDE1-.Lframe1; \ + START_SYMBOL_REF; \ + .ualong .Lpseudo_end - .Lpseudo_start; \ + AUGMENTATION_PARAM_FDE; \ + .byte 0x4; \ + .ualong .LCFI0-.Lpseudo_start; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x91; \ + .uleb128 0x1; \ + .byte 0x4; \ + .ualong .LCFI1-.LCFI0; \ + .byte 0xe; \ + .uleb128 0x14; \ + FRAME_REG_##args; \ + .byte 0x4; \ + .ualong .LCFI2-.LCFI1; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x4; \ + .ualong .LCFI3-.LCFI2; \ + .byte 0xe; \ + .uleb128 0x0; \ + .byte 0xd1; \ + .byte 0x4; \ + .ualong .LCFI4-.LCFI3; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0x91; \ + .uleb128 0x1; \ + .byte 0x4; \ + .ualong .LCFI5-.LCFI4; \ + .byte 0xe; \ + .uleb128 0x8; \ + .byte 0x80; \ + .uleb128 0x2; \ + .byte 0x4; \ + .ualong .LCFI6-.LCFI5; \ + .byte 0xe; \ + .uleb128 0x4; \ + .byte 0xc0; \ + .byte 0x4; \ + .ualong .LCFI7-.LCFI6; \ + .byte 0xe; \ + .uleb128 0x0; \ + .byte 0xd1; \ + .align 2; \ + .LEFDE1: \ + .previous + +# ifdef SHARED +# define AUGMENTATION_STRING .string "zR" +# define AUGMENTATION_PARAM .uleb128 1; .byte 0x1b +# define AUGMENTATION_PARAM_FDE .uleb128 0 +# define START_SYMBOL_REF .long .Lpseudo_start-. +# else +# define AUGMENTATION_STRING .ascii "\0" +# define AUGMENTATION_PARAM +# define AUGMENTATION_PARAM_FDE +# define START_SYMBOL_REF .long .Lpseudo_start +# endif + +# define FRAME_REG_0 /* Nothing. */ +# define FRAME_REG_1 FRAME_REG_0; .byte 0x84; .uleb128 5 +# define FRAME_REG_2 FRAME_REG_1; .byte 0x85; .uleb128 4 +# define FRAME_REG_3 FRAME_REG_2; .byte 0x86; .uleb128 3 +# define FRAME_REG_4 FRAME_REG_3; .byte 0x87; .uleb128 2 +# define FRAME_REG_5 FRAME_REG_4 +# define FRAME_REG_6 FRAME_REG_5 + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ + END (sym) + +# define SAVE_ARGS_0 /* Nothing. */ +# define SAVE_ARGS_1 SAVE_ARGS_0; mov.l r4,@(0,r15) +# define SAVE_ARGS_2 SAVE_ARGS_1; mov.l r5,@(4,r15) +# define SAVE_ARGS_3 SAVE_ARGS_2; mov.l r6,@(8,r15) +# define SAVE_ARGS_4 SAVE_ARGS_3; mov.l r7,@(12,r15) +# define SAVE_ARGS_5 SAVE_ARGS_4 +# define SAVE_ARGS_6 SAVE_ARGS_5 + +# define LOAD_ARGS_0 /* Nothing. */ +# define LOAD_ARGS_1 LOAD_ARGS_0; mov.l @(0,r15),r4 +# define LOAD_ARGS_2 LOAD_ARGS_1; mov.l @(4,r15),r5 +# define LOAD_ARGS_3 LOAD_ARGS_2; mov.l @(8,r15),r6 +# define LOAD_ARGS_4 LOAD_ARGS_3; mov.l @(12,r15),r7 +# define LOAD_ARGS_5 LOAD_ARGS_4 +# define LOAD_ARGS_6 LOAD_ARGS_5 + +# ifdef IS_IN_libpthread +# define __local_enable_asynccancel __pthread_enable_asynccancel +# define __local_disable_asynccancel __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define __local_enable_asynccancel __libc_enable_asynccancel +# define __local_disable_asynccancel __libc_disable_asynccancel +# elif defined IS_IN_librt +# define __local_enable_asynccancel __librt_enable_asynccancel +# define __local_disable_asynccancel __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +# define CENABLE \ + mov.l 1f,r0; \ + bsrf r0; \ + nop; \ + 0: bra 2f; \ + mov r0,r2; \ + .align 2; \ + 1: .long __local_enable_asynccancel - 0b; \ + 2: + +# define CDISABLE \ + mov.l 1f,r0; \ + bsrf r0; \ + mov r2,r4; \ + 0: bra 2f; \ + nop; \ + .align 2; \ + 1: .long __local_disable_asynccancel - 0b; \ + 2: + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + stc gbr,r0; \ + mov.w 0f,r1; \ + sub r1,r0; \ + mov.l @(MULTIPLE_THREADS_OFFSET,r0),r0; \ + bra 1f; \ + tst r0,r0; \ + 0: .word TLS_PRE_TCB_SIZE; \ + 1: + +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h new file mode 100644 index 000000000..546a21231 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h @@ -0,0 +1,224 @@ +/* Copyright (C) 1992,1993,1995,1996,1997,1998,1999,2000,2002,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. + Changed by Kaz Kojima, <kkojima@rr.iij4u.or.jp>. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LINUX_SH_SYSDEP_H +#define _LINUX_SH_SYSDEP_H 1 + +/* There is some commonality. */ +#include <sysdeps/unix/sh/sysdep.h> + +/* For Linux we can use the system call table in the header file + /usr/include/asm/unistd.h + of the kernel. But these symbols do not follow the SYS_* syntax + so we have to redefine the `SYS_ify' macro here. */ +#undef SYS_ify +#define SYS_ify(syscall_name) (__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, + unlike most Unices, which use the condition codes' carry flag. + + Since version 2.1 the return value of a system call might be + negative even if the call succeeded. E.g., the `lseek' system call + might return a large offset. Therefore we must not anymore test + for < 0, but test for a real error by making sure the value in R0 + is a real error number. Linus said he will make sure the no syscall + returns a value in -1 .. -4095 as a valid result so we can savely + test with -4095. */ + +#define _IMM1 #-1 +#define _IMM12 #-12 +#undef PSEUDO +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); \ + mov r0,r1; \ + mov _IMM12,r2; \ + shad r2,r1; \ + not r1,r1; \ + tst r1,r1; \ + bf .Lpseudo_end; \ + SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + END (name) + +#undef PSEUDO_NOERRNO +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args) + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(name) \ + END (name) + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ + DO_CALL (syscall_name, args); + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END (name) + +#define ret_ERRVAL ret + +#ifndef PIC +# define SYSCALL_ERROR_HANDLER \ + mov.l 0f,r1; \ + jmp @r1; \ + mov r0,r4; \ + .align 2; \ + 0: .long __syscall_error + +#include <libc/sysdeps/linux/sh/syscall_error.S> +#else +# ifdef RTLD_PRIVATE_ERRNO + +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + mov.l r1,@(r0,r12) + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long rtld_errno@GOTOFF + +# elif defined _LIBC_REENTRANT + +# if USE___THREAD + +# ifndef NOT_IN_libc +# define SYSCALL_ERROR_ERRNO __libc_errno +# else +# define SYSCALL_ERROR_ERRNO errno +# endif +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov r12,r2; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + stc gbr, r4; \ + mov.l @(r0,r12),r0; \ + bra .Lskip; \ + add r4,r0; \ + .align 2; \ + 1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF; \ + .Lskip: \ + mov r2,r12; \ + mov.l r1,@r0; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_ +# else + +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov.l r14,@-r15; \ + mov.l r12,@-r15; \ + mov.l r1,@-r15; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + sts.l pr,@-r15; \ + mov r15,r14; \ + mov.l 1f,r1; \ + bsrf r1; \ + nop; \ + 2: mov r14,r15; \ + lds.l @r15+,pr; \ + mov.l @r15+,r1; \ + mov.l r1,@r0; \ + mov.l @r15+,r12; \ + mov.l @r15+,r14; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long PLTJMP(C_SYMBOL_NAME(__errno_location))-(2b-.) +/* A quick note: it is assumed that the call to `__errno_location' does + not modify the stack! */ +# endif +# else + +/* Store (-r0) into errno through the GOT. */ +# define SYSCALL_ERROR_HANDLER \ + neg r0,r1; \ + mov r12,r2; \ + mov.l 0f,r12; \ + mova 0f,r0; \ + add r0,r12; \ + mov.l 1f,r0; \ + mov.l @(r0,r12),r0; \ + mov r2,r12; \ + mov.l r1,@r0; \ + bra .Lpseudo_end; \ + mov _IMM1,r0; \ + .align 2; \ + 0: .long _GLOBAL_OFFSET_TABLE_; \ + 1: .long errno@GOT +# endif /* _LIBC_REENTRANT */ +#endif /* PIC */ + +# ifdef NEED_SYSCALL_INST_PAD +# define SYSCALL_INST_PAD \ + or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0 +# else +# define SYSCALL_INST_PAD +# endif + +#define SYSCALL_INST0 trapa #0x10 +#define SYSCALL_INST1 trapa #0x11 +#define SYSCALL_INST2 trapa #0x12 +#define SYSCALL_INST3 trapa #0x13 +#define SYSCALL_INST4 trapa #0x14 +#define SYSCALL_INST5 mov.l @(0,r15),r0; trapa #0x15 +#define SYSCALL_INST6 mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16 + +#undef DO_CALL +#define DO_CALL(syscall_name, args) \ + mov.l 1f,r3; \ + SYSCALL_INST##args; \ + SYSCALL_INST_PAD; \ + bra 2f; \ + nop; \ + .align 2; \ + 1: .long SYS_ify (syscall_name); \ + 2: + +#endif /* __ASSEMBLER__ */ + +#endif /* linux/sh/sysdep.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S new file mode 100644 index 000000000..a45c09fd6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S @@ -0,0 +1,71 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +ENTRY (__vfork) + /* Save the PID value. */ + stc gbr, r2 + mov.w .L2, r0 + mov.l @(r0,r2), r4 + neg r4, r1 + tst r1, r1 + bf 1f + mov #1, r1 + rotr r1 +1: + mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + + /* Restore the old PID value in the parent. */ + tst r0, r0 + bt.s 2f + stc gbr, r2 + mov.w .L2, r0 + mov.l r4, @(r0,r2) + mov r1, r0 +2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 + tst r1, r1 // i.e. error in linux + bf .Lpseudo_end + SYSCALL_ERROR_HANDLER +.Lpseudo_end: + rts + nop +.L1: + .word __NR_vfork +.L2: + .word PID - TLS_PRE_TCB_SIZE + .align 2 +PSEUDO_END (__vfork) +hidden_def (vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c new file mode 100644 index 000000000..5159bf9b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigtimedwait (const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ +#ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +#endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, + info, timeout, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; +} + + +/* Return any pending signal or wait for one for the given time. */ +int attribute_hidden +__sigtimedwait (const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ + if (SINGLE_THREAD_P) + return do_sigtimedwait (set, info, timeout); + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigtimedwait (set, info, timeout); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__sigtimedwait, sigtimedwait) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c new file mode 100644 index 000000000..6c47fdee6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#define __need_NULL +#include <stddef.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ +#ifdef SIGCANCEL + sigset_t tmpset; + if (set != NULL + && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID + || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif + )) + { + /* Create a temporary mask without the bit for SIGCANCEL set. */ + // We are not copying more than we have to. + memcpy (&tmpset, set, _NSIG / 8); + __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID + __sigdelset (&tmpset, SIGSETXID); +# endif + set = &tmpset; + } +#endif + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, + info, NULL, _NSIG / 8); + + /* The kernel generates a SI_TKILL code in si_code in case tkill is + used. tkill is transparently used in raise(). Since having + SI_TKILL as a code is useful in general we fold the results + here. */ + if (result != -1 && info != NULL && info->si_code == SI_TKILL) + info->si_code = SI_USER; + + return result; +} + + +/* Return any pending signal or wait for one for the given time. */ +int +__sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ + if (SINGLE_THREAD_P) + return do_sigwaitinfo (set, info); + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = do_sigwaitinfo (set, info); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__sigwaitinfo, sigwaitinfo) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h new file mode 100644 index 000000000..41fa97ff4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h @@ -0,0 +1,52 @@ +/* Determine whether the host has multiple processors. Linux version. + Copyright (C) 1996, 2002, 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/sysctl.h> +#include <not-cancel.h> + +/* Test whether the machine has more than one processor. This is not the + best test but good enough. More complicated tests would require `malloc' + which is not available at that time. */ +static inline int +is_smp_system (void) +{ + static const int sysctl_args[] = { CTL_KERN, KERN_VERSION }; + char buf[512]; + size_t reslen = sizeof (buf); + + /* Try reading the number using `sysctl' first. */ + if (sysctl ((int *) sysctl_args, + sizeof (sysctl_args) / sizeof (sysctl_args[0]), + buf, &reslen, NULL, 0) < 0) + { + /* This was not successful. Now try reading the /proc filesystem. */ + int fd = open_not_cancel_2 ("/proc/sys/kernel/version", O_RDONLY); + if (__builtin_expect (fd, 0) == -1 + || (reslen = read_not_cancel (fd, buf, sizeof (buf))) <= 0) + /* This also didn't work. We give up and say it's a UP machine. */ + buf[0] = '\0'; + + close_not_cancel_no_status (fd); + } + + return strstr (buf, "SMP") != NULL; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch new file mode 100644 index 000000000..b54731075 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch @@ -0,0 +1,66 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S clone.S +libpthread_CSRC = pthread_once.c lowlevellock.c + +libc_a_CSRC = fork.c libc-lowlevellock.c +libc_a_SSRC = clone.S vfork.S + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +ASFLAGS-pt-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions new file mode 100644 index 000000000..d10277248 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions @@ -0,0 +1,6 @@ +libpthread { + GLIBC_2.3.3 { + # Changed PTHREAD_STACK_MIN. + pthread_attr_setstack; pthread_attr_setstacksize; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h new file mode 100644 index 000000000..e082ea8f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits. Linux/SPARC version. + Copyright (C) 1993-1998,2000,2002,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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol + and defines LINK_MAX although filesystems have different maxima. A + similar thing is true for OPEN_MAX: the limit can be changed at + runtime and therefore the macro must not be defined. Remove this + after including the header if necessary. */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif + +/* The kernel sources contain a file with all the needed information. */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN? */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX? */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX? */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif + +/* The number of data keys per process. */ +#define _POSIX_THREAD_KEYS_MAX 128 +/* This is the value this implementation supports. */ +#define PTHREAD_KEYS_MAX 1024 + +/* Controlling the iterations of destructors for thread-specific data. */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +/* Number of iterations this implementation does. */ +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process. */ +#define _POSIX_THREAD_THREADS_MAX 64 +/* We have no predefined limit on the number of threads. */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O + priority level. */ +#define AIO_PRIO_DELTA_MAX 20 + +/* Minimum size for a thread. We are free to choose a reasonable value. */ +#define PTHREAD_STACK_MIN 24576 + +/* Maximum number of timer expiration overruns. */ +#define DELAYTIMER_MAX 2147483647 + +/* Maximum tty name length. */ +#define TTY_NAME_MAX 32 + +/* Maximum login name length. This is arbitrary. */ +#define LOGIN_NAME_MAX 256 + +/* Maximum host name length. */ +#define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h new file mode 100644 index 000000000..459d1ca79 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h @@ -0,0 +1,218 @@ +/* Machine-specific pthread type layouts. SPARC version. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is + deliberately not exposed. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling. The structure of the attribute + type is deliberately not exposed. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE == 64 + int __spins; + __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV 1 +#else + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; +#endif + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is deliberately not exposed. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is deliberately not exposed. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h new file mode 100644 index 000000000..7f3a32832 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Machine-specific POSIX semaphore type layouts. SPARC version. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S new file mode 100644 index 000000000..dfc5e8261 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "./sparc64/clone.S" +#else +#include "./sparc32/clone.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c new file mode 100644 index 000000000..1cd79110a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + +#define ARCH_FORK() \ + INLINE_CLONE_SYSCALL (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + 0, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* No difference to lowlevellock.c, except we lose a couple of functions. */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c new file mode 100644 index 000000000..e9ec4df1e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c @@ -0,0 +1,131 @@ +/* low level locking for pthread library. SPARC version. + Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + + +/* These functions don't get included in libc.so */ +void +__lll_lock_wait (int *futex) +{ + do + { + int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2); + } + while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); +} + + +#ifdef IS_IN_libpthread +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + do + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait. */ + int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_timed_wait (futex, 2, &rt); + } + while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); + + return 0; +} + +int +lll_unlock_wake_cb(int* futex) +{ + int val = atomic_exchange_24_rel(futex, 0); + + if( __builtin_expect( val > 1, 0 ) ) { + lll_futex_wake( futex, 1 ); + } + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. The kernel so far does not use + the private futex operations for this. */ + if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h new file mode 100644 index 000000000..4db6fb0b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h @@ -0,0 +1,258 @@ +/* Copyright (C) 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 Libr \ary; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ + lll_futex_timed_wait (futexp, val, NULL) + +#define lll_futex_timed_wait(futexp, val, timespec) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAIT, (val), (timespec)); \ + __ret; \ + }) + +#define lll_futex_wake(futexp, nr) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAKE, (nr), 0); \ + __ret; \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + FUTEX_CMP_REQUEUE, (nr_wake), (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +#define lll_robust_dead(futexv) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ +#ifdef __sparc32_atomic_do_lock +/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs. */ +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) 1 +#else +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + FUTEX_WAKE_OP, \ + (nr_wake), (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) +#endif + +static inline int +__attribute__ ((always_inline)) +__lll_trylock (int *futex) +{ + return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(futex) __lll_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_cond_trylock (int *futex) +{ + return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(futex) __lll_cond_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_trylock (int *futex, int id) +{ + return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(futex, id) \ + __lll_robust_trylock (&(futex), id) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void +__attribute__ ((always_inline)) +__lll_lock (int *futex) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + + if (__builtin_expect (val != 0, 0)) + { + __lll_lock_wait (futex); + } +} +#define lll_mutex_lock(futex) __lll_lock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_lock (int *futex, int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_lock_wait (futex); + return result; +} +#define lll_robust_lock(futex, id) \ + __lll_robust_lock (&(futex), id) + +static inline void +__attribute__ ((always_inline)) +__lll_cond_lock (int *futex) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0); + + if (__builtin_expect (val != 0, 0)) + __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_cond_lock (&(futex)) + +#define lll_robust_cond_lock(futex, id) \ + __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; + +static inline int +__attribute__ ((always_inline)) +__lll_timedlock (int *futex, const struct timespec *abstime) +{ + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + int result = 0; + + if (__builtin_expect (val != 0, 0)) + result = __lll_timedlock_wait (futex, abstime); + return result; +} +#define lll_mutex_timedlock(futex, abstime) \ + __lll_timedlock (&(futex), abstime) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, + int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_timedlock_wait (futex, abstime); + return result; +} +#define lll_robust_timedlock(futex, abstime, id) \ + __lll_robust_timedlock (&(futex), abstime, id) + +#define lll_mutex_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_24_rel (__futex, 0); \ + if (__builtin_expect (__val > 1, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_robust_unlock(lock) \ + ((void) ({ \ + int *__futex = &(lock); \ + int __val = atomic_exchange_rel (__futex, 0); \ + if (__builtin_expect (__val & FUTEX_WAITERS, 0)) \ + lll_futex_wake (__futex, 1); \ + })) + +#define lll_mutex_islocked(futex) \ + (futex != 0) + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +#define lll_trylock(lock) lll_mutex_trylock (lock) +#define lll_lock(lock) lll_mutex_lock (lock) +#define lll_unlock(lock) lll_mutex_unlock (lock) +#define lll_islocked(lock) lll_mutex_islocked (lock) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do \ + { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } \ + while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S new file mode 100644 index 000000000..e8705c54b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pt-vfork.S" +#else +#include "sparc32/pt-vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c new file mode 100644 index 000000000..3b07cc127 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S new file mode 100644 index 000000000..a6142aafe --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S new file mode 100644 index 000000000..fb01242b5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sub %g0, %o5, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h new file mode 100644 index 000000000..ad650d040 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -0,0 +1,105 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ + cmp %g1, 0; \ + bne 1f; \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 8f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +8: jmpl %o7 + 8, %g0; \ + nop; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1: save %sp, -96, %sp; \ + cfi_def_cfa_register(%fp); \ + cfi_window_save; \ + cfi_register(%o7, %i7); \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 1f; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + call __syscall_error; \ + mov %l1, %o0; \ + b 2f; \ + mov -1, %l1; \ +1: CDISABLE; \ + mov %l0, %o0; \ +2: jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define COPY_ARGS_0 /* Nothing */ +#define COPY_ARGS_1 COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2 COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3 COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4 COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5 COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6 COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S new file mode 100644 index 000000000..1a3827789 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + cmp %o5, 0 + bne 1f + sub %g0, %o5, %o4 + sethi %hi(0x80000000), %o4 +1: st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S new file mode 100644 index 000000000..64e3bfc12 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/sparcv9/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S new file mode 100644 index 000000000..8941043c3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sub %g0, %o5, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a,pt %icc, 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h new file mode 100644 index 000000000..aec2d4a86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ + brnz,pn %g1, 1f; \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcc,pt %xcc, 8f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +8: jmpl %o7 + 8, %g0; \ + nop; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1: save %sp, -192, %sp; \ + cfi_def_cfa_register(%fp); \ + cfi_window_save; \ + cfi_register(%o7, %i7); \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x6d; \ + bcc,pt %xcc, 1f; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + call __syscall_error; \ + mov %l1, %o0; \ + ba,pt %xcc, 2f; \ + mov -1, %l1; \ +1: CDISABLE; \ + mov %l0, %o0; \ +2: jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel +# define CDISABLE call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel +# define CDISABLE call __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel +# define CDISABLE call __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define COPY_ARGS_0 /* Nothing */ +#define COPY_ARGS_1 COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2 COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3 COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4 COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5 COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6 COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c new file mode 100644 index 000000000..0a9c3372b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c new file mode 100644 index 000000000..f0d4fd21d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c new file mode 100644 index 000000000..82121a7a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c new file mode 100644 index 000000000..313c05fea --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c new file mode 100644 index 000000000..76f549cb4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S new file mode 100644 index 000000000..b4e89aceb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tcb-offsets.h> + + .text + .globl __syscall_error +ENTRY(__vfork) + ld [%g7 + PID], %o5 + sethi %hi(0x80000000), %o3 + cmp %o5, 0 + sub %g0, %o5, %o4 + move %icc, %o3, %o4 + st %o4, [%g7 + PID] + + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 + bne,a,pt %icc, 1f + st %o5, [%g7 + PID] +1: retl + nop +END(__vfork) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h new file mode 100644 index 000000000..5be9beb92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/sysdep-cancel.h" +#else +#include "sparc32/sysdep-cancel.h" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h new file mode 100644 index 000000000..744e587a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h @@ -0,0 +1,65 @@ +#ifndef _LINUX_SPARC_SYSDEP_H +#define _LINUX_SPARC_SYSDEP_H 1 + +#include <sysdeps/unix/sysdep.h> + +#undef ENTRY +#undef END + +#ifdef __ASSEMBLER__ + +#define LOADSYSCALL(x) mov __NR_##x, %g1 + +#define ENTRY(name) \ + .align 4; \ + .global C_SYMBOL_NAME(name); \ + .type name, @function; \ +C_LABEL(name) \ + cfi_startproc; + +#define END(name) \ + cfi_endproc; \ + .size name, . - name + +#define LOC(name) .L##name + + /* If the offset to __syscall_error fits into a signed 22-bit + * immediate branch offset, the linker will relax the call into + * a normal branch. + */ +#undef PSEUDO +#undef PSEUDO_END +#undef PSEUDO_NOERRNO +#undef PSEUDO_ERRVAL + +#define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; \ + bcc 1f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +1: + +#define PSEUDO_NOERRNO(name, syscall_name, args)\ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_END(name) \ + END(name) + + +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S new file mode 100644 index 000000000..160cd0b10 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/vfork.S" +#else +#include "sparc32/vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 000000000..09a571659 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <internaltypes.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" +#include "kernel-posix-cpu-timers.h" + + +#ifdef __NR_timer_create +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_create (clockid_t clock_id, struct sigevent *evp, + timer_t *timerid); +# define timer_create static compat_timer_create +# include <nptl/sysdeps/pthread/timer_create.c> +# undef timer_create + +/* Nonzero if the system calls are not available. */ +int __no_posix_timers attribute_hidden; +# endif + +# ifdef timer_create_alias +# define timer_create timer_create_alias +# endif + + +int +timer_create (clock_id, evp, timerid) + clockid_t clock_id; + struct sigevent *evp; + timer_t *timerid; +{ +# undef timer_create +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID + ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id == CLOCK_THREAD_CPUTIME_ID + ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) + : clock_id); + + /* If the user wants notification via a thread we need to handle + this special. */ + if (evp == NULL + || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1)) + { + struct sigevent local_evp; + + /* 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. */ + struct timer *newp = (struct timer *) malloc (offsetof (struct timer, + thrfunc)); + if (newp == NULL) + /* No more memory. */ + return -1; + + 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; + } + + kernel_timer_t ktimerid; + int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp, + &ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS + if (retval != -1 || errno != ENOSYS) +# endif + { +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = 1; +# endif + + 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; + } + + free (newp); + +# ifndef __ASSUME_POSIX_TIMERS + /* When we come here the syscall does not exist. Make sure we + do not try to use it again. */ + __no_posix_timers = -1; +# endif + } + else + { +# ifndef __ASSUME_POSIX_TIMERS + /* Make sure we have the necessary kernel support. */ + if (__no_posix_timers == 0) + { + INTERNAL_SYSCALL_DECL (err); + struct timespec ts; + int res; + res = INTERNAL_SYSCALL (clock_getres, err, 2, + CLOCK_REALTIME, &ts); + __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err) + ? -1 : 1); + } + + if (__no_posix_timers > 0) +# endif + { + /* Create the helper thread. */ + pthread_once (&__helper_once, __start_helper_thread); + if (__helper_tid == 0) + { + /* No resources to start the helper thread. */ + __set_errno (EAGAIN); + return -1; + } + + struct timer *newp; + newp = (struct timer *) malloc (sizeof (struct timer)); + if (newp == NULL) + return -1; + + /* Copy the thread parameters the user provided. */ + newp->sival = evp->sigev_value; + newp->thrfunc = evp->sigev_notify_function; + + /* We cannot simply copy the thread attributes since the + implementation might keep internal information for + each instance. */ + (void) pthread_attr_init (&newp->attr); + if (evp->sigev_notify_attributes != NULL) + { + struct pthread_attr *nattr; + struct pthread_attr *oattr; + + nattr = (struct pthread_attr *) &newp->attr; + oattr = (struct pthread_attr *) evp->sigev_notify_attributes; + + nattr->schedparam = oattr->schedparam; + nattr->schedpolicy = oattr->schedpolicy; + nattr->flags = oattr->flags; + nattr->guardsize = oattr->guardsize; + nattr->stackaddr = oattr->stackaddr; + nattr->stacksize = oattr->stacksize; + } + + /* In any case set the detach flag. */ + (void) pthread_attr_setdetachstate (&newp->attr, + PTHREAD_CREATE_DETACHED); + + /* Create the event structure for the kernel timer. */ + struct sigevent sev; + sev.sigev_value.sival_ptr = newp; + sev.sigev_signo = SIGTIMER; + sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; + /* This is the thread ID of the helper thread. */ + sev._sigev_un._pad[0] = __helper_tid; + + /* Create the timer. */ + INTERNAL_SYSCALL_DECL (err); + int res; + res = INTERNAL_SYSCALL (timer_create, err, 3, + syscall_clockid, &sev, &newp->ktimerid); + if (! INTERNAL_SYSCALL_ERROR_P (res, err)) + { + *timerid = (timer_t) newp; + return 0; + } + + /* Free the resources. */ + free (newp); + + __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + + return -1; + } + } + } + +# ifndef __ASSUME_POSIX_TIMERS + /* Compatibility code. */ + return compat_timer_create (clock_id, evp, timerid); +# endif +} +#else +# ifdef timer_create_alias +# define timer_create timer_create_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_create.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c new file mode 100644 index 000000000..3ebbbce30 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_delete +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_delete (timer_t timerid); +# define timer_delete static compat_timer_delete +# include <nptl/sysdeps/pthread/timer_delete.c> +# undef timer_delete +# endif + +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif + + +int +timer_delete (timerid) + timer_t timerid; +{ +# undef timer_delete +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); + + if (res == 0) + { +# ifndef __ASSUME_POSIX_TIMERS + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + + /* Free the memory. */ + (void) free (kt); + + return 0; + } + + /* The kernel timer is not known or something else bad happened. + Return the error. */ +# ifndef __ASSUME_POSIX_TIMERS + if (errno != ENOSYS) + { + __no_posix_timers = 1; +# endif + return -1; +# ifndef __ASSUME_POSIX_TIMERS + } + + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_delete (timerid); +# endif +} +#else +# ifdef timer_delete_alias +# define timer_delete timer_delete_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_delete.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c new file mode 100644 index 000000000..4c97f97ce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_getoverrun (timer_t timerid); +# define timer_getoverrun static compat_timer_getoverrun +# include <nptl/sysdeps/pthread/timer_getoverr.c> +# undef timer_getoverrun +# endif + +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif + + +int +timer_getoverrun (timerid) + timer_t timerid; +{ +# undef timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Get the information from the kernel. */ + int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_getoverrun (timerid); +# endif +} +#else +# ifdef timer_getoverrun_alias +# define timer_getoverrun timer_getoverrun_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_getoverr.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c new file mode 100644 index 000000000..3ce0916a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_gettime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_gettime (timer_t timerid, struct itimerspec *value); +# define timer_gettime static compat_timer_gettime +# include <nptl/sysdeps/pthread/timer_gettime.c> +# undef timer_gettime +# endif + +# ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +# endif + + +int +timer_gettime (timerid, value) + timer_t timerid; + struct itimerspec *value; +{ +# undef timer_gettime +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_gettime (timerid, value); +# endif +} +#else +# ifdef timer_gettime_alias +# define timer_gettime timer_gettime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_gettime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c new file mode 100644 index 000000000..0ddfe8a51 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_create +/* Helper thread to call the user-provided function. */ +static void * +timer_sigev_thread (void *arg) +{ + /* The parent thread has all signals blocked. This is a bit + surprising for user code, although valid. We unblock all + signals. */ + sigset_t ss; + sigemptyset (&ss); + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); + + struct timer *tk = (struct timer *) arg; + + /* Call the user-provided function. */ + tk->thrfunc (tk->sival); + + return NULL; +} + + +/* Helper function to support starting threads for SIGEV_THREAD. */ +static void * +timer_helper_thread (void *arg) +{ + /* Wait for the SIGTIMER signal, allowing the setXid signal, and + none else. */ + sigset_t ss; + sigemptyset (&ss); + __sigaddset (&ss, SIGTIMER); +#ifdef SIGSETXID + __sigaddset (&ss, SIGSETXID); +#endif + + /* Endless loop of waiting for signals. The loop is only ended when + the thread is canceled. */ + while (1) + { + siginfo_t si; + + /* sigwaitinfo cannot be used here, since it deletes + SIGCANCEL == SIGTIMER from the set. */ + + int oldtype = LIBC_CANCEL_ASYNC (); + + /* XXX The size argument hopefully will have to be changed to the + real size of the user-level sigset_t. */ + int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, + _NSIG / 8); + + LIBC_CANCEL_RESET (oldtype); + + if (result > 0) + { + if (si.si_code == SI_TIMER) + { + struct timer *tk = (struct timer *) si.si_ptr; + + /* That the signal we are waiting for. */ + pthread_t th; + (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); + } + else if (si.si_code == SI_TKILL) + /* The thread is canceled. */ + pthread_exit (NULL); + } + } +} + + +/* Control variable for helper thread creation. */ +pthread_once_t __helper_once attribute_hidden; + + +/* TID of the helper thread. */ +pid_t __helper_tid attribute_hidden; + + +/* Reset variables so that after a fork a new helper thread gets started. */ +static void +reset_helper_control (void) +{ + __helper_once = PTHREAD_ONCE_INIT; + __helper_tid = 0; +} + + +void +attribute_hidden +__start_helper_thread (void) +{ + /* The helper thread needs only very little resources + and should go away automatically when canceled. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Block all signals in the helper thread but SIGSETXID. To do this + thoroughly we temporarily have to block all signals here. The + helper can lose wakeups if SIGCANCEL is not blocked throughout, + but sigfillset omits it. So, we add it back explicitly here. */ + sigset_t ss; + sigset_t oss; + sigfillset (&ss); + __sigaddset (&ss, SIGCANCEL); +#ifdef SIGSETXID + __sigdelset (&ss, SIGSETXID); +#endif + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + + /* Create the helper thread for this timer. */ + pthread_t th; + int res = pthread_create (&th, &attr, timer_helper_thread, NULL); + if (res == 0) + /* We managed to start the helper thread. */ + __helper_tid = ((struct pthread *) th)->tid; + + /* Restore the signal mask. */ + INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, + _NSIG / 8); + + /* No need for the attribute anymore. */ + (void) pthread_attr_destroy (&attr); + + /* We have to make sure that after fork()ing a new helper thread can + be created. */ + pthread_atfork (NULL, NULL, reset_helper_control); +} +#endif + +#ifndef __ASSUME_POSIX_TIMERS +# include <nptl/sysdeps/pthread/timer_routines.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c new file mode 100644 index 000000000..558c63f26 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_settime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_settime (timer_t timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); +# define timer_settime static compat_timer_settime +# include <nptl/sysdeps/pthread/timer_settime.c> +# undef timer_settime +# endif + +# ifdef timer_settime_alias +# define timer_settime timer_settime_alias +# endif + + +int +timer_settime (timerid, flags, value, ovalue) + timer_t timerid; + int flags; + const struct itimerspec *value; + struct itimerspec *ovalue; +{ +# undef timer_settime +# ifndef __ASSUME_POSIX_TIMERS + if (__no_posix_timers >= 0) +# endif + { + struct timer *kt = (struct timer *) timerid; + + /* Delete the kernel timer object. */ + int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, + value, ovalue); + +# ifndef __ASSUME_POSIX_TIMERS + if (res != -1 || errno != ENOSYS) + { + /* We know the syscall support is available. */ + __no_posix_timers = 1; +# endif + return res; +# ifndef __ASSUME_POSIX_TIMERS + } +# endif + +# ifndef __ASSUME_POSIX_TIMERS + __no_posix_timers = -1; +# endif + } + +# ifndef __ASSUME_POSIX_TIMERS + return compat_timer_settime (timerid, flags, value, ovalue); +# endif +} +#else +# ifdef timer_settime_alias +# define timer_settime timer_settime_alias +# endif +/* The new system calls are not available. Use the userlevel + implementation. */ +# include <nptl/sysdeps/pthread/timer_settime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c new file mode 100644 index 000000000..72c8d615e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include "fork.h" +#include <atomic.h> + + +void +__unregister_atfork (dso_handle) + void *dso_handle; +{ + /* Check whether there is any entry in the list which we have to + remove. It is likely that this is not the case so don't bother + getting the lock. + + We do not worry about other threads adding entries for this DSO + right this moment. If this happens this is a race and we can do + whatever we please. The program will crash anyway seen. */ + struct fork_handler *runp = __fork_handlers; + struct fork_handler *lastp = NULL; + + while (runp != NULL) + if (runp->dso_handle == dso_handle) + break; + else + { + lastp = runp; + runp = runp->next; + } + + if (runp == NULL) + /* Nothing to do. */ + return; + + /* Get the lock to not conflict with additions or deletions. Note + that there couldn't have been another thread deleting something. + The __unregister_atfork function is only called from the + dlclose() code which itself serializes the operations. */ + lll_lock (__fork_lock); + + /* We have to create a new list with all the entries we don't remove. */ + struct deleted_handler + { + struct fork_handler *handler; + struct deleted_handler *next; + } *deleted = NULL; + + /* Remove the entries for the DSO which is unloaded from the list. + It's a single linked list so readers are. */ + do + { + if (runp->dso_handle == dso_handle) + { + if (lastp == NULL) + __fork_handlers = runp->next; + else + lastp->next = runp->next; + + /* We cannot overwrite the ->next element now. Put the deleted + entries in a separate list. */ + struct deleted_handler *newp = alloca (sizeof (*newp)); + newp->handler = runp; + newp->next = deleted; + deleted = newp; + } + else + lastp = runp; + + runp = runp->next; + } + while (runp != NULL); + + /* Release the lock. */ + lll_unlock (__fork_lock); + + /* Walk the list of all entries which have to be deleted. */ + while (deleted != NULL) + { + /* We need to be informed by possible current users. */ + deleted->handler->need_signal = 1; + /* Make sure this gets written out first. */ + atomic_write_barrier (); + + /* Decrement the reference counter. If it does not reach zero + wait for the last user. */ + atomic_decrement (&deleted->handler->refcntr); + unsigned int val; + while ((val = deleted->handler->refcntr) != 0) + lll_futex_wait (&deleted->handler->refcntr, val); + + deleted = deleted->next; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym new file mode 100644 index 000000000..8044b4078 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym @@ -0,0 +1,7 @@ +#include <pthread.h> +#include <stddef.h> + +-- + +UNWINDBUFSIZE sizeof (__pthread_unwind_buf_t) +UWJMPBUF offsetof (__pthread_unwind_buf_t, __cancel_jmp_buf) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S new file mode 100644 index 000000000..f55d34629 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__waitpid, waitpid, 3) +ret +PSEUDO_END(__waitpid) + +libc_hidden_def (__waitpid) +weak_alias (__waitpid, waitpid) +libc_hidden_weak (waitpid) +weak_alias (__waitpid, __libc_waitpid) +libc_hidden_weak (__libc_waitpid) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S new file mode 100644 index 000000000..43de3320d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END(__libc_write) + +libc_hidden_def (__write_nocancel) +libc_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libc_hidden_weak (__write) +weak_alias (__libc_write, write) +libc_hidden_weak (write) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile new file mode 100644 index 000000000..b32ce29ef --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -0,0 +1,4 @@ +ifeq ($(subdir),nptl) +CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions \ + -fno-asynchronous-unwind-tables $(fno-unit-at-a-time) +endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions @@ -0,0 +1,7 @@ +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h new file mode 100644 index 000000000..51fdab0fb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h @@ -0,0 +1,209 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ + struct __pthread_internal_list *__prev; + struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __count; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; +#if __WORDSIZE != 64 + unsigned int __nusers; +#endif + int __spins; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ +# if __WORDSIZE == 64 + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + int __writer; + int __pad1; + unsigned long int __pad2; + unsigned long int __pad3; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + } __data; +# else + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned int __flags; + int __writer; + } __data; +# endif + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h new file mode 100644 index 000000000..57edbbbfb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T 32 +#else +# define __SIZEOF_SEM_T 16 +#endif + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S new file mode 100644 index 000000000..dfa6adb3e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <sysdeps/unix/sysv/linux/x86_64/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h new file mode 100644 index 000000000..02485daa5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <signal.h> +#include <time.h> +#include <sys/types.h> + +#define OLD_TIMER_MAX 256 + +extern timer_t __compat_timer_list[OLD_TIMER_MAX] attribute_hidden; + + +extern int __timer_create_new (clockid_t clock_id, struct sigevent *evp, + timer_t *timerid); +extern int __timer_delete_new (timer_t timerid); +extern int __timer_getoverrun_new (timer_t timerid); +extern int __timer_gettime_new (timer_t timerid, struct itimerspec *value); +extern int __timer_settime_new (timer_t timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); + + +extern int __timer_create_old (clockid_t clock_id, struct sigevent *evp, + int *timerid); +extern int __timer_delete_old (int timerid); +extern int __timer_getoverrun_old (int timerid); +extern int __timer_gettime_old (int timerid, struct itimerspec *value); +extern int __timer_settime_old (int timerid, int flags, + const struct itimerspec *value, + struct itimerspec *ovalue); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c new file mode 100644 index 000000000..c828e158d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 4, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S new file mode 100644 index 000000000..3621efa4f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S @@ -0,0 +1,30 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* In libc.so we do not unconditionally use the lock prefix. Only if + the application is using threads. */ +#ifndef UP +# define LOCK \ + cmpl $0, __libc_multiple_threads(%rip); \ + je 0f; \ + lock; \ +0: +#endif + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S new file mode 100644 index 000000000..3a49e25dd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S @@ -0,0 +1,283 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <pthread-errnos.h> + + .text + +#ifndef LOCK +# ifdef UP +# define LOCK +# else +# define LOCK lock +# endif +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .globl __lll_mutex_lock_wait + .type __lll_mutex_lock_wait,@function + .hidden __lll_mutex_lock_wait + .align 16 +__lll_mutex_lock_wait: + pushq %r10 + pushq %rdx + + xorq %r10, %r10 /* No timeout. */ + movl $2, %edx +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + + cmpl %edx, %eax /* NB: %edx == 2 */ + jne 2f + +1: movl $SYS_futex, %eax + syscall + +2: movl %edx, %eax + xchgl %eax, (%rdi) /* NB: lock is implied */ + + testl %eax, %eax + jnz 1b + + popq %rdx + popq %r10 + retq + .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc + .globl __lll_mutex_timedlock_wait + .type __lll_mutex_timedlock_wait,@function + .hidden __lll_mutex_timedlock_wait + .align 16 +__lll_mutex_timedlock_wait: + /* Check for a valid timeout value. */ + cmpq $1000000000, 8(%rdx) + jae 3f + + pushq %r8 + pushq %r9 + pushq %r12 + pushq %r13 + pushq %r14 + + /* Stack frame for the timespec and timeval structs. */ + subq $16, %rsp + + movq %rdi, %r12 + movq %rdx, %r13 + +1: + /* Get current time. */ + movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + /* This is a regular function call, all caller-save registers + might be clobbered. */ + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 4f + addq $1000000000, %rsi + decq %rdi +4: testq %rdi, %rdi + js 5f /* Time is already up. */ + + /* Futex call. */ + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movl $1, %eax + movl $2, %edx + LOCK + cmpxchgl %edx, (%r12) + + testl %eax, %eax + je 8f + + movq %rsp, %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rcx + +8: /* NB: %edx == 2 */ + xorl %eax, %eax + LOCK + cmpxchgl %edx, (%rdi) + jnz 7f + +6: addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + popq %r9 + popq %r8 + retq + + /* Check whether the time expired. */ +7: cmpq $-ETIMEDOUT, %rcx + je 5f + + /* Make sure the current holder knows we are going to sleep. */ + movl %edx, %eax + xchgl %eax, (%rdi) + testl %eax, %eax + jz 6b + jmp 1b + +3: movl $EINVAL, %eax + retq + +5: movl $ETIMEDOUT, %eax + jmp 6b + .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc + .globl lll_unlock_wake_cb + .type lll_unlock_wake_cb,@function + .hidden lll_unlock_wake_cb + .align 16 +lll_unlock_wake_cb: + pushq %rsi + pushq %rdx + + LOCK + addl $1, (%rdi) + jng 1f + + popq %rdx + popq %rsi + retq + .size lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + + .globl __lll_mutex_unlock_wake + .type __lll_mutex_unlock_wake,@function + .hidden __lll_mutex_unlock_wake + .align 16 +__lll_mutex_unlock_wake: + pushq %rsi + pushq %rdx + + movl $0, (%rdi) + movl $FUTEX_WAKE, %esi + movl $1, %edx /* Wake one thread. */ + movl $SYS_futex, %eax + syscall + + popq %rdx + popq %rsi + retq + .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc + .globl __lll_timedwait_tid + .type __lll_timedwait_tid,@function + .hidden __lll_timedwait_tid + .align 16 +__lll_timedwait_tid: + pushq %r12 + pushq %r13 + + movq %rdi, %r12 + movq %rsi, %r13 + + subq $16, %rsp + + /* Get current time. */ +2: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 5f + addq $1000000000, %rsi + decq %rdi +5: testq %rdi, %rdi + js 6f /* Time is already up. */ + + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movl (%r12), %edx + testl %edx, %edx + jz 4f + + movq %rsp, %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdi + movl $SYS_futex, %eax + syscall + + cmpl $0, (%rdi) + jne 1f +4: xorl %eax, %eax + +8: addq $16, %rsp + popq %r13 + popq %r12 + retq + +1: cmpq $-ETIMEDOUT, %rax + jne 2b + +6: movl $ETIMEDOUT, %eax + jmp 8b + .size __lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h new file mode 100644 index 000000000..694cbf448 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h @@ -0,0 +1,341 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> + +#ifndef LOCK_INSTR +# ifdef UP +# define LOCK_INSTR /* nothing */ +# else +# define LOCK_INSTR "lock;" +# endif +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + +/* Initializer for compatibility lock. */ +#define LLL_MUTEX_LOCK_INITIALIZER (0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2) + +/* Delay in spinlock loop. */ +#define BUSY_WAIT_NOP asm ("rep; nop") + + +#define lll_futex_wait(futex, val) \ + do { \ + int __ignore; \ + register __typeof (val) _val asm ("edx") = (val); \ + __asm __volatile ("xorq %%r10, %%r10\n\t" \ + "syscall" \ + : "=a" (__ignore) \ + : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \ + "d" (_val) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + + +#define lll_futex_wake(futex, nr) \ + do { \ + int __ignore; \ + register __typeof (nr) _nr asm ("edx") = (nr); \ + __asm __volatile ("syscall" \ + : "=a" (__ignore) \ + : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAKE), \ + "d" (_nr) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + + +/* Does not preserve %eax and %ecx. */ +extern int __lll_mutex_lock_wait (int *__futex, int __val) attribute_hidden; +/* Does not preserver %eax, %ecx, and %edx. */ +extern int __lll_mutex_timedlock_wait (int *__futex, int __val, + const struct timespec *__abstime) + attribute_hidden; +/* Preserves all registers but %eax. */ +extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden; + + +/* NB: in the lll_mutex_trylock macro we simply return the value in %eax + after the cmpxchg instruction. In case the operation succeded this + value is zero. In case the operation failed, the cmpxchg instruction + has loaded the current value of the memory work which is guaranteed + to be nonzero. */ +#define lll_mutex_trylock(futex) \ + ({ int ret; \ + __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_cond_trylock(futex) \ + ({ int ret; \ + __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \ + "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +#define lll_mutex_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (1), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_cond_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (2), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ + ({ int result, ignore1, ignore2, ignore3; \ + __asm __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %4, %%rdi\n\t" \ + "movq %8, %%rdx\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_timedlock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=a" (result), "=&D" (ignore1), "=S" (ignore2), \ + "=&d" (ignore3), "=m" (futex) \ + : "0" (0), "2" (1), "m" (futex), "m" (timeout) \ + : "memory", "cx", "cc", "r10", "r11"); \ + result; }) + + +#define lll_mutex_unlock(futex) \ + (void) ({ int ignore; \ + __asm __volatile (LOCK_INSTR "decl %0\n\t" \ + "jne 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %0, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_unlock_wake\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=m" (futex), "=&D" (ignore) \ + : "m" (futex) \ + : "ax", "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_islocked(futex) \ + (futex != LLL_MUTEX_LOCK_INITIALIZER) + + +/* We have a separate internal lock implementation which is not tied + to binary compatibility. */ + +/* Type for lock object. */ +typedef int lll_lock_t; + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + 2 - taken by more users */ + + +#if defined NOT_IN_libc || defined UP +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself. They avoid + the lock prefix when the thread library is not used. + + The code sequence to avoid unnecessary lock prefixes is what the AMD + guys suggested. If you do not like it, bring it up with AMD. + + XXX In future we might even want to avoid it on UP machines. */ + +# define lll_trylock(futex) \ + ({ unsigned char ret; \ + __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; cmpxchgl %2, %1\n\t" \ + "jmp 1f\n" \ + "0:\tcmpxchgl %2, %1\n\t" \ + "1:setne %0" \ + : "=a" (ret), "=m" (futex) \ + : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ + "0" (LLL_MUTEX_LOCK_INITIALIZER) \ + : "memory"); \ + ret; }) + + +# define lll_lock(futex) \ + (void) ({ int ignore1, ignore2, ignore3; \ + __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; cmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + "jmp 2f\n" \ + "0:\tcmpxchgl %0, %2\n\t" \ + "jnz 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %2, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_lock_wait\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ + "=a" (ignore3) \ + : "0" (1), "m" (futex), "3" (0) \ + : "cx", "r11", "cc", "memory"); }) + + +# define lll_unlock(futex) \ + (void) ({ int ignore; \ + __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ + "je 0f\n\t" \ + "lock; decl %0\n\t" \ + "jne 1f\n\t" \ + "jmp 2f\n" \ + "0:\tdecl %0\n\t" \ + "jne 1f\n\t" \ + ".subsection 1\n" \ + "1:\tleaq %0, %%rdi\n\t" \ + "subq $128, %%rsp\n\t" \ + "callq __lll_mutex_unlock_wake\n\t" \ + "addq $128, %%rsp\n\t" \ + "jmp 2f\n\t" \ + ".previous\n" \ + "2:" \ + : "=m" (futex), "=&D" (ignore) \ + : "m" (futex) \ + : "ax", "cx", "r11", "cc", "memory"); }) +#endif + + +#define lll_islocked(futex) \ + (futex != LLL_MUTEX_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. + + The macro parameter must not have any side effect. */ +#define lll_wait_tid(tid) \ + do { \ + int __ignore; \ + register __typeof (tid) _tid asm ("edx") = (tid); \ + if (_tid != 0) \ + __asm __volatile ("xorq %%r10, %%r10\n\t" \ + "1:\tmovq %2, %%rax\n\t" \ + "syscall\n\t" \ + "cmpl $0, (%%rdi)\n\t" \ + "jne 1b" \ + : "=&a" (__ignore) \ + : "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid), \ + "d" (_tid) \ + : "memory", "cc", "r10", "r11", "cx"); \ + } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) + attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __result = 0; \ + if (tid != 0) \ + { \ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ + __result = EINVAL; \ + else \ + __result = __lll_timedwait_tid (&tid, abstime); \ + } \ + __result; }) + + +/* Conditional variable handling. */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, + const struct timespec *abstime) + attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ + __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ + __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ + __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ + __lll_cond_broadcast (cond) + + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S new file mode 100644 index 000000000..653b6b12f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S @@ -0,0 +1,33 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +#define SAVE_PID \ + movl %fs:PID, %esi; \ + movl %esi, %edx; \ + negl %edx; \ + movl %edx, %fs:PID + +#define RESTORE_PID \ + testq %rax, %rax; \ + je 1f; \ + movl %esi, %fs:PID; \ +1: + +#include <../../../../../../sysdeps/unix/sysv/linux/x86_64/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S new file mode 100644 index 000000000..fa8125dd8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S @@ -0,0 +1,160 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelbarrier.h> + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_barrier_wait + .type pthread_barrier_wait,@function + .align 16 +pthread_barrier_wait: + /* Get the mutex. */ + xorl %eax, %eax + movl $1, %esi + LOCK + cmpxchgl %esi, MUTEX(%rdi) + jnz 1f + + /* One less waiter. If this was the last one needed wake + everybody. */ +2: decl LEFT(%rdi) + je 3f + + /* There are more threads to come. */ +#if CURR_EVENT == 0 + movl (%rdi), %edx +#else + movl CURR_EVENT(%rdi), %edx +#endif + + /* Release the mutex. */ + LOCK + decl MUTEX(%rdi) + jne 6f + + /* Wait for the remaining threads. The call will return immediately + if the CURR_EVENT memory has meanwhile been changed. */ +7: +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + xorq %r10, %r10 +8: movl $SYS_futex, %eax + syscall + + /* Don't return on spurious wakeups. The syscall does not change + any register except %eax so there is no need to reload any of + them. */ +#if CURR_EVENT == 0 + cmpl %edx, (%rdi) +#else + cmpl %edx, CURR_EVENT(%rdi) +#endif + je 8b + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%rdi), %eax + LOCK + xaddl %edx, LEFT(%rdi) + subl $1, %eax + cmpl %eax, %edx + jne,pt 10f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + decl MUTEX(%rdi) + jne 9f + +10: xorl %eax, %eax /* != PTHREAD_BARRIER_SERIAL_THREAD */ + + retq + + /* The necessary number of threads arrived. */ +3: +#if CURR_EVENT == 0 + incl (%rdi) +#else + incl CURR_EVENT(%rdi) +#endif + + /* Wake up all waiters. The count is a signed number in the kernel + so 0x7fffffff is the highest value. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + + /* Increment LEFT. If this brings the count back to the + initial count unlock the object. */ + movl $1, %edx + movl INIT_COUNT(%rdi), %eax + LOCK + xaddl %edx, LEFT(%rdi) + subl $1, %eax + cmpl %eax, %edx + jne,pt 5f + + /* Release the mutex. We cannot release the lock before + waking the waiting threads since otherwise a new thread might + arrive and gets waken up, too. */ + LOCK + decl MUTEX(%rdi) + jne 4f + +5: orl $-1, %eax /* == PTHREAD_BARRIER_SERIAL_THREAD */ + + retq + +1: addq $MUTEX, %rdi + callq __lll_mutex_lock_wait + subq $MUTEX, %rdi + jmp 2b + +4: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + jmp 5b + +6: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + subq $MUTEX, %rdi + jmp 7b + +9: addq $MUTEX, %rdi + callq __lll_mutex_unlock_wake + jmp 10b + .size pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S new file mode 100644 index 000000000..8b3833392 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S @@ -0,0 +1,138 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function + .align 16 +__pthread_cond_broadcast: + + /* Get internal lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + +2: addq $cond_futex, %rdi + movq total_seq-cond_futex(%rdi), %r9 + cmpq wakeup_seq-cond_futex(%rdi), %r9 + jna 4f + + /* Cause all currently waiting threads to recognize they are + woken up. */ + movq %r9, wakeup_seq-cond_futex(%rdi) + movq %r9, woken_seq-cond_futex(%rdi) + addq %r9, %r9 + movl %r9d, (%rdi) + incl broadcast_seq-cond_futex(%rdi) + + /* Get the address of the mutex used. */ + movq dep_mutex-cond_futex(%rdi), %r8 + + /* Unlock. */ + LOCK + decl cond_lock-cond_futex(%rdi) + jne 7f + +8: cmpq $-1, %r8 + je 9f + + /* Wake up all threads. */ + movl $FUTEX_CMP_REQUEUE, %esi + movl $SYS_futex, %eax + movl $1, %edx + movl $0x7fffffff, %r10d + syscall + + /* For any kind of error, which mainly is EAGAIN, we try again + with WAKE. The general test also covers running on old + kernels. */ + cmpq $-4095, %rax + jae 9f + +10: xorl %eax, %eax + retq + + .align 16 + /* Unlock. */ +4: LOCK + decl cond_lock-cond_futex(%rdi) + jne 5f + +6: xorl %eax, %eax + retq + + /* Initial locking failed. */ +1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: addq $cond_lock-cond_futex, %rdi + callq __lll_mutex_unlock_wake + jmp 6b + + /* Unlock in loop requires wakeup. */ +7: addq $cond_lock-cond_futex, %rdi + callq __lll_mutex_unlock_wake + subq $cond_lock-cond_futex, %rdi + jmp 8b + +9: /* The futex requeue functionality is not available. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + jmp 10b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S new file mode 100644 index 000000000..bc5843564 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S @@ -0,0 +1,104 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 + +#define EINVAL 22 + + + .text + + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function + .align 16 +__pthread_cond_signal: + + /* Get internal lock. */ + movq %rdi, %r8 + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + +2: addq $cond_futex, %rdi + movq total_seq(%r8), %rcx + cmpq wakeup_seq(%r8), %rcx + jbe 4f + + /* Bump the wakeup number. */ + addq $1, wakeup_seq(%r8) + addl $1, (%rdi) + + /* Wake up one thread. */ + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + movl $1, %edx + syscall + + /* Unlock. */ +4: LOCK +#if cond_lock == 0 + decl (%r8) +#else + decl cond_lock(%r8) +#endif + jne 5f + +6: xorl %eax, %eax + retq + + /* Initial locking failed. */ +1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 2b + + /* Unlock in loop requires wakeup. */ +5: + movq %r8, %rdi + callq __lll_mutex_unlock_wake + jmp 6b + .size __pthread_cond_signal, .-__pthread_cond_signal +versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S new file mode 100644 index 000000000..ad3ae1e76 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -0,0 +1,470 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function + .align 16 +__pthread_cond_timedwait: +.LSTARTCODE: + pushq %r12 +.Lpush_r12: + pushq %r13 +.Lpush_r13: + pushq %r14 +.Lpush_r14: +#define FRAME_SIZE 80 + subq $FRAME_SIZE, %rsp +.Lsubq: + + cmpq $1000000000, 8(%rdx) + movl $EINVAL, %eax + jae 18f + + /* Stack frame: + + rsp + 80 + +--------------------------+ + rsp + 48 | cleanup buffer | + +--------------------------+ + rsp + 40 | old wake_seq value | + +--------------------------+ + rsp + 24 | timeout value | + +--------------------------+ + rsp + 16 | mutex pointer | + +--------------------------+ + rsp + 8 | condvar pointer | + +--------------------------+ + rsp + 4 | old broadcast_seq value | + +--------------------------+ + rsp + 0 | old cancellation mode | + +--------------------------+ + */ + + cmpq $-1, dep_mutex(%rdi) + + /* Prepare structure passed to cancellation handler. */ + movq %rdi, 8(%rsp) + movq %rsi, 16(%rsp) + movq %rdx, %r13 + + je 22f + movq %rsi, dep_mutex(%rdi) + + /* Get internal lock. */ +22: movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 1f + + /* Unlock the mutex. */ +2: movq 16(%rsp), %rdi + xorl %esi, %esi + callq __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 16f + + movq 8(%rsp), %rdi + incq total_seq(%rdi) + incl cond_futex(%rdi) + addl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Install cancellation handler. */ +#ifdef PIC + leaq __condvar_cleanup(%rip), %rsi +#else + leaq __condvar_cleanup, %rsi +#endif + leaq 48(%rsp), %rdi + movq %rsp, %rdx + callq __pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movq 8(%rsp), %rdi + movq wakeup_seq(%rdi), %r9 + movl broadcast_seq(%rdi), %edx + movq %r9, 40(%rsp) + movl %edx, 4(%rsp) + + /* Get the current time. */ +8: +#ifdef __NR_clock_gettime + /* Get the clock number. Note that the field in the condvar + structure stores the number minus 1. */ + movq 8(%rsp), %rdi + movl cond_nwaiters(%rdi), %edi + andl $((1 << clock_bits) - 1), %edi + /* Only clocks 0 and 1 are allowed so far. Both are handled in the + kernel. */ + leaq 24(%rsp), %rsi + movl $__NR_clock_gettime, %eax + syscall +# ifndef __ASSUME_POSIX_TIMERS + cmpq $-ENOSYS, %rax + je 19f +# endif + + /* Compute relative timeout. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq 32(%rsp), %rdx +#else + leaq 24(%rsp), %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 32(%rsp), %rax + movl $1000, %edx + mul %rdx /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq %rax, %rdx +#endif + jns 12f + addq $1000000000, %rdx + decq %rcx +12: testq %rcx, %rcx + movq 8(%rsp), %rdi + movq $-ETIMEDOUT, %r14 + js 6f + + /* Store relative timeout. */ +21: movq %rcx, 24(%rsp) + movq %rdx, 32(%rsp) + + movl cond_futex(%rdi), %r12d + + /* Unlock. */ + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 3f + +4: callq __pthread_enable_asynccancel + movl %eax, (%rsp) + + leaq 24(%rsp), %r10 +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %r12, %rdx + addq $cond_futex, %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %r14 + + movl (%rsp), %edi + callq __pthread_disable_asynccancel + + /* Lock. */ + movq 8(%rsp), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jne 5f + +6: movl broadcast_seq(%rdi), %edx + + movq woken_seq(%rdi), %rax + + movq wakeup_seq(%rdi), %r9 + + cmpl 4(%rsp), %edx + jne 23f + + cmpq 40(%rsp), %r9 + jbe 15f + + cmpq %rax, %r9 + ja 9f + +15: cmpq $-ETIMEDOUT, %r14 + jne 8b + +13: incq wakeup_seq(%rdi) + incl cond_futex(%rdi) + movl $ETIMEDOUT, %r14d + jmp 14f + +23: xorq %r14, %r14 + jmp 24f + +9: xorq %r14, %r14 +14: incq woken_seq(%rdi) + +24: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 25f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 25f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + +25: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movq 48+CLEANUP_PREV(%rsp), %rdx + movq %rdx, %fs:CLEANUP + + movq 16(%rsp), %rdi + callq __pthread_mutex_cond_lock + + testq %rax, %rax + cmoveq %r14, %rax + +18: addq $FRAME_SIZE, %rsp +.Laddq: + popq %r14 +.Lpop_r14: + popq %r13 +.Lpop_r13: + popq %r12 +.Lpop_r12: + + retq + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +16: movq 8(%rsp), %rdi + movq %rax, (%rsp) + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 17f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + +17: movq (%rsp), %rax + jmp 18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS + /* clock_gettime not available. */ +19: leaq 24(%rsp), %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 32(%rsp), %rax + movl $1000, %edx + mul %rdx /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdx + subq 24(%rsp), %rcx + subq %rax, %rdx + jns 20f + addq $1000000000, %rdx + decq %rcx +20: testq %rcx, %rcx + movq 8(%rsp), %rdi + movq $-ETIMEDOUT, %r14 + js 6b + jmp 21b +#endif +.LENDCODE: + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2) + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long L(ENDCIE)-L(STARTCIE) # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zR" # NUL-terminated augmentation + # string. +#else + .ascii "\0" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 1 # Augmentation value length. + .byte 0x1b # Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x8 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code +#else + .long .LSTARTCODE # Start address of the code. +#endif + .long .LENDCODE-.LSTARTCODE # Length of the code. +#ifdef SHARED + .uleb128 0 # No augmentation data. +#endif + .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x40+.Lpush_r13-.Lpush_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 0x8d # DW_CFA_offset %r13 + .uleb128 3 + .byte 0x40+.Lpush_r14-.Lpush_r13 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32 + .byte 0x84 # DW_CFA_offset %r14 + .uleb128 4 + .byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32+FRAME_SIZE + .byte 3 # DW_CFA_advance_loc2 + .2byte .Laddq-.Lsubq + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32 + .byte 0x40+.Lpop_r14-.Laddq # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 0xce # DW_CFA_restore %r14 + .byte 0x40+.Lpop_r13-.Lpop_r14 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0xcd # DW_CFA_restore %r13 + .byte 0x40+.Lpop_r12-.Lpop_r13 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 0xcc # DW_CFA_restore %r12 + .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 32+FRAME_SIZE + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x8d # DW_CFA_offset %r13 + .uleb128 3 + .byte 0x84 # DW_CFA_offset %r14 + .uleb128 4 + .align 8 +.LENDFDE: diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S new file mode 100644 index 000000000..b837d466b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S @@ -0,0 +1,423 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + + + .text + + .align 16 + .type __condvar_cleanup, @function + .globl __condvar_cleanup + .hidden __condvar_cleanup +__condvar_cleanup: + pushq %r12 + + /* Get internal lock. */ + movq %rdi, %r8 + movq 8(%rdi), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jz 1f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + +1: movl broadcast_seq(%rdi), %edx + cmpl 4(%r8), %edx + jne 3f + + incq wakeup_seq(%rdi) + incq woken_seq(%rdi) + incl cond_futex(%rdi) + +3: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + xorq %r12, %r12 + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 4f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 4f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + movl $1, %r12d + +4: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + je 2f +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + + /* Wake up all waiters to make sure no signal gets lost. */ +2: testq %r12, %r12 + jnz 5f + addq $cond_futex, %rdi + movl $FUTEX_WAKE, %esi + movl $0x7fffffff, %edx + movl $SYS_futex, %eax + syscall + +5: movq 16(%r8), %rdi + callq __pthread_mutex_cond_lock + + popq %r12 + + retq + .size __condvar_cleanup, .-__condvar_cleanup + + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 16 +__pthread_cond_wait: +.LSTARTCODE: + pushq %r12 +.Lpush_r12: +#define FRAME_SIZE 64 + subq $FRAME_SIZE, %rsp +.Lsubq: + /* Stack frame: + + rsp + 64 + +--------------------------+ + rsp + 32 | cleanup buffer | + +--------------------------+ + rsp + 24 | old wake_seq value | + +--------------------------+ + rsp + 16 | mutex pointer | + +--------------------------+ + rsp + 8 | condvar pointer | + +--------------------------+ + rsp + 4 | old broadcast_seq value | + +--------------------------+ + rsp + 0 | old cancellation mode | + +--------------------------+ + */ + + cmpq $-1, dep_mutex(%rdi) + + /* Prepare structure passed to cancellation handler. */ + movq %rdi, 8(%rsp) + movq %rsi, 16(%rsp) + + je 15f + movq %rsi, dep_mutex(%rdi) + + /* Get internal lock. */ +15: movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jne 1f + + /* Unlock the mutex. */ +2: movq 16(%rsp), %rdi + xorl %esi, %esi + callq __pthread_mutex_unlock_usercnt + + testl %eax, %eax + jne 12f + + movq 8(%rsp), %rdi + incq total_seq(%rdi) + incl cond_futex(%rdi) + addl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Install cancellation handler. */ +#ifdef PIC + leaq __condvar_cleanup(%rip), %rsi +#else + leaq __condvar_cleanup, %rsi +#endif + leaq 32(%rsp), %rdi + movq %rsp, %rdx + callq __pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movq 8(%rsp), %rdi + movq wakeup_seq(%rdi), %r9 + movl broadcast_seq(%rdi), %edx + movq %r9, 24(%rsp) + movl %edx, 4(%rsp) + + /* Unlock. */ +8: movl cond_futex(%rdi), %r12d + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 3f + +4: callq __pthread_enable_asynccancel + movl %eax, (%rsp) + + movq 8(%rsp), %rdi + xorq %r10, %r10 + movq %r12, %rdx + addq $cond_futex-cond_lock, %rdi + movl $SYS_futex, %eax +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + syscall + + movl (%rsp), %edi + callq __pthread_disable_asynccancel + + /* Lock. */ + movq 8(%rsp), %rdi + movl $1, %esi + xorl %eax, %eax + LOCK +#if cond_lock == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, cond_lock(%rdi) +#endif + jnz 5f + +6: movl broadcast_seq(%rdi), %edx + + movq woken_seq(%rdi), %rax + + movq wakeup_seq(%rdi), %r9 + + cmpl 4(%rsp), %edx + jne 16f + + cmpq 24(%rsp), %r9 + jbe 8b + + cmpq %rax, %r9 + jna 8b + + incq woken_seq(%rdi) + + /* Unlock */ +16: subl $(1 << clock_bits), cond_nwaiters(%rdi) + + /* Wake up a thread which wants to destroy the condvar object. */ + cmpq $0xffffffffffffffff, total_seq(%rdi) + jne 17f + movl cond_nwaiters(%rdi), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 17f + + addq $cond_nwaiters, %rdi + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + movl $1, %edx + syscall + subq $cond_nwaiters, %rdi + +17: LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: movq 32+CLEANUP_PREV(%rsp), %rdx + movq %rdx, %fs:CLEANUP + + movq 16(%rsp), %rdi + callq __pthread_mutex_cond_lock +14: addq $FRAME_SIZE, %rsp +.Laddq: + + popq %r12 +.Lpop_r12: + + /* We return the result of the mutex_lock operation. */ + retq + + /* Initial locking failed. */ +1: +.LSbl1: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires wakeup. */ +3: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_lock_wait +#if cond_lock != 0 + subq $cond_lock, %rdi +#endif + jmp 6b + + /* Unlock after loop requires wakeup. */ +10: +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + + /* The initial unlocking of the mutex failed. */ +12: movq %rax, %r10 + movq 8(%rsp), %rdi + LOCK +#if cond_lock == 0 + decl (%rdi) +#else + decl cond_lock(%rdi) +#endif + jne 13f + +#if cond_lock != 0 + addq $cond_lock, %rdi +#endif + callq __lll_mutex_unlock_wake + +13: movq %r10, %rax + jmp 14b +.LENDCODE: + .size __pthread_cond_wait, .-__pthread_cond_wait +versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2) + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long L(ENDCIE)-L(STARTCIE) # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zR" # NUL-terminated augmentation + # string. +#else + .ascii "\0" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 1 # Augmentation value length. + .byte 0x1b # Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x8 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code +#else + .long .LSTARTCODE # Start address of the code. +#endif + .long .LENDCODE-.LSTARTCODE # Length of the code. +#ifdef SHARED + .uleb128 0 # No augmentation data. +#endif + .byte 0x40+.Lpush_r12-.LSTARTCODE # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .byte 0x40+.Lsubq-.Lpush_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16+FRAME_SIZE + .byte 3 # DW_CFA_advance_loc2 + .2byte .Laddq-.Lsubq + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 0x40+.Lpop_r12-.Laddq # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 0xcc # DW_CFA_restore %r12 + .byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 80 + .byte 0x8c # DW_CFA_offset %r12 + .uleb128 2 + .align 8 +.LENDFDE: diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S new file mode 100644 index 000000000..6bf8d095b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S @@ -0,0 +1,257 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define SYS_futex 202 +#define FUTEX_WAKE 1 + + .comm __fork_generation, 4, 4 + + .text + + + .globl __pthread_once + .type __pthread_once,@function + .align 16 +__pthread_once: +.LSTARTCODE: + testl $2, (%rdi) + jz 1f + xorl %eax, %eax + retq + + /* Preserve the function pointer. */ +1: pushq %rsi +.Lpush_rsi: + xorq %r10, %r10 + + /* Not yet initialized or initialization in progress. + Get the fork generation counter now. */ +6: movl (%rdi), %eax + +5: movl %eax, %edx + + testl $2, %eax + jnz 4f + + andl $3, %edx + orl __fork_generation(%rip), %edx + orl $1, %edx + + LOCK + cmpxchgl %edx, (%rdi) + jnz 5b + + /* Check whether another thread already runs the initializer. */ + testl $1, %eax + jz 3f /* No -> do it. */ + + /* Check whether the initializer execution was interrupted + by a fork. */ + xorl %edx, %eax + testl $0xfffffffc, %eax + jnz 3f /* Different for generation -> run initializer. */ + + /* Somebody else got here first. Wait. */ +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + jmp 6b + + /* Preserve the pointer to the control variable. */ +3: pushq %rdi +.Lpush_rdi: + +.LcleanupSTART: + callq *8(%rsp) +.LcleanupEND: + + /* Get the control variable address back. */ + popq %rdi +.Lpop_rdi: + + /* Sucessful run of the initializer. Signal that we are done. */ + LOCK + incl (%rdi) + + /* Wake up all other threads. */ + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + +4: addq $8, %rsp +.Ladd: + xorl %eax, %eax + retq + + .size __pthread_once,.-__pthread_once + + + .globl __pthread_once_internal +__pthread_once_internal = __pthread_once + + .globl pthread_once +pthread_once = __pthread_once + + + .type clear_once_control,@function + .align 16 +clear_once_control: + movq (%rsp), %rdi + movq %rax, %r8 + movl $0, (%rdi) + + movl $0x7fffffff, %edx + movl $FUTEX_WAKE, %esi + movl $SYS_futex, %eax + syscall + + movq %r8, %rdi +.LcallUR: + call _Unwind_Resume@PLT + hlt +.LENDCODE: + .size clear_once_control,.-clear_once_control + + + .section .gcc_except_table,"a",@progbits +.LexceptSTART: + .byte 0xff # @LPStart format (omit) + .byte 0xff # @TType format (omit) + .byte 0x01 # call-site format + # DW_EH_PE_uleb128 + .uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: + .uleb128 .LcleanupSTART-.LSTARTCODE + .uleb128 .LcleanupEND-.LcleanupSTART + .uleb128 clear_once_control-.LSTARTCODE + .uleb128 0 + .uleb128 .LcallUR-.LSTARTCODE + .uleb128 .LENDCODE-.LcallUR + .uleb128 0 + .uleb128 0 +.Lcstend: + + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE # Length of the CIE. +.LSTARTCIE: + .long 0 # CIE ID. + .byte 1 # Version number. +#ifdef SHARED + .string "zPLR" # NUL-terminated augmentation + # string. +#else + .string "zPL" # NUL-terminated augmentation + # string. +#endif + .uleb128 1 # Code alignment factor. + .sleb128 -8 # Data alignment factor. + .byte 16 # Return address register + # column. +#ifdef SHARED + .uleb128 7 # Augmentation value length. + .byte 0x9b # Personality: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4 + # + DW_EH_PE_indirect + .long DW.ref.__gcc_personality_v0-. + .byte 0x1b # LSDA Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. + .byte 0x1b # FDE Encoding: DW_EH_PE_pcrel + # + DW_EH_PE_sdata4. +#else + .uleb128 10 # Augmentation value length. + .byte 0x0 # Personality: absolute + .quad __gcc_personality_v0 + .byte 0x0 # LSDA Encoding: absolute +#endif + .byte 0x0c # DW_CFA_def_cfa + .uleb128 7 + .uleb128 8 + .byte 0x90 # DW_CFA_offset, column 0x10 + .uleb128 1 + .align 8 +.LENDCIE: + + .long .LENDFDE-.LSTARTFDE # Length of the FDE. +.LSTARTFDE: + .long .LSTARTFDE-.LSTARTFRAME # CIE pointer. +#ifdef SHARED + .long .LSTARTCODE-. # PC-relative start address + # of the code. + .long .LENDCODE-.LSTARTCODE # Length of the code. + .uleb128 4 # Augmentation size + .long .LexceptSTART-. +#else + .quad .LSTARTCODE # Start address of the code. + .quad .LENDCODE-.LSTARTCODE # Length of the code. + .uleb128 8 # Augmentation size + .quad .LexceptSTART +#endif + .byte 4 # DW_CFA_advance_loc4 + .long .Lpush_rsi-.LSTARTCODE + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpush_rdi-.Lpush_rsi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpop_rdi-.Lpush_rdi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 + .byte 4 # DW_CFA_advance_loc4 + .long .Ladd-.Lpop_rdi + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 8 + .byte 4 # DW_CFA_advance_loc4 + .long clear_once_control-.Ladd + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 24 +#if 0 + .byte 4 # DW_CFA_advance_loc4 + .long .Lpop_rdi2-clear_once_control + .byte 14 # DW_CFA_def_cfa_offset + .uleb128 16 +#endif + .align 8 +.LENDFDE: + + +#ifdef SHARED + .hidden DW.ref.__gcc_personality_v0 + .weak DW.ref.__gcc_personality_v0 + .section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits + .align 8 + .type DW.ref.__gcc_personality_v0, @object + .size DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: + .quad __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..5e9d8fb1d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S @@ -0,0 +1,177 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> + + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_rdlock + .type __pthread_rwlock_rdlock,@function + .align 16 +__pthread_rwlock_rdlock: + xorq %r10, %r10 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%rdi), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%rdi) + je 5f + cmpl $0, FLAGS(%rdi) + je 5f + +3: incl READERS_QUEUED(%rdi) + je 4f + + movl READERS_WAKEUP(%rdi), %edx + + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 10f + +11: addq $READERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + + subq $READERS_WAKEUP, %rdi + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 12f + +13: decl READERS_QUEUED(%rdi) + jmp 2b + +5: xorl %edx, %edx + incl NR_READERS(%rdi) + je 8f +9: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 6f +7: + + movq %rdx, %rax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + /* Deadlock detected. */ + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 7b + + /* Overflow. */ +8: decl NR_READERS(%rdi) + movl $EAGAIN, %edx + jmp 9b + + /* Overflow. */ +4: decl READERS_QUEUED(%rdi) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 11b + +12: +#if MUTEX == 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 13b + .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + + .globl pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + + .globl __pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..b44660418 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S @@ -0,0 +1,220 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> + + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedrdlock + .type pthread_rwlock_timedrdlock,@function + .align 16 +pthread_rwlock_timedrdlock: + pushq %r12 + pushq %r13 + pushq %r14 + subq $16, %rsp + + movq %rdi, %r12 + movq %rsi, %r13 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%r12), %eax + testl %eax, %eax + jne 14f + cmpl $0, WRITERS_QUEUED(%r12) + je 5f + cmpl $0, FLAGS(%r12) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpq $1000000000, 8(%r13) + jae 19f + + incl READERS_QUEUED(%r12) + je 4f + + movl READERS_WAKEUP(%r12), %r14d + + /* Unlock. */ + LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 10f + + /* Get current time. */ +11: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdi + subq (%rsp), %rcx + subq %rax, %rdi + jns 15f + addq $1000000000, %rdi + decq %rcx +15: testq %rcx, %rcx + js 16f /* Time is already up. */ + + /* Futex call. */ + movq %rcx, (%rsp) /* Store relative timeout. */ + movq %rdi, 8(%rsp) + +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %rsp, %r10 + movl %r14d, %edx + leaq READERS_WAKEUP(%r12), %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rdx +17: + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%r12) +#else + cmpxchgl %esi, MUTEX(%r12) +#endif + jnz 12f + +13: decl READERS_QUEUED(%r12) + cmpq $-ETIMEDOUT, %rdx + jne 2b + +18: movl $ETIMEDOUT, %edx + jmp 9f + + +5: xorl %edx, %edx + incl NR_READERS(%r12) + je 8f +9: LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 6f + +7: movq %rdx, %rax + + addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX == 0 + movq %r12, %rdi +#else + leal MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +8: decl NR_READERS(%r12) + movl $EAGAIN, %edx + jmp 9b + + /* Overflow. */ +4: decl READERS_QUEUED(%r12) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_lock_wait + jmp 13b + +16: movq $-ETIMEDOUT, %rdx + jmp 17b + +19: movl $EINVAL, %edx + jmp 9b + .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..525e5b6b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S @@ -0,0 +1,211 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> + + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl pthread_rwlock_timedwrlock + .type pthread_rwlock_timedwrlock,@function + .align 16 +pthread_rwlock_timedwrlock: + pushq %r12 + pushq %r13 + pushq %r14 + subq $16, %rsp + + movq %rdi, %r12 + movq %rsi, %r13 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%r12), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%r12) + je 5f + + /* Check the value of the timeout parameter. */ +3: cmpq $1000000000, 8(%r13) + jae 19f + + incl WRITERS_QUEUED(%r12) + je 4f + + movl WRITERS_WAKEUP(%r12), %r14d + + LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 10f + + /* Get current time. */ +11: movq %rsp, %rdi + xorl %esi, %esi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rcx + movq 8(%r13), %rdi + subq (%rsp), %rcx + subq %rax, %rdi + jns 15f + addq $1000000000, %rdi + decq %rcx +15: testq %rcx, %rcx + js 16f /* Time is already up. */ + + /* Futex call. */ + movq %rcx, (%rsp) /* Store relative timeout. */ + movq %rdi, 8(%rsp) + +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movq %rsp, %r10 + movl %r14d, %edx + leaq WRITERS_WAKEUP(%r12), %rdi + movl $SYS_futex, %eax + syscall + movq %rax, %rdx +17: + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%r12) +#else + cmpxchgl %esi, MUTEX(%r12) +#endif + jnz 12f + +13: decl WRITERS_QUEUED(%r12) + cmpq $-ETIMEDOUT, %rdx + jne 2b + +18: movl $ETIMEDOUT, %edx + jmp 9f + + +5: xorl %edx, %edx + movl %fs:TID, %eax + movl %eax, WRITER(%r12) +9: LOCK +#if MUTEX == 0 + decl (%r12) +#else + decl MUTEX(%r12) +#endif + jne 6f + +7: movq %rdx, %rax + + addq $16, %rsp + popq %r14 + popq %r13 + popq %r12 + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b +20: movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX == 0 + movq %r12, %rdi +#else + leal MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + + /* Overflow. */ +4: decl WRITERS_QUEUED(%r12) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 11b + +12: +#if MUTEX == 0 + movq %r12, %rdi +#else + leaq MUTEX(%r12), %rdi +#endif + callq __lll_mutex_lock_wait + jmp 13b + +16: movq $-ETIMEDOUT, %rdx + jmp 17b + +19: movl $EINVAL, %edx + jmp 9b + .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S new file mode 100644 index 000000000..3a6b9f0ba --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S @@ -0,0 +1,130 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> + + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_unlock + .type __pthread_rwlock_unlock,@function + .align 16 +__pthread_rwlock_unlock: + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: cmpl $0, WRITER(%rdi) + jne 5f + decl NR_READERS(%rdi) + jnz 6f + +5: movl $0, WRITER(%rdi) + + movl $1, %esi + leaq WRITERS_WAKEUP(%rdi), %r10 + movq %rsi, %rdx + cmpl $0, WRITERS_QUEUED(%rdi) + jne 0f + + /* If also no readers waiting nothing to do. */ + cmpl $0, READERS_QUEUED(%rdi) + je 6f + + movl $0x7fffffff, %edx + leaq READERS_WAKEUP(%rdi), %r10 + +0: incl (%r10) + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 7f + +8: movl $SYS_futex, %eax + movq %r10, %rdi + syscall + + xorl %eax, %eax + retq + + .align 16 +6: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 3f + +4: xorl %eax, %eax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +3: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 4b + +7: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 8b + + .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock + + .globl pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + + .globl __pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..0e82f890a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> + + +#define SYS_futex 202 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + + .text + + .globl __pthread_rwlock_wrlock + .type __pthread_rwlock_wrlock,@function + .align 16 +__pthread_rwlock_wrlock: + xorq %r10, %r10 + + /* Get the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 1f + +2: movl WRITER(%rdi), %eax + testl %eax, %eax + jne 14f + cmpl $0, NR_READERS(%rdi) + je 5f + +3: incl WRITERS_QUEUED(%rdi) + je 4f + + movl WRITERS_WAKEUP(%rdi), %edx + + LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 10f + +11: addq $WRITERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 + xorl %esi, %esi +#else + movl $FUTEX_WAIT, %esi +#endif + movl $SYS_futex, %eax + syscall + + subq $WRITERS_WAKEUP, %rdi + + /* Reget the lock. */ + movl $1, %esi + xorl %eax, %eax + LOCK +#if MUTEX == 0 + cmpxchgl %esi, (%rdi) +#else + cmpxchgl %esi, MUTEX(%rdi) +#endif + jnz 12f + +13: decl WRITERS_QUEUED(%rdi) + jmp 2b + +5: xorl %edx, %edx + movl %fs:TID, %eax + movl %eax, WRITER(%rdi) +9: LOCK +#if MUTEX == 0 + decl (%rdi) +#else + decl MUTEX(%rdi) +#endif + jne 6f +7: + + movq %rdx, %rax + retq + +1: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 2b + +14: cmpl %fs:TID, %eax + jne 3b + movl $EDEADLK, %edx + jmp 9b + +6: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake + jmp 7b + +4: decl WRITERS_QUEUED(%rdi) + movl $EAGAIN, %edx + jmp 9b + +10: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_unlock_wake +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 11b + +12: +#if MUTEX != 0 + addq $MUTEX, %rdi +#endif + callq __lll_mutex_lock_wait +#if MUTEX != 0 + subq $MUTEX, %rdi +#endif + jmp 13b + .size __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + + .globl pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + + .globl __pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..dc811787e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include <nptl/sysdeps/x86_64/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..7da1c75dc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <nptl/sysdeps/x86_64/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S new file mode 100644 index 000000000..7f608a597 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S @@ -0,0 +1,66 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define SYS_futex 202 +#define FUTEX_WAKE 1 + + + .text + + .globl sem_post + .type sem_post,@function + .align 16 +sem_post: + movl $1, %edx + LOCK + xaddl %edx, (%rdi) + + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %esi + incl %edx + syscall + + testq %rax, %rax + js 1f + + xorl %eax, %eax + retq + +1: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl $EINVAL, %fs:(%rdx) +#else + callq __errno_location@plt + movl $EINVAL, (%rax) +#endif + + orl $-1, %eax + retq + .size sem_post,.-sem_post diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S new file mode 100644 index 000000000..c44d3f5e7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S @@ -0,0 +1,175 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define SYS_futex 202 + +/* For the calculation see asm/vsyscall.h. */ +#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000 + + + .text + + .globl sem_timedwait + .type sem_timedwait,@function + .align 16 + cfi_startproc +sem_timedwait: + /* First check for cancellation. */ + movl %fs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 11f + + movl (%rdi), %eax +2: testl %eax, %eax + je 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%rdi) + jne 2b + + xorl %eax, %eax + retq + + /* Check whether the timeout value is valid. */ +1: pushq %r12 + cfi_adjust_cfa_offset(8) + pushq %r13 + cfi_adjust_cfa_offset(8) + pushq %r14 + cfi_adjust_cfa_offset(8) + subq $24, %rsp + cfi_adjust_cfa_offset(24) + + movq %rdi, %r12 + cfi_offset(12, -16) /* %r12 */ + movq %rsi, %r13 + cfi_offset(13, -24) /* %r13 */ + + /* Check for invalid nanosecond field. */ + cmpq $1000000000, 8(%r13) + movl $EINVAL, %r14d + cfi_offset(14, -24) /* %r14 */ + jae 6f + +7: call __pthread_enable_asynccancel + movl %eax, 16(%rsp) + + xorl %esi, %esi + movq %rsp, %rdi + movq $VSYSCALL_ADDR_vgettimeofday, %rax + callq *%rax + + /* Compute relative timeout. */ + movq 8(%rsp), %rax + movl $1000, %edi + mul %rdi /* Milli seconds to nano seconds. */ + movq (%r13), %rdi + movq 8(%r13), %rsi + subq (%rsp), %rdi + subq %rax, %rsi + jns 5f + addq $1000000000, %rsi + decq %rdi +5: testq %rdi, %rdi + movl $ETIMEDOUT, %r14d + js 6f /* Time is already up. */ + + movq %rdi, (%rsp) /* Store relative timeout. */ + movq %rsi, 8(%rsp) + + movq %rsp, %r10 + movq %r12, %rdi + xorl %esi, %esi + movl $SYS_futex, %eax + xorl %edx, %edx + syscall + movq %rax, %r14 + + movl 16(%rsp), %edi + call __pthread_disable_asynccancel + + testq %r14, %r14 + je 9f + cmpq $-EWOULDBLOCK, %r14 + jne 3f + +9: movl (%r12), %eax +8: testl %eax, %eax + je 7b + + leaq -1(%rax), %rcx + LOCK + cmpxchgl %ecx, (%r12) + jne 8b + + xorl %eax, %eax +10: addq $24, %rsp + cfi_adjust_cfa_offset(-24) + popq %r14 + cfi_adjust_cfa_offset(-8) + cfi_restore(14) + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + retq + + cfi_adjust_cfa_offset(48) + cfi_offset(12, -16) /* %r12 */ + cfi_offset(13, -24) /* %r13 */ + cfi_offset(14, -32) /* %r14 */ +3: negq %r14 +6: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl %r14d, %fs:(%rdx) +#else + callq __errno_location@plt + movl %r14d, (%rax) +#endif + + orl $-1, %eax + jmp 10b + cfi_adjust_cfa_offset(-48) + cfi_restore(14) + cfi_restore(13) + cfi_restore(12) + +11: /* Canceled. */ + movq $0xffffffffffffffff, %fs:RESULT + LOCK + orl $0x10, %fs:CANCELHANDLING + movq %fs:CLEANUP_JMP_BUF, %rdi + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_timedwait,.-sem_timedwait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S new file mode 100644 index 000000000..31271bb94 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S @@ -0,0 +1,59 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + .text + + .globl sem_trywait + .type sem_trywait,@function + .align 16 +sem_trywait: + movl (%rdi), %eax +2: testl %eax, %eax + jz 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%rdi) + jne 2b + + xorl %eax, %eax + retq + +1: +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl $EAGAIN, %fs:(%rdx) +#else + callq __errno_location@plt + movl $EAGAIN, (%rax) +#endif + orl $-1, %eax + retq + .size sem_trywait,.-sem_trywait + versioned_symbol(libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S new file mode 100644 index 000000000..63ecd063a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S @@ -0,0 +1,120 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <shlib-compat.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define SYS_futex 202 + + + .text + + .globl sem_wait + .type sem_wait,@function + .align 16 + cfi_startproc +sem_wait: + /* First check for cancellation. */ + movl %fs:CANCELHANDLING, %eax + andl $0xfffffff9, %eax + cmpl $8, %eax + je 4f + + pushq %r12 + cfi_adjust_cfa_offset(8) + cfi_offset(12, -16) + pushq %r13 + cfi_adjust_cfa_offset(8) + movq %rdi, %r13 + cfi_offset(13, -24) + +3: movl (%r13), %eax +2: testl %eax, %eax + je 1f + + leaq -1(%rax), %rdx + LOCK + cmpxchgl %edx, (%r13) + jne 2b + xorl %eax, %eax + + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + + retq + + cfi_adjust_cfa_offset(16) + cfi_offset(12, -16) + cfi_offset(13, -24) +1: call __pthread_enable_asynccancel + movl %eax, %r8d + + xorq %r10, %r10 + movl $SYS_futex, %eax + movq %r13, %rdi + movq %r10, %rsi + movq %r10, %rdx + syscall + movq %rax, %r12 + + movl %r8d, %edi + call __pthread_disable_asynccancel + + testq %r12, %r12 + je 3b + cmpq $-EWOULDBLOCK, %r12 + je 3b + negq %r12 +#if USE___THREAD + movq errno@gottpoff(%rip), %rdx + movl %r12d, %fs:(%rdx) +#else + callq __errno_location@plt + movl %r12d, (%rax) +#endif + orl $-1, %eax + + popq %r13 + cfi_adjust_cfa_offset(-8) + cfi_restore(13) + popq %r12 + cfi_adjust_cfa_offset(-8) + cfi_restore(12) + + retq + +4: /* Canceled. */ + movq $0xffffffffffffffff, %fs:RESULT + LOCK + orl $0x10, %fs:CANCELHANDLING + movq %fs:CLEANUP_JMP_BUF, %rdi + jmp HIDDEN_JUMPTARGET (__pthread_unwind) + cfi_endproc + .size sem_wait,.-sem_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h new file mode 100644 index 000000000..97debaba9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + SINGLE_THREAD_P; \ + jne L(pseudo_cancel); \ + .type __##syscall_name##_nocancel,@function; \ + .globl __##syscall_name##_nocancel; \ + __##syscall_name##_nocancel: \ + DO_CALL (syscall_name, args); \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + ret; \ + .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + L(pseudo_cancel): \ + /* Save registers that might get destroyed. */ \ + SAVESTK_##args \ + PUSHARGS_##args \ + CENABLE \ + /* Restore registers. */ \ + POPARGS_##args \ + /* The return value from CENABLE is argument for CDISABLE. */ \ + movq %rax, (%rsp); \ + movl $SYS_ify (syscall_name), %eax; \ + syscall; \ + movq (%rsp), %rdi; \ + /* Save %rax since it's the error code from the syscall. */ \ + movq %rax, 8(%rsp); \ + CDISABLE \ + movq 8(%rsp), %rax; \ + RESTSTK_##args \ + cmpq $-4095, %rax; \ + jae SYSCALL_ERROR_LABEL; \ + L(pseudo_end): + + +# define PUSHARGS_0 /* Nothing. */ +# define PUSHARGS_1 PUSHARGS_0 movq %rdi, 8(%rsp); +# define PUSHARGS_2 PUSHARGS_1 movq %rsi, 16(%rsp); +# define PUSHARGS_3 PUSHARGS_2 movq %rdx, 24(%rsp); +# define PUSHARGS_4 PUSHARGS_3 movq %rcx, 32(%rsp); +# define PUSHARGS_5 PUSHARGS_4 movq %r8, 40(%rsp); +# define PUSHARGS_6 PUSHARGS_5 movq %r9, 48(%rsp); + +# define POPARGS_0 /* Nothing. */ +# define POPARGS_1 POPARGS_0 movq 8(%rsp), %rdi; +# define POPARGS_2 POPARGS_1 movq 16(%rsp), %rsi; +# define POPARGS_3 POPARGS_2 movq 24(%rsp), %rdx; +# define POPARGS_4 POPARGS_3 movq 32(%rsp), %r10; +# define POPARGS_5 POPARGS_4 movq 40(%rsp), %r8; +# define POPARGS_6 POPARGS_5 movq 48(%rsp), %r9; + +/* We always have to align the stack before calling a function. */ +# define SAVESTK_0 subq $24, %rsp; cfi_adjust_cfa_offset (24); +# define SAVESTK_1 SAVESTK_0 +# define SAVESTK_2 SAVESTK_1 +# define SAVESTK_3 subq $40, %rsp; cfi_adjust_cfa_offset (40); +# define SAVESTK_4 SAVESTK_3 +# define SAVESTK_5 subq $56, %rsp; cfi_adjust_cfa_offset (56); +# define SAVESTK_6 SAVESTK_5 + +# define RESTSTK_0 addq $24,%rsp; cfi_adjust_cfa_offset (-24); +# define RESTSTK_1 RESTSTK_0 +# define RESTSTK_2 RESTSTK_1 +# define RESTSTK_3 addq $40, %rsp; cfi_adjust_cfa_offset (-40); +# define RESTSTK_4 RESTSTK_3 +# define RESTSTK_5 addq $56, %rsp; cfi_adjust_cfa_offset (-56); +# define RESTSTK_6 RESTSTK_5 + +# ifdef IS_IN_libpthread +# define CENABLE call __pthread_enable_asynccancel; +# define CDISABLE call __pthread_disable_asynccancel; +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE call __libc_enable_asynccancel; +# define CDISABLE call __libc_disable_asynccancel; +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE call __librt_enable_asynccancel; +# define CDISABLE call __librt_disable_asynccancel; +# else +# error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P \ + __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, __local_multiple_threads(%rip) +# endif + +# else + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET +# endif + +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_create.c new file mode 100644 index 000000000..a07b1afe5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_create.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "compat-timer.h" +#include <atomic.h> + + +#define timer_create_alias __timer_create_new +#include "../timer_create.c" + +#undef timer_create +weak_alias(__timer_create_new, timer_create) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_delete.c new file mode 100644 index 000000000..8456dc31a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_delete.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "compat-timer.h" + + +#define timer_delete_alias __timer_delete_new +#include "../timer_delete.c" + +#undef timer_delete +weak_alias(__timer_delete_new, timer_delete) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c new file mode 100644 index 000000000..86a2df696 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "compat-timer.h" + + +#define timer_getoverrun_alias __timer_getoverrun_new +#include "../timer_getoverr.c" + +#undef timer_getoverrun +weak_alias(__timer_getoverrun_new, timer_getoverrun) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_gettime.c new file mode 100644 index 000000000..6b260e453 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_gettime.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "compat-timer.h" + + +#define timer_gettime_alias __timer_gettime_new +#include "../timer_gettime.c" + +#undef timer_gettime +weak_alias(__timer_gettime_new, timer_gettime) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_settime.c new file mode 100644 index 000000000..0ec178246 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/timer_settime.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "compat-timer.h" + + +#define timer_settime_alias __timer_settime_new +#include "../timer_settime.c" + +#undef timer_settime +weak_alias(__timer_settime_new, timer_settime) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S new file mode 100644 index 000000000..f68d40439 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -0,0 +1,35 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <tcb-offsets.h> + +#define SAVE_PID \ + movl %fs:PID, %esi; \ + movl $0x80000000, %ecx; \ + movl %esi, %edx; \ + negl %edx; \ + cmove %ecx, %edx; \ + movl %edx, %fs:PID + +#define RESTORE_PID \ + testq %rax, %rax; \ + je 1f; \ + movl %esi, %fs:PID; \ +1: + +#include <sysdeps/unix/sysv/linux/x86_64/vfork.S> diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile b/libpthread/nptl/sysdeps/x86_64/Makefile new file mode 100644 index 000000000..6e24a26cd --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile @@ -0,0 +1,28 @@ +# Copyright (C) 2002, 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, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +# P4s have problems with 4M aliasing. We disturb the allocation of stacks +# just enough so the subsequent allocations do not use stack address +# (mod 4M) == 0. +CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536 +endif diff --git a/libpthread/nptl/sysdeps/x86_64/dl-tls.h b/libpthread/nptl/sysdeps/x86_64/dl-tls.h new file mode 100644 index 000000000..3e4768dc1 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + Copyright (C) 2002 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h new file mode 100644 index 000000000..345ed557c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..55696204c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_init.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c new file mode 100644 index 000000000..7cf0e0ecc --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_lock.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S new file mode 100644 index 000000000..9b5133583 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 16 +pthread_spin_trylock: + movl $1, %eax + xorl %ecx, %ecx + LOCK + cmpxchgl %ecx, (%rdi) + movl $EBUSY, %eax + cmovel %ecx, %eax + retq + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..d3e13bde9 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl $1, (%rdi) + xorl %eax, %eax + retq + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/x86_64/pthreaddef.h b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h new file mode 100644 index 000000000..27896a445 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. The frame pointer is not usable. */ +#define CURRENT_STACK_FRAME \ + ({ char *frame; asm ("movq %%rsp, %0" : "=r" (frame)); frame; }) + + +/* We prefer to have the stack allocated in the low 4GB since this + allows faster context switches. */ +#define ARCH_MAP_FLAGS MAP_32BIT + +/* If it is not possible to allocate memory there retry without that + flag. */ +#define ARCH_RETRY_MMAP(size) \ + mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, \ + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + asm volatile ("syscall" :: "a" (__NR_exit), "D" (val)) diff --git a/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym new file mode 100644 index 000000000..8118d2df8 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,12 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +CLEANUP offsetof (struct pthread, cleanup) +CLEANUP_PREV offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/libpthread/nptl/sysdeps/x86_64/tls.h b/libpthread/nptl/sysdeps/x86_64/tls.h new file mode 100644 index 000000000..516827b8e --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tls.h @@ -0,0 +1,334 @@ +/* Definition for thread-local data handling. nptl/x86_64 version. + Copyright (C) 2002, 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#include <asm/prctl.h> /* For ARCH_SET_FS. */ +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> + + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; + uintptr_t sysinfo; + uintptr_t stack_guard; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools. */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Alignment requirement for the stack. */ +#define STACK_ALIGN 16 + + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + + +/* Get the thread descriptor definition. */ +# include <nptl/descr.h> + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ struct pthread *__pd; \ + THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + + +/* Macros to load from and store into segment registers. */ +# define TLS_GET_FS() \ + ({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; }) +# define TLS_SET_FS(val) \ + __asm ("movl %0, %%fs" :: "q" (val)) + + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. + + We have to make the syscall for both uses of the macro since the + address might be (and probably is) different. */ +# define TLS_INIT_TP(thrdescr, secondcall) \ + ({ void *_thrdescr = (thrdescr); \ + tcbhead_t *_head = _thrdescr; \ + int _result; \ + \ + _head->tcb = _thrdescr; \ + /* For now the thread descriptor is at the same address. */ \ + _head->self = _thrdescr; \ + \ + /* It is a simple syscall to set the %fs value for the thread. */ \ + asm volatile ("syscall" \ + : "=a" (_result) \ + : "0" ((unsigned long int) __NR_arch_prctl), \ + "D" ((unsigned long int) ARCH_SET_FS), \ + "S" (_thrdescr) \ + : "memory", "cc", "r11", "cx"); \ + \ + _result ? "cannot set %fs base address for thread-local storage" : 0; \ + }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct pthread *__pd; \ + THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__self; \ + asm ("movq %%fs:%c1,%q0" : "=r" (__self) \ + : "i" (offsetof (struct pthread, header.self))); \ + __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF_INCLUDE <sys/reg.h> /* For the FS constant. */ +# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) \ + ({ __typeof (descr->member) __value; \ + if (sizeof (__value) == 1) \ + asm volatile ("movb %%fs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member))); \ + else if (sizeof (__value) == 4) \ + asm volatile ("movl %%fs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + asm volatile ("movq %%fs:%P1,%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + } \ + __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ({ __typeof (descr->member[0]) __value; \ + if (sizeof (__value) == 1) \ + asm volatile ("movb %%fs:%P2(%q3),%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (__value) == 4) \ + asm volatile ("movl %%fs:%P1(,%q2,4),%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + } \ + __value; }) + + +/* Loading addresses of objects on x86-64 needs to be treated special + when generating PIC code. */ +#ifdef __pic__ +# define IMM_MODE "nr" +#else +# define IMM_MODE "ir" +#endif + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM(descr, member, value) \ + ({ if (sizeof (descr->member) == 1) \ + asm volatile ("movb %b0,%%fs:%P1" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member))); \ + else if (sizeof (descr->member) == 4) \ + asm volatile ("movl %0,%%fs:%P1" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (descr->member) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + asm volatile ("movq %q0,%%fs:%P1" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member))); \ + }}) + + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ({ if (sizeof (descr->member[0]) == 1) \ + asm volatile ("movb %b0,%%fs:%P1(%q2)" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (descr->member[0]) == 4) \ + asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (descr->member[0]) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + }}) + + +/* Atomic compare and exchange on TLS, returning old value. */ +#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ + ({ __typeof (descr->member) __ret; \ + __typeof (oldval) __old = (oldval); \ + if (sizeof (descr->member) == 4) \ + asm volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3" \ + : "=a" (__ret) \ + : "0" (__old), "r" (newval), \ + "i" (offsetof (struct pthread, member))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); \ + __ret; }) + + +/* Atomic set bit. */ +#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + asm volatile (LOCK_PREFIX "orl %1, %%fs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (1 << (bit))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +#define CALL_THREAD_FCT(descr) \ + ({ void *__res; \ + asm volatile ("movq %%fs:%P2, %%rdi\n\t" \ + "callq *%%fs:%P1" \ + : "=a" (__res) \ + : "i" (offsetof (struct pthread, start_routine)), \ + "i" (offsetof (struct pthread, arg)) \ + : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11", \ + "memory", "cc"); \ + __res; }) + + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/unwind.c b/libpthread/nptl/unwind.c new file mode 100644 index 000000000..56a423815 --- /dev/null +++ b/libpthread/nptl/unwind.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com> + and Richard Henderson <rth@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "pthreadP.h" +#include "jmpbuf-unwind.h" + +#ifdef HAVE_FORCED_UNWIND + +#ifdef _STACK_GROWS_DOWN +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj >= (uintptr_t) other - adj) +#elif _STACK_GROWS_UP +# define FRAME_LEFT(frame, other, adj) \ + ((uintptr_t) frame - adj <= (uintptr_t) other - adj) +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + +static _Unwind_Reason_Code +unwind_stop (int version, _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + struct _Unwind_Exception *exc_obj, + struct _Unwind_Context *context, void *stop_parameter) +{ + struct pthread_unwind_buf *buf = stop_parameter; + struct pthread *self = THREAD_SELF; + struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); + int do_longjump = 0; + + /* Adjust all pointers used in comparisons, so that top of thread's + stack is at the top of address space. Without that, things break + if stack is allocated above the main stack. */ + uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; + + /* Do longjmp if we're at "end of stack", aka "end of unwind data". + We assume there are only C frame without unwind data in between + here and the jmp_buf target. Otherwise simply note that the CFA + of a function is NOT within it's stack frame; it's the SP of the + previous frame. */ + if ((actions & _UA_END_OF_STACK) + || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context, + adj)) + do_longjump = 1; + + if (__builtin_expect (curp != NULL, 0)) + { + /* Handle the compatibility stuff. Execute all handlers + registered with the old method which would be unwound by this + step. */ + struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup; + void *cfa = (void *) _Unwind_GetCFA (context); + + if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj))) + { + do + { + /* Pointer to the next element. */ + struct _pthread_cleanup_buffer *nextp = curp->__prev; + + /* Call the handler. */ + curp->__routine (curp->__arg); + + /* To the next. */ + curp = nextp; + } + while (curp != oldp + && (do_longjump || FRAME_LEFT (cfa, curp, adj))); + + /* Mark the current element as handled. */ + THREAD_SETMEM (self, cleanup, curp); + } + } + + if (do_longjump) + __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1); + + return _URC_NO_REASON; +} + + +static void +unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) +{ + /* When we get here a C++ catch block didn't rethrow the object. We + cannot handle this case and therefore abort. */ +# define STR_N_LEN(str) str, strlen (str) + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, + STR_N_LEN ("FATAL: exception not rethrown\n")); + abort (); +} + +#endif /* have forced unwind */ + + +void +__cleanup_fct_attribute __attribute ((noreturn)) +__pthread_unwind (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + struct pthread *self = THREAD_SELF; + +#ifdef HAVE_FORCED_UNWIND + /* This is not a catchable exception, so don't provide any details about + the exception type. We do need to initialize the field though. */ + THREAD_SETMEM (self, exc.exception_class, 0); + THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup); + + _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf); +#else + /* Handle the compatibility stuff first. Execute all handlers + registered with the old method. We don't execute them in order, + instead, they will run first. */ + struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup; + struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); + + if (curp != oldp) + { + do + { + /* Pointer to the next element. */ + struct _pthread_cleanup_buffer *nextp = curp->__prev; + + /* Call the handler. */ + curp->__routine (curp->__arg); + + /* To the next. */ + curp = nextp; + } + while (curp != oldp); + + /* Mark the current element as handled. */ + THREAD_SETMEM (self, cleanup, curp); + } + + /* We simply jump to the registered setjmp buffer. */ + __libc_unwind_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1); +#endif + /* NOTREACHED */ + + /* We better do not get here. */ + abort (); +} +hidden_def (__pthread_unwind) + + +void +__cleanup_fct_attribute __attribute ((noreturn)) +__pthread_unwind_next (__pthread_unwind_buf_t *buf) +{ + struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; + + __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev); +} +hidden_def (__pthread_unwind_next) diff --git a/libpthread/nptl/vars.c b/libpthread/nptl/vars.c new file mode 100644 index 000000000..c4306737f --- /dev/null +++ b/libpthread/nptl/vars.c @@ -0,0 +1,43 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthreadP.h> +#include <stdlib.h> +#include <tls.h> +#include <unistd.h> + +/* Default stack size. */ +size_t __default_stacksize attribute_hidden +#ifdef SHARED +; +#else + = PTHREAD_STACK_MIN; +#endif + +/* Flag whether the machine is SMP or not. */ +int __is_smp attribute_hidden; + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Variable set to a nonzero value if more than one thread runs or ran. */ +int __pthread_multiple_threads attribute_hidden; +#endif + +/* Table of the key information. */ +struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX] + __attribute__ ((nocommon)); +hidden_def (__pthread_keys) diff --git a/libpthread/nptl/version.c b/libpthread/nptl/version.c new file mode 100644 index 000000000..f2fd25fd6 --- /dev/null +++ b/libpthread/nptl/version.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> +#include <sysdep.h> + + +static const char banner[] = +#include "banner.h" +"Copyright (C) 2003 Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ +PARTICULAR PURPOSE.\n" +#ifdef HAVE_FORCED_UNWIND +"Forced unwind support included.\n" +#endif +; + + +extern void __nptl_main (void) __attribute__ ((noreturn)); +void +__nptl_main (void) +{ + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (write, err, 3, STDOUT_FILENO, (const char *) banner, + sizeof banner - 1); + + _exit (0); +} diff --git a/libpthread/nptl/version.h b/libpthread/nptl/version.h new file mode 100644 index 000000000..f294f5c97 --- /dev/null +++ b/libpthread/nptl/version.h @@ -0,0 +1 @@ +#define VERSION __stringify(__UCLIBC_MAJOR__) "." __stringify(__UCLIBC_MINOR__) "." __stringify(__UCLIBC_SUBLEVEL__) diff --git a/libpthread/nptl_db/ChangeLog b/libpthread/nptl_db/ChangeLog new file mode 100644 index 000000000..52c849138 --- /dev/null +++ b/libpthread/nptl_db/ChangeLog @@ -0,0 +1,207 @@ +2004-09-09 Roland McGrath <roland@redhat.com> + + * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Don't abort if inferior's + descriptor is bogus. + +2004-05-27 Roland McGrath <roland@redhat.com> + + * td_thr_validate.c: When we find no threads and the inferior appears + uninitialized, validate the main thread as a special case. + +2004-05-01 Jakub Jelinek <jakub@redhat.com> + + * thread_dbP.h (LOG): Use write instead of __libc_write. + +2004-04-03 Ulrich Drepper <drepper@redhat.com> + + * td_ta_set_event.c (td_ta_set_event): Initialize copy to avoid + warnings. + + * td_ta_thr_iter.c (td_ta_thr_iter): Initialize list to avoid warning. + * td_ta_clear_event.c (td_ta_clear_event): Initialize eventmask to + avoid warning. + * td_ta_set_event.c (td_ta_set_event): Likewise. + +2004-03-24 Roland McGrath <roland@redhat.com> + + * fetch-value.c (_td_locate_field): Cast DB_DESC_OFFSET to int32_t. + * thread_dbP.h (DB_DESC_OFFSET): Remove cast from definition. + +2004-03-13 Jakub Jelinek <jakub@redhat.com> + + * db_info.c: Don't use TLS_TP_OFFSET in the #if, but + TLS_TCB_SIZE == 0 ?: in the DESC macro. + +2004-03-12 Roland McGrath <roland@redhat.com> + + * db_info.c [TLS_DTV_AT_TP && TLS_TP_OFFSET > 0] + (_thread_db_pthread_dtvp): Define differently for this case (PowerPC). + +2003-12-11 Ulrich Weigand <uweigand@de.ibm.com> + + * db_info.c (REGISTER): Add bit size of thread register as second + parameter to REGISTER macro. + +2003-12-02 Roland McGrath <roland@redhat.com> + + * thread_dbP.h (DB_FUNCTION): New macro. + * structs.def: Use it for __nptl_create_event and __nptl_death_event. + * db_info.c (DB_FUNCTION): New macro. + * td_symbol_list.c (DB_FUNCTION): New macro, prepend "." to symbol + name under [HAVE_ASM_GLOBAL_DOT_NAME]. + (td_lookup) [HAVE_ASM_GLOBAL_DOT_NAME]: If lookup fails with PS_NOSYM + and name starts with a dot, try it without the dot. + +2003-09-08 Roland McGrath <roland@redhat.com> + + * td_thr_get_info.c (td_thr_get_info): Cast th_unique to thread_t. + +2003-08-22 Roland McGrath <roland@redhat.com> + + * fetch-value.c (_td_check_sizeof, _td_locate_field): Return + TD_NOCAPAB for PS_NOSYM, instead of vanilla TD_ERR. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Return TD_NOAPLIC when + DB_GET_FIELD returns TD_NOCAPAB. + + * thread_db.h (td_thr_tls_get_addr): Use psaddr_t in signature. + * structs.def [USE_TLS]: Add DB_STRUCT_FIELD (link_map, l_tls_modid). + * db_info.c (link_map): Typedef it. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Rewritten. + +2003-08-14 Roland McGrath <roland@redhat.com> + + * thread_dbP.h: Mostly rewritten with many new macros and decls. + * td_ta_new.c (td_ta_new): Don't cache a lot of symbol values. + * structs.def: New file. + * db_info.c: New file. + * td_symbol_list.c (symbol_list_arr): Define with structs.def macros. + * td_ta_clear_event.c: Rewritten. + * td_ta_event_addr.c: Rewritten. + * td_ta_event_getmsg.c: Rewritten. + * td_ta_get_nthreads.c: Rewritten. + * td_ta_map_lwp2thr.c: New file. + * td_ta_set_event.c: Rewritten. + * td_ta_thr_iter.c: Rewritten. + * td_ta_tsd_iter.c: Rewritten. + * td_thr_clear_event.c: Rewritten. + * td_thr_event_enable.c: Rewritten. + * td_thr_event_getmsg.c: Rewritten. + * td_thr_get_info.c: Rewritten. + * td_thr_getfpregs.c: Rewritten. + * td_thr_getgregs.c: Rewritten. + * td_thr_set_event.c: Rewritten. + * td_thr_setfpregs.c: Rewritten. + * td_thr_setgregs.c: Rewritten. + * td_thr_tlsbase.c: Rewritten. + * td_thr_tsd.c: Rewritten. + * td_thr_validate.c: Rewritten. + * Makefile (distribute): Add them. + * fetch-value.c: New file. + * Makefile (libthread_db-routines): Add it. + + * thread_db.h (td_err_e): Comment fix. + +2003-08-05 Roland McGrath <roland@redhat.com> + + * thread_dbP.h (td_lookup): Add attribute_hidden to decl. + +2003-08-04 Roland McGrath <roland@redhat.com> + + * td_ta_clear_event.c (td_ta_clear_event): Fix sizes in ps_* calls. + +2003-06-23 Roland McGrath <roland@redhat.com> + + * proc_service.h: Cosmetic and comment fixes. + +2003-06-19 Roland McGrath <roland@redhat.com> + + * td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool' + for value written into inferior's `report_events'. + +2003-03-18 Roland McGrath <roland@redhat.com> + + * td_thr_event_getmsg.c (td_thr_event_getmsg): Splice the thread out + of the ->nextevent linkage. + + * td_ta_event_getmsg.c (td_ta_event_getmsg): Runtime error instead of + assert for reading TD_EVENT_NONE. Clear the event buffer after + reading it. Add a sanity check for foo->nextevent = foo. + +2003-03-15 Roland McGrath <roland@redhat.com> + + * thread_db.h (td_err_e): Add TD_NOTLS and TD_TLSDEFER. + (td_thr_tlsbase): Declare it. + * td_thr_tlsbase.c: New file. + * Makefile (libthread_db-routines): Add it. + * Versions (libthread_db: GLIBC_2.3.3): New set, add td_thr_tlsbase. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use td_thr_tlsbase. + +2003-03-14 Roland McGrath <roland@redhat.com> + + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Use `header.' prefix. + +2003-03-10 Roland McGrath <roland@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): Don't use `header.data.' + prefix for `struct pthread' members. + * td_thr_validate.c (check_thread_list): Likewise. + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Likewise. + +2003-03-03 Roland McGrath <roland@redhat.com> + + * td_thr_tls_get_addr.c (td_thr_tls_get_addr): Handle TLS_DTV_AT_TP. + +2003-02-15 Ulrich Drepper <drepper@redhat.com> + + * td_symbol_list.c: New symbol name for SYM_PTHREAD_NTHREADS. + +2003-01-07 Jakub Jelinek <jakub@redhat.com> + + * td_ta_event_getmsg.c: Include assert.h. + +-2003-01-05 Ulrich Drepper <drepper@redhat.com> + + * Makefile (libthread_db.so-no-z-defs): Define. + +2003-01-03 Roland McGrath <roland@redhat.com> + + * td_thr_setgregs.c (td_thr_setgregs): *_BIT -> *_BITMASK + * td_thr_setfpregs.c (td_thr_setfpregs): Likewise. + * td_thr_get_info.c (td_thr_get_info): Likewise. + * td_thr_getgregs.c (td_thr_getgregs): Likewise. + * td_thr_getfpregs.c (td_thr_getfpregs): Likewise. + * td_ta_thr_iter.c (iterate_thread_list): Likewise. + +2002-12-12 Roland McGrath <roland@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): Handle special case of + uninitialized __stack_user (zeros), hard-wire just the main thread. + + * td_thr_get_info.c (td_thr_get_info): Fix ti_lid initialization. + +2002-12-06 Roland McGrath <roland@redhat.com> + + * td_ta_event_getmsg.c (td_ta_event_getmsg): Write the NEXT pointer + into the inferior's __pthread_last_event variable, not a word from + an inferior address used in the parent. Pass the address of a + null word to ps_pdwrite, not a null pointer. + +2002-12-04 Roland McGrath <roland@redhat.com> + + * td_thr_get_info.c (td_thr_get_info): ti_tid is pthread_t, not a PID. + + * thread_db.h (td_thrinfo_t): Comment fix. + + * td_ta_map_lwp2thr.c: Moved to ../nptl/sysdeps/i386/. + +2002-12-04 Ulrich Drepper <drepper@redhat.com> + + * td_ta_thr_iter.c (iterate_thread_list): At end of iteration read + pointer to the next element from inferior. + +2002-12-02 Roland McGrath <roland@redhat.com> + + * td_symbol_list.c (symbol_list_arr): pthread_keys -> __pthread_keys + + * td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Fetch inferior registers to + see its %gs value, not our own. diff --git a/libpthread/nptl_db/Makefile b/libpthread/nptl_db/Makefile new file mode 100644 index 000000000..f9100219a --- /dev/null +++ b/libpthread/nptl_db/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../ +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl_db/Makefile.in b/libpthread/nptl_db/Makefile.in new file mode 100644 index 000000000..3eaded59f --- /dev/null +++ b/libpthread/nptl_db/Makefile.in @@ -0,0 +1,71 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +subdirs += libpthread/nptl/nptl_db + +# Get the thread include dependencies and shared object name +CFLAGS-nptl_db := -DLIBPTHREAD_SO="\"libpthread.so.$(MAJOR_VERSION)\"" +CFLAGS-nptl_db += -I$(top_srcdir)libpthread/nptl -D_GNU_SOURCE +CFLAGS-nptl_db += -DIS_IN_libthread_db=1 -std=gnu99 -I$(top_srcdir)ldso/include + +LDFLAGS-libthread_db.so := $(LDFLAGS_NOSTRIP) -s --warn-unresolved-symbols + +LIBS-libthread_db.so := $(LIBS) + +libthread_db_FULL_NAME := libthread_db-$(VERSION).so + +libthread_db_DIR := $(top_srcdir)libpthread/nptl_db +libthread_db_OUT := $(top_builddir)libpthread/nptl_db + +libthread_db_SRC := $(wildcard $(libthread_db_DIR)/td_*.c) \ + $(libthread_db_DIR)/fetch-value.c + +libthread_db_OBJ := $(patsubst $(libthread_db_DIR)/%.c,$(libthread_db_OUT)/%.o,$(libthread_db_SRC)) + +libthread_db-so-y := $(libthread_db_OBJ:.o=.oS) +ifeq ($(DOPIC),y) +libthread_db-a-y := $(libthread_db-so-y) +else +libthread_db-a-y := $(libthread_db_OBJ) +endif + +libthread_db-multi-y := $(libthread_db_SRC) + +lib-a-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.a +lib-so-$(PTHREADS_DEBUG_SUPPORT) += $(top_builddir)lib/libthread_db.so +objclean-y += libthread_db_clean +headers-$(PTHREADS_DEBUG_SUPPORT) += $(nptl_db_headers) +headers_clean-y += nptl_db_headers_clean + +ifeq ($(DOPIC),y) +$(top_builddir)lib/libthread_db.so: $(top_builddir)lib/libthread_db.a $(libc) +else +$(top_builddir)lib/libthread_db.so: $(libthread_db_OUT)/libthread_db_so.a $(libc) +endif + $(call link.so,$(libthread_db_FULL_NAME),1) + +$(libthread_db_OUT)/libthread_db_so.a: $(libthread_db-so-y) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +$(top_builddir)lib/libthread_db.a: $(libthread_db-a-y) + $(Q)$(INSTALL) -d $(dir $@) + $(Q)$(RM) $@ + $(do_strip) + $(do_ar) + +$(top_builddir)include/thread_db.h: + $(do_ln) $(call rel_srcdir)$(PTDIR)_db/$(@F) $@ + +nptl_db_headers:= $(top_builddir)include/thread_db.h + +nptl_db_headers_clean: + $(do_rm) $(nptl_db_headers) + +libthread_db_clean: + $(do_rm) $(addprefix $(libthread_db_OUT)/*., o oS a) diff --git a/libpthread/nptl_db/db_info.c b/libpthread/nptl_db/db_info.c new file mode 100644 index 000000000..5aec152d5 --- /dev/null +++ b/libpthread/nptl_db/db_info.c @@ -0,0 +1,103 @@ +/* This file is included by pthread_create.c to define in libpthread + all the magic symbols required by libthread_db. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <tls.h> + +typedef struct pthread pthread; +typedef struct pthread_key_struct pthread_key_struct; +typedef struct pthread_key_data pthread_key_data; +typedef struct +{ + struct pthread_key_data data[PTHREAD_KEY_2NDLEVEL_SIZE]; +} +pthread_key_data_level2; + +typedef struct +{ + union dtv dtv[UINT32_MAX / 2 / sizeof (union dtv)]; /* No constant bound. */ +} dtv; + +typedef struct link_map link_map; + + +#define schedparam_sched_priority schedparam.sched_priority + +#define eventbuf_eventmask eventbuf.eventmask +#define eventbuf_eventmask_event_bits eventbuf.eventmask.event_bits + +#define DESC(name, offset, obj) \ + DB_DEFINE_DESC (name, 8 * sizeof (obj), 1, offset); +#define ARRAY_DESC(name, offset, obj) \ + DB_DEFINE_DESC (name, \ + 8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \ + offset); + +#if defined(TLS_TCB_AT_TP) +# define dtvp header.dtv +#elif defined(TLS_DTV_AT_TP) +/* Special case hack. If TLS_TCB_SIZE == 0 (on PowerPC), there is no TCB + containing the DTV at the TP, but actually the TCB lies behind the TP, + i.e. at the very end of the area covered by TLS_PRE_TCB_SIZE. */ +DESC (_thread_db_pthread_dtvp, + TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv) + - (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), union dtv) +#endif + + +#define DB_STRUCT(type) \ + const uint32_t _thread_db_sizeof_##type = sizeof (type); +#define DB_STRUCT_FIELD(type, field) \ + DESC (_thread_db_##type##_##field, \ + offsetof (type, field), ((type *) 0)->field) +#define DB_STRUCT_ARRAY_FIELD(type, field) \ + ARRAY_DESC (_thread_db_##type##_##field, \ + offsetof (type, field), ((type *) 0)->field) +#define DB_VARIABLE(name) DESC (_thread_db_##name, 0, name) +#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (_thread_db_##name, 0, name) +#define DB_SYMBOL(name) /* Nothing. */ +#define DB_FUNCTION(name) /* Nothing. */ +#include "structs.def" +#undef DB_STRUCT +#undef DB_STRUCT_FIELD +#undef DB_SYMBOL +#undef DB_FUNCTION +#undef DB_VARIABLE +#undef DESC + + + +#ifdef DB_THREAD_SELF +# ifdef DB_THREAD_SELF_INCLUDE +# include DB_THREAD_SELF_INCLUDE +# endif + +/* This macro is defined in the machine's tls.h using the three below. */ +# define CONST_THREAD_AREA(bits, value) \ + const uint32_t _thread_db_const_thread_area = (value); +# define REGISTER_THREAD_AREA(bits, regofs, scale) \ + DB_DEFINE_DESC (_thread_db_register##bits##_thread_area, \ + bits, (scale), (regofs)); +# define REGISTER(bits, size, regofs, bias) \ + DB_DEFINE_DESC (_thread_db_register##bits, size, (uint32_t)(bias), (regofs)); + +DB_THREAD_SELF +#endif diff --git a/libpthread/nptl_db/fetch-value.c b/libpthread/nptl_db/fetch-value.c new file mode 100644 index 000000000..0d9bb0eb8 --- /dev/null +++ b/libpthread/nptl_db/fetch-value.c @@ -0,0 +1,284 @@ +/* Helper routines for libthread_db. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <byteswap.h> +#include <assert.h> + +td_err_e +_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name) +{ + if (*sizep == 0) + { + psaddr_t descptr; + ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr); + if (err == PS_NOSYM) + return TD_NOCAPAB; + if (err == PS_OK) + err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep); + if (err != PS_OK) + return TD_ERR; + if (*sizep & 0xff000000U) + *sizep = bswap_32 (*sizep); + } + return TD_OK; +} + +td_err_e +_td_locate_field (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, psaddr_t *address) +{ + uint32_t elemsize; + + if (DB_DESC_SIZE (desc) == 0) + { + /* Read the information about this field from the inferior. */ + psaddr_t descptr; + ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr); + if (err == PS_NOSYM) + return TD_NOCAPAB; + if (err == PS_OK) + err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC); + if (err != PS_OK) + return TD_ERR; + if (DB_DESC_SIZE (desc) == 0) + return TD_DBERR; + if (DB_DESC_SIZE (desc) & 0xff000000U) + { + /* Byte-swap these words, though we leave the size word + in native order as the handy way to distinguish. */ + DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc)); + DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc)); + } + } + + if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc)) + /* This is an internal indicator to callers with nonzero IDX + that the IDX value is too big. */ + return TD_NOAPLIC; + + elemsize = DB_DESC_SIZE (desc); + if (elemsize & 0xff000000U) + elemsize = bswap_32 (elemsize); + + *address += (int32_t) DB_DESC_OFFSET (desc); + *address += (elemsize / 8 * (idx - (psaddr_t) 0)); + return TD_OK; +} + +td_err_e +_td_fetch_value (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t *result) +{ + ps_err_e err; + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdread (ta->ph, address, &value, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value; + err = ps_pdread (ta->ph, address, &value, sizeof value); + value = bswap_32 (value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdread (ta->ph, address, &value, sizeof value); + value = bswap_64 (value); + *result = (psaddr_t) 0 + value; + } + else + return TD_DBERR; + + return err == PS_OK ? TD_OK : TD_ERR; +} + + +td_err_e +_td_store_value (td_thragent_t *ta, + uint32_t desc[2], int descriptor_name, psaddr_t idx, + psaddr_t address, psaddr_t widened_value) +{ + ps_err_e err; + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value = widened_value - (psaddr_t) 0; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value = widened_value - (psaddr_t) 0; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value = widened_value - (psaddr_t) 0; + value = bswap_32 (value); + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + value = bswap_64 (value); + err = ps_pdwrite (ta->ph, address, &value, sizeof value); + } + else + return TD_DBERR; + + return err == PS_OK ? TD_OK : TD_ERR; +} + +td_err_e +_td_fetch_value_local (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, psaddr_t idx, + void *address, + psaddr_t *result) +{ + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (&value, address, sizeof value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value; + memcpy (&value, address, sizeof value); + value = bswap_32 (value); + *result = (psaddr_t) 0 + value; + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (&value, address, sizeof value); + value = bswap_64 (value); + *result = (psaddr_t) 0 + value; + } + else + return TD_DBERR; + + return TD_OK; +} + + +td_err_e +_td_store_value_local (td_thragent_t *ta, + uint32_t desc[2], int descriptor_name, psaddr_t idx, + void *address, psaddr_t widened_value) +{ + td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address); + if (terr != TD_OK) + return terr; + + if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8)) + { + uint8_t value = widened_value - (psaddr_t) 0; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 32) + { + uint32_t value = widened_value - (psaddr_t) 0; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == 64) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (32)) + { + uint32_t value = widened_value - (psaddr_t) 0; + value = bswap_32 (value); + memcpy (address, &value, sizeof value); + } + else if (DB_DESC_SIZE (desc) == bswap_32 (64)) + { + uint64_t value = widened_value - (psaddr_t) 0; + if (sizeof (psaddr_t) < 8) + return TD_NOCAPAB; + value = bswap_64 (value); + memcpy (address, &value, sizeof value); + } + else + return TD_DBERR; + + return TD_OK; +} diff --git a/libpthread/nptl_db/proc_service.h b/libpthread/nptl_db/proc_service.h new file mode 100644 index 000000000..d49e87ab3 --- /dev/null +++ b/libpthread/nptl_db/proc_service.h @@ -0,0 +1,87 @@ +/* Callback interface for libthread_db, functions users must define. + Copyright (C) 1999,2002,2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* The definitions in this file must correspond to those in the debugger. */ +#include <sys/procfs.h> + +/* Functions in this interface return one of these status codes. */ +typedef enum +{ + PS_OK, /* Generic "call succeeded". */ + PS_ERR, /* Generic error. */ + PS_BADPID, /* Bad process handle. */ + PS_BADLID, /* Bad LWP identifier. */ + PS_BADADDR, /* Bad address. */ + PS_NOSYM, /* Could not find given symbol. */ + PS_NOFREGS /* FPU register set not available for given LWP. */ +} ps_err_e; + + +/* This type is opaque in this interface. + It's defined by the user of libthread_db. */ +struct ps_prochandle; + + +/* Read or write process memory at the given address. */ +extern ps_err_e ps_pdread (struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_pdwrite (struct ps_prochandle *, + psaddr_t, const void *, size_t); +extern ps_err_e ps_ptread (struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_ptwrite (struct ps_prochandle *, + psaddr_t, const void *, size_t); + + +/* Get and set the given LWP's general or FPU register set. */ +extern ps_err_e ps_lgetregs (struct ps_prochandle *, + lwpid_t, prgregset_t); +extern ps_err_e ps_lsetregs (struct ps_prochandle *, + lwpid_t, const prgregset_t); +extern ps_err_e ps_lgetfpregs (struct ps_prochandle *, + lwpid_t, prfpregset_t *); +extern ps_err_e ps_lsetfpregs (struct ps_prochandle *, + lwpid_t, const prfpregset_t *); + +/* Return the PID of the process. */ +extern pid_t ps_getpid (struct ps_prochandle *); + +/* Fetch the special per-thread address associated with the given LWP. + This call is only used on a few platforms (most use a normal register). + The meaning of the `int' parameter is machine-dependent. */ +extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, + lwpid_t, int, psaddr_t *); + + +/* Look up the named symbol in the named DSO in the symbol tables + associated with the process being debugged, filling in *SYM_ADDR + with the corresponding run-time address. */ +extern ps_err_e ps_pglobal_lookup (struct ps_prochandle *, + const char *object_name, + const char *sym_name, + psaddr_t *sym_addr); + + +/* Stop or continue the entire process. */ +extern ps_err_e ps_pstop (const struct ps_prochandle *); +extern ps_err_e ps_pcontinue (const struct ps_prochandle *); + +/* Stop or continue the given LWP alone. */ +extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t); +extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t); diff --git a/libpthread/nptl_db/structs.def b/libpthread/nptl_db/structs.def new file mode 100644 index 000000000..823af5cba --- /dev/null +++ b/libpthread/nptl_db/structs.def @@ -0,0 +1,88 @@ +/* List of types and symbols in libpthread examined by libthread_db. + Copyright (C) 2003, 2006 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef DB_STRUCT_ARRAY_FIELD +# define DB_STRUCT_ARRAY_FIELD(type, field) DB_STRUCT_FIELD (type, field) +# define DB_ARRAY_VARIABLE(name) DB_VARIABLE (name) +# define STRUCTS_DEF_DEFAULTS 1 +#endif + +DB_STRUCT (pthread) +DB_STRUCT_FIELD (pthread, list) +DB_STRUCT_FIELD (pthread, report_events) +DB_STRUCT_FIELD (pthread, tid) +DB_STRUCT_FIELD (pthread, start_routine) +DB_STRUCT_FIELD (pthread, cancelhandling) +DB_STRUCT_FIELD (pthread, schedpolicy) +DB_STRUCT_FIELD (pthread, schedparam_sched_priority) +DB_STRUCT_FIELD (pthread, specific) +DB_STRUCT_FIELD (pthread, eventbuf) +DB_STRUCT_FIELD (pthread, eventbuf_eventmask) +DB_STRUCT_ARRAY_FIELD (pthread, eventbuf_eventmask_event_bits) +DB_STRUCT_FIELD (pthread, nextevent) + +DB_STRUCT (list_t) +DB_STRUCT_FIELD (list_t, next) +DB_STRUCT_FIELD (list_t, prev) + +DB_STRUCT (td_thr_events_t) +DB_STRUCT_ARRAY_FIELD (td_thr_events_t, event_bits) + +DB_STRUCT (td_eventbuf_t) +DB_STRUCT_FIELD (td_eventbuf_t, eventnum) +DB_STRUCT_FIELD (td_eventbuf_t, eventdata) + +DB_SYMBOL (stack_used) +DB_SYMBOL (__stack_user) +DB_SYMBOL (nptl_version) +DB_FUNCTION (__nptl_create_event) +DB_FUNCTION (__nptl_death_event) +DB_SYMBOL (__nptl_threads_events) +DB_VARIABLE (__nptl_nthreads) +DB_VARIABLE (__nptl_last_event) + +DB_ARRAY_VARIABLE (__pthread_keys) +DB_STRUCT (pthread_key_struct) +DB_STRUCT_FIELD (pthread_key_struct, seq) +DB_STRUCT_FIELD (pthread_key_struct, destr) + +DB_STRUCT (pthread_key_data) +DB_STRUCT_FIELD (pthread_key_data, seq) +DB_STRUCT_FIELD (pthread_key_data, data) +DB_STRUCT (pthread_key_data_level2) +DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data) + +#if USE_TLS +DB_STRUCT_FIELD (link_map, l_tls_modid) +#endif + +#if !defined IS_IN_libpthread || USE_TLS +DB_STRUCT_ARRAY_FIELD (dtv, dtv) +# define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */ +DB_STRUCT_FIELD (dtv_t, pointer_val) +#endif +#if !defined IS_IN_libpthread || TLS_TCB_AT_TP +DB_STRUCT_FIELD (pthread, dtvp) +#endif + +#ifdef STRUCTS_DEF_DEFAULTS +# undef DB_STRUCT_ARRAY_FIELD +# undef DB_ARRAY_VARIABLE +# undef STRUCTS_DEF_DEFAULTS +#endif diff --git a/libpthread/nptl_db/td_init.c b/libpthread/nptl_db/td_init.c new file mode 100644 index 000000000..946ff7244 --- /dev/null +++ b/libpthread/nptl_db/td_init.c @@ -0,0 +1,32 @@ +/* Initialization function of thread debugger support library. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +int __td_debug; + + +td_err_e +td_init (void) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_init"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_log.c b/libpthread/nptl_db/td_log.c new file mode 100644 index 000000000..52212a0e9 --- /dev/null +++ b/libpthread/nptl_db/td_log.c @@ -0,0 +1,32 @@ +/* Noop, left for historical reasons. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_log (void) +{ + /* This interface is deprecated in the Sun interface. We provide it + for compatibility but don't do anything ourself. We might in + future do some logging if this seems reasonable. */ + LOG ("td_log"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_symbol_list.c b/libpthread/nptl_db/td_symbol_list.c new file mode 100644 index 000000000..04aed6787 --- /dev/null +++ b/libpthread/nptl_db/td_symbol_list.c @@ -0,0 +1,87 @@ +/* Return list of symbols the library can request. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#ifndef __UCLIBC__ +#include <gnu/lib-names.h> +#endif +#include "thread_dbP.h" + + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DOT "." /* PPC64 requires . prefix on code symbols. */ +#else +# define DOT /* No prefix. */ +#endif + +static const char *symbol_list_arr[] = +{ +# define DB_STRUCT(type) \ + [SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type, +# define DB_STRUCT_FIELD(type, field) \ + [SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field, +# define DB_SYMBOL(name) \ + [SYM_##name] = #name, +# define DB_FUNCTION(name) \ + [SYM_##name] = DOT #name, +# define DB_VARIABLE(name) \ + [SYM_##name] = #name, \ + [SYM_DESC_##name] = "_thread_db_" #name, +# include "structs.def" +# undef DB_STRUCT +# undef DB_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE + + [SYM_TH_UNIQUE_CONST_THREAD_AREA] = "_thread_db_const_thread_area", + [SYM_TH_UNIQUE_REGISTER64] = "_thread_db_register64", + [SYM_TH_UNIQUE_REGISTER32] = "_thread_db_register32", + [SYM_TH_UNIQUE_REGISTER32_THREAD_AREA] = "_thread_db_register32_thread_area", + [SYM_TH_UNIQUE_REGISTER64_THREAD_AREA] = "_thread_db_register64_thread_area", + + [SYM_NUM_MESSAGES] = NULL +}; + + +const char ** +td_symbol_list (void) +{ + return symbol_list_arr; +} + + +ps_err_e +td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) +{ + ps_err_e result; + assert (idx >= 0 && idx < SYM_NUM_MESSAGES); + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], + sym_addr); + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME + /* For PowerPC, 64-bit uses dot symbols but 32-bit does not. + We could be a 64-bit libthread_db debugging a 32-bit libpthread. */ + if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.') + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1], + sym_addr); +#endif + + return result; +} diff --git a/libpthread/nptl_db/td_ta_clear_event.c b/libpthread/nptl_db/td_ta_clear_event.c new file mode 100644 index 000000000..7a2850c4e --- /dev/null +++ b/libpthread/nptl_db/td_ta_clear_event.c @@ -0,0 +1,79 @@ +/* Globally disable events. + Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_clear_event (ta_arg, event) + const td_thragent_t *ta_arg; + td_thr_events_t *event; +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventmask = 0; + void *copy = NULL; + + LOG ("td_ta_clear_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, ta, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask &= ~event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (ta, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_delete.c b/libpthread/nptl_db/td_ta_delete.c new file mode 100644 index 000000000..57b90e57f --- /dev/null +++ b/libpthread/nptl_db/td_ta_delete.c @@ -0,0 +1,42 @@ +/* Detach to target process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_delete (td_thragent_t *ta) +{ + LOG ("td_ta_delete"); + + /* Safety check. Note that the test will also fail for TA == NULL. */ + if (!ta_ok (ta)) + return TD_BADTA; + + /* Remove the handle from the list. */ + list_del (&ta->list); + + /* The handle was allocated in `td_ta_new'. */ + free (ta); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_enable_stats.c b/libpthread/nptl_db/td_ta_enable_stats.c new file mode 100644 index 000000000..ec7014ad2 --- /dev/null +++ b/libpthread/nptl_db/td_ta_enable_stats.c @@ -0,0 +1,35 @@ +/* Enable collection of statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_enable_stats (const td_thragent_t *ta, int enable) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_enable_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_event_addr.c b/libpthread/nptl_db/td_ta_event_addr.c new file mode 100644 index 000000000..45c6b113d --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_addr.c @@ -0,0 +1,61 @@ +/* Get event address. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_addr (const td_thragent_t *ta_arg, + td_event_e event, td_notify_t *addr) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t taddr = NULL; + + LOG ("td_ta_event_addr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + switch (event) + { + case TD_CREATE: + err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event); + break; + + case TD_DEATH: + err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event); + break; + + default: + /* Event cannot be handled. */ + return TD_NOEVENT; + } + + if (err == TD_OK) + { + /* Success, we got the address. */ + addr->type = NOTIFY_BPT; + addr->u.bptaddr = taddr; + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_event_getmsg.c b/libpthread/nptl_db/td_ta_event_getmsg.c new file mode 100644 index 000000000..d3b46bd56 --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_getmsg.c @@ -0,0 +1,105 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventbuf, eventnum, eventdata; + psaddr_t thp, next; + void *copy = NULL; + + /* XXX I cannot think of another way but using a static variable. */ + /* XXX Use at least __thread once it is possible. */ + static td_thrhandle_t th; + + LOG ("td_thr_event_getmsg"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Get the pointer to the thread descriptor with the last event. */ + err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0); + if (err != TD_OK) + return err; + + if (thp == 0) + /* Nothing waiting. */ + return TD_NOMSG; + + /* Copy the event message buffer in from the inferior. */ + err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t); + if (err != TD_OK) + return err; + + /* Read the event details from the target thread. */ + err = DB_GET_FIELD_LOCAL (eventnum, ta, copy, td_eventbuf_t, eventnum, 0); + if (err != TD_OK) + return err; + /* If the structure is on the list there better be an event recorded. */ + if ((int) (uintptr_t) eventnum == TD_EVENT_NONE) + return TD_DBERR; + + /* Fill the user's data structure. */ + err = DB_GET_FIELD_LOCAL (eventdata, ta, copy, td_eventbuf_t, eventdata, 0); + if (err != TD_OK) + return err; + + /* Generate the thread descriptor. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = thp; + + /* Fill the user's data structure. */ + msg->msg.data = (uintptr_t) eventdata; + msg->event = (uintptr_t) eventnum; + msg->th_p = &th; + + /* And clear the event message in the target. */ + memset (copy, 0, ta->ta_sizeof_td_eventbuf_t); + err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy); + if (err != TD_OK) + return err; + + /* Get the pointer to the next descriptor with an event. */ + err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0); + if (err != TD_OK) + return err; + + /* Store the pointer in the list head variable. */ + err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next); + if (err != TD_OK) + return err; + + if (next != 0) + /* Clear the next pointer in the current descriptor. */ + err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0); + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_nthreads.c b/libpthread/nptl_db/td_ta_get_nthreads.c new file mode 100644 index 000000000..ffe78bd57 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_nthreads.c @@ -0,0 +1,42 @@ +/* Get the number of threads in the process. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +td_err_e +td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t n; + + LOG ("td_ta_get_nthreads"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Access the variable in the inferior that tells us. */ + err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0); + if (err == TD_OK) + *np = (uintptr_t) n; + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_ph.c b/libpthread/nptl_db/td_ta_get_ph.c new file mode 100644 index 000000000..04e01fb73 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_ph.c @@ -0,0 +1,36 @@ +/* Get external process handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) +{ + LOG ("td_ta_get_ph"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + *ph = ta->ph; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_get_stats.c b/libpthread/nptl_db/td_ta_get_stats.c new file mode 100644 index 000000000..d5d879c3e --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_stats.c @@ -0,0 +1,35 @@ +/* Retrieve statistics for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_get_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_id2thr.c b/libpthread/nptl_db/td_ta_map_id2thr.c new file mode 100644 index 000000000..189a67171 --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_id2thr.c @@ -0,0 +1,38 @@ +/* Map thread ID to thread handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) +{ + LOG ("td_ta_map_id2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Create the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = (psaddr_t) pt; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_lwp2thr.c b/libpthread/nptl_db/td_ta_map_lwp2thr.c new file mode 100644 index 000000000..acfa0fd8a --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_lwp2thr.c @@ -0,0 +1,178 @@ +/* Which thread is running on an LWP? + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <stdlib.h> +#include <byteswap.h> +#include <sys/procfs.h> + + +td_err_e +td_ta_map_lwp2thr (const td_thragent_t *ta_arg, + lwpid_t lwpid, td_thrhandle_t *th) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + ps_err_e err; + td_err_e terr; + prgregset_t regs; + psaddr_t addr; + + LOG ("td_ta_map_lwp2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + if (ta->ta_howto == ta_howto_unknown) + { + /* We need to read in from the inferior the instructions what to do. */ + psaddr_t howto; + + err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto); + if (err == PS_OK) + { + err = ps_pdread (ta->ph, howto, + &ta->ta_howto_data.const_thread_area, + sizeof ta->ta_howto_data.const_thread_area); + if (err != PS_OK) + return TD_ERR; + ta->ta_howto = ta_howto_const_thread_area; + if (ta->ta_howto_data.const_thread_area & 0xff000000U) + ta->ta_howto_data.const_thread_area + = bswap_32 (ta->ta_howto_data.const_thread_area); + } + else + { + switch (sizeof (regs[0])) + { + case 8: + err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg; + else if (err == PS_NOSYM) + { + err = td_lookup (ta->ph, + SYM_TH_UNIQUE_REGISTER64_THREAD_AREA, + &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg_thread_area; + } + break; + + case 4: + err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg; + else if (err == PS_NOSYM) + { + err = td_lookup (ta->ph, + SYM_TH_UNIQUE_REGISTER32_THREAD_AREA, + &howto); + if (err == PS_OK) + ta->ta_howto = ta_howto_reg_thread_area; + } + break; + + default: + abort (); + return TD_DBERR; + } + + if (err != PS_OK) + return TD_DBERR; + + /* For either of these methods we read in the same descriptor. */ + err = ps_pdread (ta->ph, howto, + ta->ta_howto_data.reg, DB_SIZEOF_DESC); + if (err != PS_OK) + return TD_ERR; + if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0) + return TD_DBERR; + if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U) + { + /* Byte-swap these words, though we leave the size word + in native order as the handy way to distinguish. */ + DB_DESC_OFFSET (ta->ta_howto_data.reg) + = bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg)); + DB_DESC_NELEM (ta->ta_howto_data.reg) + = bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg)); + } + } + } + + switch (ta->ta_howto) + { + case ta_howto_unknown: + return TD_DBERR; + + default: + return TD_DBERR; + + case ta_howto_reg: + /* On most machines, we are just looking at a register. */ + if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK) + return TD_ERR; + terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1, + 0, regs, &addr); + if (terr != TD_OK) + return terr; + /* In this descriptor the nelem word is overloaded as the bias. */ + addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg); + th->th_unique = addr; + break; + + case ta_howto_const_thread_area: + /* Some hosts don't have this call and this case won't be used. */ +# pragma weak ps_get_thread_area + if (&ps_get_thread_area == NULL) + return TD_NOCAPAB; + + /* A la x86-64, there is a constant magic index for get_thread_area. */ + if (ps_get_thread_area (ta->ph, lwpid, + ta->ta_howto_data.const_thread_area, + &th->th_unique) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + break; + + case ta_howto_reg_thread_area: + if (&ps_get_thread_area == NULL) + return TD_NOCAPAB; + + /* A la i386, there is a register with an index for get_thread_area. */ + if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK) + return TD_ERR; + terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1, + 0, regs, &addr); + if (terr != TD_OK) + return terr; + /* In this descriptor the nelem word is overloaded as scale factor. */ + if (ps_get_thread_area + (ta->ph, lwpid, + ((addr - (psaddr_t) 0) + >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)), + &th->th_unique) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + break; + } + + /* Found it. Now complete the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_new.c b/libpthread/nptl_db/td_ta_new.c new file mode 100644 index 000000000..f84049af3 --- /dev/null +++ b/libpthread/nptl_db/td_ta_new.c @@ -0,0 +1,65 @@ +/* Attach to target process. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <version.h> + +#include "thread_dbP.h" + + +/* Datatype for the list of known thread agents. Normally there will + be exactly one so we don't spend much though on making it fast. */ +LIST_HEAD (__td_agent_list); + + +td_err_e +td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) +{ + psaddr_t versaddr; + char versbuf[sizeof (VERSION)]; + + LOG ("td_ta_new"); + + /* Check whether the versions match. */ + if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK) + return TD_NOLIBTHREAD; + if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) + return TD_ERR; + + if (memcmp (versbuf, VERSION, sizeof VERSION) != 0) + /* Not the right version. */ + return TD_VERSION; + + /* Fill in the appropriate information. */ + *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t)); + if (*ta == NULL) + return TD_MALLOC; + + /* Store the proc handle which we will pass to the callback functions + back into the debugger. */ + (*ta)->ph = ps; + + /* Now add the new agent descriptor to the list. */ + list_add (&(*ta)->list, &__td_agent_list); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_reset_stats.c b/libpthread/nptl_db/td_ta_reset_stats.c new file mode 100644 index 000000000..ea59d2cda --- /dev/null +++ b/libpthread/nptl_db/td_ta_reset_stats.c @@ -0,0 +1,35 @@ +/* Reset statistics. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_reset_stats (const td_thragent_t *ta) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_reset_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_set_event.c b/libpthread/nptl_db/td_ta_set_event.c new file mode 100644 index 000000000..29fc14bfb --- /dev/null +++ b/libpthread/nptl_db/td_ta_set_event.c @@ -0,0 +1,79 @@ +/* Globally enable events. + Copyright (C) 1999,2001,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_set_event (ta_arg, event) + const td_thragent_t *ta_arg; + td_thr_events_t *event; +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t eventmask = 0; + void *copy = NULL; + + LOG ("td_ta_set_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, ta, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask |= event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (ta, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_setconcurrency.c b/libpthread/nptl_db/td_ta_setconcurrency.c new file mode 100644 index 000000000..8552ffbe0 --- /dev/null +++ b/libpthread/nptl_db/td_ta_setconcurrency.c @@ -0,0 +1,35 @@ +/* Set suggested concurrency level for process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_setconcurrency (const td_thragent_t *ta, int level) +{ + /* This is something LinuxThreads does not need to support. */ + LOG ("td_ta_setconcurrency"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_ta_thr_iter.c b/libpthread/nptl_db/td_ta_thr_iter.c new file mode 100644 index 000000000..66e437665 --- /dev/null +++ b/libpthread/nptl_db/td_ta_thr_iter.c @@ -0,0 +1,148 @@ +/* Iterate over a process's threads. + Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +static td_err_e +iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + psaddr_t head, int fake_empty) +{ + td_err_e err; + psaddr_t next, ofs; + void *copy; + + /* Test the state. + XXX This is incomplete. Normally this test should be in the loop. */ + if (state != TD_THR_ANY_STATE) + return TD_OK; + + err = DB_GET_FIELD (next, ta, head, list_t, next, 0); + if (err != TD_OK) + return err; + + if (next == 0 && fake_empty) + { + /* __pthread_initialize_minimal has not run. + There is just the main thread to return. */ + td_thrhandle_t th; + err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th); + if (err == TD_OK) + err = callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK; + return err; + } + + /* Cache the offset from struct pthread to its list_t member. */ + err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0); + if (err != TD_OK) + return err; + + if (ta->ta_sizeof_pthread == 0) + { + err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread); + if (err != TD_OK) + return err; + } + copy = __alloca (ta->ta_sizeof_pthread); + + while (next != head) + { + psaddr_t addr, schedpolicy, schedprio; + + addr = next - (ofs - (psaddr_t) 0); + if (next == 0 || addr == 0) /* Sanity check. */ + return TD_DBERR; + + /* Copy the whole descriptor in once so we can access the several + fields locally. Excess copying in one go is much better than + multiple ps_pdread calls. */ + if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK) + return TD_ERR; + + err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, + schedpolicy, 0); + if (err != TD_OK) + break; + err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, + schedparam_sched_priority, 0); + if (err != TD_OK) + break; + + /* Now test whether this thread matches the specified conditions. */ + + /* Only if the priority level is as high or higher. */ + int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + if (descr_pri >= ti_pri) + { + /* Yep, it matches. Call the callback function. */ + td_thrhandle_t th; + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = addr; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; + } + + /* Get the pointer to the next element. */ + err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t, + next, 0); + if (err != TD_OK) + break; + } + + return err; +} + + +td_err_e +td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + sigset_t *ti_sigmask_p, unsigned int ti_user_flags) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t list = 0; + + LOG ("td_ta_thr_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* The thread library keeps two lists for the running threads. One + list contains the thread which are using user-provided stacks + (this includes the main thread) and the other includes the + threads for which the thread library allocated the stacks. We + have to iterate over both lists separately. We start with the + list of threads with user-defined stacks. */ + + err = DB_GET_SYMBOL (list, ta, __stack_user); + if (err == TD_OK) + err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 1); + + /* And the threads with stacks allocated by the implementation. */ + if (err == TD_OK) + err = DB_GET_SYMBOL (list, ta, stack_used); + if (err == TD_OK) + err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0); + + return err; +} diff --git a/libpthread/nptl_db/td_ta_tsd_iter.c b/libpthread/nptl_db/td_ta_tsd_iter.c new file mode 100644 index 000000000..9cfb1e8de --- /dev/null +++ b/libpthread/nptl_db/td_ta_tsd_iter.c @@ -0,0 +1,81 @@ +/* Iterate over a process's thread-specific data. + Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <alloca.h> + +td_err_e +td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback, + void *cbdata_p) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + void *keys; + size_t keys_nb, keys_elemsize; + psaddr_t addr; + uint32_t idx; + + LOG ("td_ta_tsd_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* This makes sure we have the size information on hand. */ + addr = 0; + err = _td_locate_field (ta, + ta->ta_var___pthread_keys, SYM_DESC___pthread_keys, + (psaddr_t) 0 + 1, &addr); + if (err != TD_OK) + return err; + + /* Now copy in the entire array of key descriptors. */ + keys_elemsize = (addr - (psaddr_t) 0) / 8; + keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys); + keys = __alloca (keys_nb); + err = DB_GET_SYMBOL (addr, ta, __pthread_keys); + if (err != TD_OK) + return err; + if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK) + return TD_ERR; + + /* Now get all descriptors, one after the other. */ + for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx) + { + psaddr_t seq, destr; + err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0); + if (err != TD_OK) + return err; + if (((uintptr_t) seq) & 1) + { + err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct, + destr, 0); + if (err != TD_OK) + return err; + /* Return with an error if the callback returns a nonzero value. */ + if (callback ((thread_key_t) idx, destr, cbdata_p) != 0) + return TD_DBERR; + } + /* Advance to the next element in the copied array. */ + keys += keys_elemsize; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_clear_event.c b/libpthread/nptl_db/td_thr_clear_event.c new file mode 100644 index 000000000..c43c625a4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_clear_event.c @@ -0,0 +1,77 @@ +/* Disable specific event for thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_clear_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_err_e err; + psaddr_t eventmask; + void *copy = NULL; + + LOG ("td_thr_clear_event"); + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p, + th->th_unique, pthread, eventbuf_eventmask, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask &= ~event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_dbresume.c b/libpthread/nptl_db/td_thr_dbresume.c new file mode 100644 index 000000000..3fd794377 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbresume.c @@ -0,0 +1,30 @@ +/* Resume execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbresume (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbresume"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_dbsuspend.c b/libpthread/nptl_db/td_thr_dbsuspend.c new file mode 100644 index 000000000..6ef82ad34 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbsuspend.c @@ -0,0 +1,30 @@ +/* Suspend execution of given thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbsuspend (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbsuspend"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_event_enable.c b/libpthread/nptl_db/td_thr_event_enable.c new file mode 100644 index 000000000..a02be5da4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_enable.c @@ -0,0 +1,34 @@ +/* Enable event process-wide. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_event_enable (th, onoff) + const td_thrhandle_t *th; + int onoff; +{ + LOG ("td_thr_event_enable"); + + /* Write the new value into the thread data structure. */ + return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0, + (psaddr_t) 0 + (onoff != 0)); +} diff --git a/libpthread/nptl_db/td_thr_event_getmsg.c b/libpthread/nptl_db/td_thr_event_getmsg.c new file mode 100644 index 000000000..b24fc25d7 --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_getmsg.c @@ -0,0 +1,119 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <assert.h> + + +td_err_e +td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) +{ + td_err_e err; + psaddr_t eventbuf, eventnum, eventdata; + psaddr_t thp, prevp; + void *copy = NULL; + + LOG ("td_thr_event_getmsg"); + + /* Copy the event message buffer in from the inferior. */ + err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread, + eventbuf, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t); + if (err != TD_OK) + return err; + + /* Check whether an event occurred. */ + err = DB_GET_FIELD_LOCAL (eventnum, th->th_ta_p, copy, + td_eventbuf_t, eventnum, 0); + if (err != TD_OK) + return err; + if ((int) (uintptr_t) eventnum == TD_EVENT_NONE) + /* Nothing. */ + return TD_NOMSG; + + /* Fill the user's data structure. */ + err = DB_GET_FIELD_LOCAL (eventdata, th->th_ta_p, copy, + td_eventbuf_t, eventdata, 0); + if (err != TD_OK) + return err; + + msg->msg.data = (uintptr_t) eventdata; + msg->event = (uintptr_t) eventnum; + msg->th_p = th; + + /* And clear the event message in the target. */ + memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t); + err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy); + if (err != TD_OK) + return err; + + /* Get the pointer to the thread descriptor with the last event. + If it doesn't match TH, then walk down the list until we find it. + We must splice it out of the list so that there is no dangling + pointer to it later when it dies. */ + err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event); + if (err != TD_OK) + return err; + err = DB_GET_VALUE (thp, th->th_ta_p, __nptl_last_event, 0); + if (err != TD_OK) + return err; + + while (thp != 0) + { + psaddr_t next; + err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread, + nextevent, 0); + if (err != TD_OK) + return err; + + if (next == thp) + return TD_DBERR; + + if (thp == th->th_unique) + { + /* PREVP points at this thread, splice it out. */ + psaddr_t next_nextp; + err = DB_GET_FIELD_ADDRESS (next_nextp, th->th_ta_p, next, pthread, + nextevent, 0); + assert (err == TD_OK); /* We used this field before. */ + if (prevp == next_nextp) + return TD_DBERR; + + err = _td_store_value (th->th_ta_p, + th->th_ta_p->ta_var___nptl_last_event, -1, + 0, prevp, next); + if (err != TD_OK) + return err; + + /* Now clear this thread's own next pointer so it's not dangling + when the thread resumes and then chains on for its next event. */ + return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0); + } + + err = DB_GET_FIELD_ADDRESS (prevp, th->th_ta_p, thp, pthread, + nextevent, 0); + assert (err == TD_OK); /* We used this field before. */ + thp = next; + } + + /* Ack! This should not happen. */ + return TD_DBERR; +} diff --git a/libpthread/nptl_db/td_thr_get_info.c b/libpthread/nptl_db/td_thr_get_info.c new file mode 100644 index 000000000..bb1388804 --- /dev/null +++ b/libpthread/nptl_db/td_thr_get_info.c @@ -0,0 +1,110 @@ +/* Get thread information. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> +#include "thread_dbP.h" + + +td_err_e +td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) +{ + td_err_e err; + void *copy; + psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events; + + LOG ("td_thr_get_info"); + + /* Copy the whole descriptor in once so we can access the several + fields locally. Excess copying in one go is much better than + multiple ps_pdread calls. */ + err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread); + if (err != TD_OK) + return err; + + err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique, + pthread, specific, 0); + if (err != TD_OK) + return err; + + err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread, + schedpolicy, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread, + schedparam_sched_priority, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread, + report_events, 0); + if (err != TD_OK) + return err; + + /* Fill in information. Clear first to provide reproducable + results for the fields we do not fill in. */ + memset (infop, '\0', sizeof (td_thrinfo_t)); + + infop->ti_tid = (thread_t) th->th_unique; + infop->ti_tls = (char *) tls; + infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + infop->ti_type = TD_THR_USER; + + if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0) + /* XXX For now there is no way to get more information. */ + infop->ti_state = TD_THR_ACTIVE; + else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + infop->ti_state = TD_THR_ZOMBIE; + else + infop->ti_state = TD_THR_UNKNOWN; + + /* Initialization which are the same in both cases. */ + infop->ti_ta_p = th->th_ta_p; + infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid; + infop->ti_traceme = report_events != 0; + + err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread, + start_routine, 0); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread, + eventbuf_eventmask_event_bits, idx); + if (err != TD_OK) + break; + infop->ti_events.event_bits[idx] = (uintptr_t) word; + } + if (err == TD_NOAPLIC) + memset (&infop->ti_events.event_bits[idx], 0, + (TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_getfpregs.c b/libpthread/nptl_db/td_thr_getfpregs.c new file mode 100644 index 000000000..7760512eb --- /dev/null +++ b/libpthread/nptl_db/td_thr_getfpregs.c @@ -0,0 +1,53 @@ +/* Get a thread's floating-point register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_getfpregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* If the thread already terminated we return all zeroes. */ + if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getgregs.c b/libpthread/nptl_db/td_thr_getgregs.c new file mode 100644 index 000000000..4c2373ef6 --- /dev/null +++ b/libpthread/nptl_db/td_thr_getgregs.c @@ -0,0 +1,53 @@ +/* Get a thread's general register set. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getgregs (const td_thrhandle_t *th, prgregset_t regset) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_getgregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* If the thread already terminated we return all zeroes. */ + if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getxregs.c b/libpthread/nptl_db/td_thr_getxregs.c new file mode 100644 index 000000000..3c77ab6be --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregs.c @@ -0,0 +1,30 @@ +/* Get a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregs (const td_thrhandle_t *th, void *xregs) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_getxregsize.c b/libpthread/nptl_db/td_thr_getxregsize.c new file mode 100644 index 000000000..1704e4b0a --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregsize.c @@ -0,0 +1,30 @@ +/* Get the size of the extra state register set for this architecture. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregsize"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_set_event.c b/libpthread/nptl_db/td_thr_set_event.c new file mode 100644 index 000000000..6617147a8 --- /dev/null +++ b/libpthread/nptl_db/td_thr_set_event.c @@ -0,0 +1,77 @@ +/* Enable specific event for thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +td_thr_set_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_err_e err; + psaddr_t eventmask; + void *copy = NULL; + + LOG ("td_thr_set_event"); + + /* Fetch the old event mask from the inferior and modify it in place. */ + err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p, + th->th_unique, pthread, eventbuf_eventmask, 0); + if (err == TD_OK) + err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t); + if (err == TD_OK) + { + uint32_t idx; + for (idx = 0; idx < TD_EVENTSIZE; ++idx) + { + psaddr_t word; + uint32_t mask; + err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, + td_thr_events_t, event_bits, idx); + if (err != TD_OK) + break; + mask = (uintptr_t) word; + mask |= event->event_bits[idx]; + word = (psaddr_t) (uintptr_t) mask; + err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy, + td_thr_events_t, event_bits, idx, word); + if (err != TD_OK) + break; + } + if (err == TD_NOAPLIC) + { + err = TD_OK; + while (idx < TD_EVENTSIZE) + if (event->event_bits[idx++] != 0) + { + err = TD_NOEVENT; + break; + } + } + if (err == TD_OK) + /* Now write it back to the inferior. */ + err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_setfpregs.c b/libpthread/nptl_db/td_thr_setfpregs.c new file mode 100644 index 000000000..01bdb5323 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setfpregs.c @@ -0,0 +1,50 @@ +/* Set a thread's floating-point register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_setfpregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* Only set the registers if the thread hasn't yet terminated. */ + if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setgregs.c b/libpthread/nptl_db/td_thr_setgregs.c new file mode 100644 index 000000000..2a9ce7e01 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setgregs.c @@ -0,0 +1,50 @@ +/* Set a thread's general register set. + Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs) +{ + psaddr_t cancelhandling, tid; + td_err_e err; + + LOG ("td_thr_setgregs"); + + /* We have to get the state and the PID for this thread. */ + err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread, + cancelhandling, 0); + if (err != TD_OK) + return err; + + /* Only set the registers if the thread hasn't yet terminated. */ + if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setprio.c b/libpthread/nptl_db/td_thr_setprio.c new file mode 100644 index 000000000..6032b0ed4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setprio.c @@ -0,0 +1,30 @@ +/* Set a thread's priority. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setprio (const td_thrhandle_t *th, int prio) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setprio"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setsigpending.c b/libpthread/nptl_db/td_thr_setsigpending.c new file mode 100644 index 000000000..e2c9d7ad2 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setsigpending.c @@ -0,0 +1,31 @@ +/* Raise a signal for a thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, + const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setsigpending"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setxregs.c b/libpthread/nptl_db/td_thr_setxregs.c new file mode 100644 index 000000000..f48877c78 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setxregs.c @@ -0,0 +1,30 @@ +/* Set a thread's extra state register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) +{ + /* XXX This might have to be platform specific. */ + LOG ("td_thr_setxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_sigsetmask.c b/libpthread/nptl_db/td_thr_sigsetmask.c new file mode 100644 index 000000000..3a68aecd3 --- /dev/null +++ b/libpthread/nptl_db/td_thr_sigsetmask.c @@ -0,0 +1,30 @@ +/* Set a thread's signal mask. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_sigsetmask"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tls_get_addr.c b/libpthread/nptl_db/td_thr_tls_get_addr.c new file mode 100644 index 000000000..e7d232272 --- /dev/null +++ b/libpthread/nptl_db/td_thr_tls_get_addr.c @@ -0,0 +1,43 @@ +/* Get address of thread local variable. + Copyright (C) 2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <link.h> +#include "thread_dbP.h" + +td_err_e +td_thr_tls_get_addr (const td_thrhandle_t *th, + psaddr_t map_address, size_t offset, psaddr_t *address) +{ + td_err_e err; + psaddr_t modid; + + /* Get the TLS module ID from the `struct link_map' in the inferior. */ + err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map, + l_tls_modid, 0); + if (err == TD_NOCAPAB) + return TD_NOAPLIC; + if (err == TD_OK) + { + err = td_thr_tlsbase (th, (uintptr_t) modid, address); + if (err == TD_OK) + *address += offset; + } + return err; +} diff --git a/libpthread/nptl_db/td_thr_tlsbase.c b/libpthread/nptl_db/td_thr_tlsbase.c new file mode 100644 index 000000000..aaeda6f3c --- /dev/null +++ b/libpthread/nptl_db/td_thr_tlsbase.c @@ -0,0 +1,55 @@ +/* Locate TLS data for a thread. + Copyright (C) 2003, 2006 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +td_err_e +td_thr_tlsbase (const td_thrhandle_t *th, + unsigned long int modid, + psaddr_t *base) +{ + td_err_e err; + psaddr_t dtv, dtvslot, dtvptr; + + if (modid < 1) + return TD_NOTLS; + + /* Get the DTV pointer from the thread descriptor. */ + err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0); + if (err != TD_OK) + return err; + + /* Find the corresponding entry in the DTV. */ + err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid); + if (err != TD_OK) + return err; + + /* Extract the TLS block address from that DTV slot. */ + err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0); + if (err != TD_OK) + return err; + + /* It could be that the memory for this module is not allocated for + the given thread. */ + if ((uintptr_t) dtvptr & 1) + return TD_TLSDEFER; + + *base = dtvptr; + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tsd.c b/libpthread/nptl_db/td_thr_tsd.c new file mode 100644 index 000000000..08f617b7d --- /dev/null +++ b/libpthread/nptl_db/td_thr_tsd.c @@ -0,0 +1,96 @@ +/* Get a thread-specific data pointer for a thread. + Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) +{ + td_err_e err; + psaddr_t tk_seq, level1, level2, seq, value; + void *copy; + uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd; + + LOG ("td_thr_tsd"); + + /* Get the key entry. */ + err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk); + if (err == TD_NOAPLIC) + return TD_BADKEY; + if (err != TD_OK) + return err; + + /* Fail if this key is not at all used. */ + if (((uintptr_t) tk_seq & 1) == 0) + return TD_BADKEY; + + /* This makes sure we have the size information on hand. */ + err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2, + data, 1); + if (err != TD_OK) + return err; + + /* Compute the indeces. */ + pthread_key_2ndlevel_size + = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data); + idx1st = tk / pthread_key_2ndlevel_size; + idx2nd = tk % pthread_key_2ndlevel_size; + + /* Now fetch the first level pointer. */ + err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread, + specific, idx1st); + if (err == TD_NOAPLIC) + return TD_DBERR; + if (err != TD_OK) + return err; + + /* Check the pointer to the second level array. */ + if (level1 == 0) + return TD_NOTSD; + + /* Locate the element within the second level array. */ + err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, + level1, pthread_key_data_level2, data, idx2nd); + if (err == TD_NOAPLIC) + return TD_DBERR; + if (err != TD_OK) + return err; + + /* Now copy in that whole structure. */ + err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data); + if (err != TD_OK) + return err; + + /* Check whether the data is valid. */ + err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0); + if (err != TD_OK) + return err; + if (seq != tk_seq) + return TD_NOTSD; + + /* Finally, fetch the value. */ + err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data, + data, 0); + if (err == TD_OK) + *data = value; + + return err; +} diff --git a/libpthread/nptl_db/td_thr_validate.c b/libpthread/nptl_db/td_thr_validate.c new file mode 100644 index 000000000..19ee940d6 --- /dev/null +++ b/libpthread/nptl_db/td_thr_validate.c @@ -0,0 +1,91 @@ +/* Validate a thread handle. + Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include <stdbool.h> + +static td_err_e +check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit) +{ + td_err_e err; + psaddr_t next, ofs; + + err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0); + if (err == TD_OK) + { + if (next == 0) + { + *uninit = true; + return TD_NOTHR; + } + err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0); + } + + while (err == TD_OK) + { + if (next == head) + return TD_NOTHR; + + if (next - (ofs - (psaddr_t) 0) == th->th_unique) + return TD_OK; + + err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0); + } + + return err; +} + + +td_err_e +td_thr_validate (const td_thrhandle_t *th) +{ + td_err_e err; + psaddr_t list = NULL; + + LOG ("td_thr_validate"); + + /* First check the list with threads using user allocated stacks. */ + bool uninit = false; + err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user); + if (err == TD_OK) + err = check_thread_list (th, list, &uninit); + + /* If our thread is not on this list search the list with stack + using implementation allocated stacks. */ + if (err == TD_NOTHR) + { + err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used); + if (err == TD_OK) + err = check_thread_list (th, list, &uninit); + + if (err == TD_NOTHR && uninit) + { + /* __pthread_initialize_minimal has not run yet. + But the main thread still has a valid ID. */ + td_thrhandle_t main_th; + err = td_ta_map_lwp2thr (th->th_ta_p, + ps_getpid (th->th_ta_p->ph), &main_th); + if (err == TD_OK && th->th_unique != main_th.th_unique) + err = TD_NOTHR; + } + } + + return err; +} diff --git a/libpthread/nptl_db/thread_db.h b/libpthread/nptl_db/thread_db.h new file mode 100644 index 000000000..433b54fd5 --- /dev/null +++ b/libpthread/nptl_db/thread_db.h @@ -0,0 +1,459 @@ +/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread + Copyright (C) 1999,2001,2002,2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _THREAD_DB_H +#define _THREAD_DB_H 1 + +/* This is the debugger interface for the NPTL library. It is + modelled closely after the interface with same names in Solaris + with the goal to share the same code in the debugger. */ +#include <pthread.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/procfs.h> + + +/* Error codes of the library. */ +typedef enum +{ + TD_OK, /* No error. */ + TD_ERR, /* No further specified error. */ + TD_NOTHR, /* No matching thread found. */ + TD_NOSV, /* No matching synchronization handle found. */ + TD_NOLWP, /* No matching light-weighted process found. */ + TD_BADPH, /* Invalid process handle. */ + TD_BADTH, /* Invalid thread handle. */ + TD_BADSH, /* Invalid synchronization handle. */ + TD_BADTA, /* Invalid thread agent. */ + TD_BADKEY, /* Invalid key. */ + TD_NOMSG, /* No event available. */ + TD_NOFPREGS, /* No floating-point register content available. */ + TD_NOLIBTHREAD, /* Application not linked with thread library. */ + TD_NOEVENT, /* Requested event is not supported. */ + TD_NOCAPAB, /* Capability not available. */ + TD_DBERR, /* Internal debug library error. */ + TD_NOAPLIC, /* Operation is not applicable. */ + TD_NOTSD, /* No thread-specific data available. */ + TD_MALLOC, /* Out of memory. */ + TD_PARTIALREG, /* Not entire register set was read or written. */ + TD_NOXREGS, /* X register set not available for given thread. */ + TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */ + TD_NOTALLOC = TD_TLSDEFER, + TD_VERSION, /* Version if libpthread and libthread_db do not match. */ + TD_NOTLS /* There is no TLS segment in the given module. */ +} td_err_e; + + +/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to + select threads regardless of state in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_STATE, + TD_THR_UNKNOWN, + TD_THR_STOPPED, + TD_THR_RUN, + TD_THR_ACTIVE, + TD_THR_ZOMBIE, + TD_THR_SLEEP, + TD_THR_STOPPED_ASLEEP +} td_thr_state_e; + +/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used + to select threads regardless of type in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_TYPE, + TD_THR_USER, + TD_THR_SYSTEM +} td_thr_type_e; + + +/* Types of the debugging library. */ + +/* Handle for a process. This type is opaque. */ +typedef struct td_thragent td_thragent_t; + +/* The actual thread handle type. This is also opaque. */ +typedef struct td_thrhandle +{ + td_thragent_t *th_ta_p; + psaddr_t th_unique; +} td_thrhandle_t; + + +/* Forward declaration of a type defined by and for the dynamic linker. */ +struct link_map; + + +/* Flags for `td_ta_thr_iter'. */ +#define TD_THR_ANY_USER_FLAGS 0xffffffff +#define TD_THR_LOWEST_PRIORITY -20 +#define TD_SIGNO_MASK NULL + + +#define TD_EVENTSIZE 2 +#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ +#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ +#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ + +/* Bitmask of enabled events. */ +typedef struct td_thr_events +{ + uint32_t event_bits[TD_EVENTSIZE]; +} td_thr_events_t; + +/* Event set manipulation macros. */ +#define __td_eventmask(n) \ + (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) +#define __td_eventword(n) \ + ((UINT32_C ((n) - 1)) >> BT_UISHIFT) + +#define td_event_emptyset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = 0; \ + } while (0) + +#define td_event_fillset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ + } while (0) + +#define td_event_addset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) +#define td_event_delset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) +#define td_eventismember(setp, n) \ + (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) +#if TD_EVENTSIZE == 2 +# define td_eventisempty(setp) \ + (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) +#else +# error "td_eventisempty must be changed to match TD_EVENTSIZE" +#endif + +/* Events reportable by the thread implementation. */ +typedef enum +{ + TD_ALL_EVENTS, /* Pseudo-event number. */ + TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ + TD_READY, /* Is executable now. */ + TD_SLEEP, /* Blocked in a synchronization obj. */ + TD_SWITCHTO, /* Now assigned to a process. */ + TD_SWITCHFROM, /* Not anymore assigned to a process. */ + TD_LOCK_TRY, /* Trying to get an unavailable lock. */ + TD_CATCHSIG, /* Signal posted to the thread. */ + TD_IDLE, /* Process getting idle. */ + TD_CREATE, /* New thread created. */ + TD_DEATH, /* Thread terminated. */ + TD_PREEMPT, /* Preempted. */ + TD_PRI_INHERIT, /* Inherited elevated priority. */ + TD_REAP, /* Reaped. */ + TD_CONCURRENCY, /* Number of processes changing. */ + TD_TIMEOUT, /* Conditional variable wait timed out. */ + TD_MIN_EVENT_NUM = TD_READY, + TD_MAX_EVENT_NUM = TD_TIMEOUT, + TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ +} td_event_e; + +/* Values representing the different ways events are reported. */ +typedef enum +{ + NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ + NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically + inserted. */ + NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ +} td_notify_e; + +/* Description how event type is reported. */ +typedef struct td_notify +{ + td_notify_e type; /* Way the event is reported. */ + union + { + psaddr_t bptaddr; /* Address of breakpoint. */ + int syscallno; /* Number of system call used. */ + } u; +} td_notify_t; + +/* Structure used to report event. */ +typedef struct td_event_msg +{ + td_event_e event; /* Event type being reported. */ + const td_thrhandle_t *th_p; /* Thread reporting the event. */ + union + { +# if 0 + td_synchandle_t *sh; /* Handle of synchronization object. */ +#endif + uintptr_t data; /* Event specific data. */ + } msg; +} td_event_msg_t; + +/* Structure containing event data available in each thread structure. */ +typedef struct +{ + td_thr_events_t eventmask; /* Mask of enabled events. */ + td_event_e eventnum; /* Number of last event. */ + void *eventdata; /* Data associated with event. */ +} td_eventbuf_t; + + +/* Gathered statistics about the process. */ +typedef struct td_ta_stats +{ + int nthreads; /* Total number of threads in use. */ + int r_concurrency; /* Concurrency level requested by user. */ + int nrunnable_num; /* Average runnable threads, numerator. */ + int nrunnable_den; /* Average runnable threads, denominator. */ + int a_concurrency_num; /* Achieved concurrency level, numerator. */ + int a_concurrency_den; /* Achieved concurrency level, denominator. */ + int nlwps_num; /* Average number of processes in use, + numerator. */ + int nlwps_den; /* Average number of processes in use, + denominator. */ + int nidle_num; /* Average number of idling processes, + numerator. */ + int nidle_den; /* Average number of idling processes, + denominator. */ +} td_ta_stats_t; + + +/* Since Sun's library is based on Solaris threads we have to define a few + types to map them to POSIX threads. */ +typedef pthread_t thread_t; +typedef pthread_key_t thread_key_t; + + +/* Callback for iteration over threads. */ +typedef int td_thr_iter_f (const td_thrhandle_t *, void *); + +/* Callback for iteration over thread local data. */ +typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); + + + +/* Forward declaration. This has to be defined by the user. */ +struct ps_prochandle; + + +/* Information about the thread. */ +typedef struct td_thrinfo +{ + td_thragent_t *ti_ta_p; /* Process handle. */ + unsigned int ti_user_flags; /* Unused. */ + thread_t ti_tid; /* Thread ID returned by + pthread_create(). */ + char *ti_tls; /* Pointer to thread-local data. */ + psaddr_t ti_startfunc; /* Start function passed to + pthread_create(). */ + psaddr_t ti_stkbase; /* Base of thread's stack. */ + long int ti_stksize; /* Size of thread's stack. */ + psaddr_t ti_ro_area; /* Unused. */ + int ti_ro_size; /* Unused. */ + td_thr_state_e ti_state; /* Thread state. */ + unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ + td_thr_type_e ti_type; /* Type of the thread (system vs + user thread). */ + intptr_t ti_pc; /* Unused. */ + intptr_t ti_sp; /* Unused. */ + short int ti_flags; /* Unused. */ + int ti_pri; /* Thread priority. */ + lwpid_t ti_lid; /* Kernel PID for this thread. */ + sigset_t ti_sigmask; /* Signal mask. */ + unsigned char ti_traceme; /* Nonzero if event reporting + enabled. */ + unsigned char ti_preemptflag; /* Unused. */ + unsigned char ti_pirecflag; /* Unused. */ + sigset_t ti_pending; /* Set of pending signals. */ + td_thr_events_t ti_events; /* Set of enabled events. */ +} td_thrinfo_t; + + + +/* Prototypes for exported library functions. */ + +/* Initialize the thread debug support library. */ +extern td_err_e td_init (void); + +/* Historical relict. Should not be used anymore. */ +extern td_err_e td_log (void); + +/* Return list of symbols the library can request. */ +extern const char **td_symbol_list (void); + +/* Generate new thread debug library handle for process PS. */ +extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); + +/* Free resources allocated for TA. */ +extern td_err_e td_ta_delete (td_thragent_t *__ta); + +/* Get number of currently running threads in process associated with TA. */ +extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); + +/* Return process handle passed in `td_ta_new' for process associated with + TA. */ +extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, + struct ps_prochandle **__ph); + +/* Map thread library handle PT to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, + td_thrhandle_t *__th); + +/* Map process ID LWPID to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, + td_thrhandle_t *__th); + + +/* Call for each thread in a process associated with TA the callback function + CALLBACK. */ +extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, + td_thr_iter_f *__callback, void *__cbdata_p, + td_thr_state_e __state, int __ti_pri, + sigset_t *__ti_sigmask_p, + unsigned int __ti_user_flags); + +/* Call for each defined thread local data entry the callback function KI. */ +extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, + void *__p); + + +/* Get event address for EVENT. */ +extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, + td_event_e __event, td_notify_t *__ptr); + +/* Enable EVENT in global mask. */ +extern td_err_e td_ta_set_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Disable EVENT in global mask. */ +extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Return information about last event. */ +extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, + td_event_msg_t *__msg); + + +/* Set suggested concurrency level for process associated with TA. */ +extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); + + +/* Enable collecting statistics for process associated with TA. */ +extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); + +/* Reset statistics. */ +extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); + +/* Retrieve statistics from process associated with TA. */ +extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, + td_ta_stats_t *__statsp); + + +/* Validate that TH is a thread handle. */ +extern td_err_e td_thr_validate (const td_thrhandle_t *__th); + +/* Return information about thread TH. */ +extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, + td_thrinfo_t *__infop); + +/* Retrieve floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, + prfpregset_t *__regset); + +/* Retrieve general register contents of process running thread TH. */ +extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Retrieve extended register contents of process running thread TH. */ +extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); + +/* Get size of extended register set of process running thread TH. */ +extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); + +/* Set floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, + const prfpregset_t *__fpregs); + +/* Set general register contents of process running thread TH. */ +extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Set extended register contents of process running thread TH. */ +extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, + const void *__addr); + + +/* Get address of the given module's TLS storage area for the given thread. */ +extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th, + unsigned long int __modid, + psaddr_t *__base); + +/* Get address of thread local variable. */ +extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, + psaddr_t __map_address, size_t __offset, + psaddr_t *__address); + + +/* Enable reporting for EVENT for thread TH. */ +extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); + +/* Enable EVENT for thread TH. */ +extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Disable EVENT for thread TH. */ +extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Get event message for thread TH. */ +extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, + td_event_msg_t *__msg); + + +/* Set priority of thread TH. */ +extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); + + +/* Set pending signals for thread TH. */ +extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, + unsigned char __n, const sigset_t *__ss); + +/* Set signal mask for thread TH. */ +extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, + const sigset_t *__ss); + + +/* Return thread local data associated with key TK in thread TH. */ +extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, + const thread_key_t __tk, void **__data); + + +/* Suspend execution of thread TH. */ +extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); + +/* Resume execution of thread TH. */ +extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); + +#endif /* thread_db.h */ diff --git a/libpthread/nptl_db/thread_dbP.h b/libpthread/nptl_db/thread_dbP.h new file mode 100644 index 000000000..c3d263b0c --- /dev/null +++ b/libpthread/nptl_db/thread_dbP.h @@ -0,0 +1,258 @@ +/* Private header for thread debug library + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _THREAD_DBP_H +#define _THREAD_DBP_H 1 + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> +#include "proc_service.h" +#include "thread_db.h" +#include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */ + +#ifdef __UCLIBC__ +#define __alloca alloca +#endif + +/* Indeces for the symbol names. */ +enum + { +# define DB_STRUCT(type) SYM_SIZEOF_##type, +# define DB_STRUCT_FIELD(type, field) SYM_##type##_FIELD_##field, +# define DB_SYMBOL(name) SYM_##name, +# define DB_FUNCTION(name) SYM_##name, +# define DB_VARIABLE(name) SYM_##name, SYM_DESC_##name, +# include "structs.def" +# undef DB_STRUCT +# undef DB_STRUCT_FIELD +# undef DB_SYMBOL +# undef DB_FUNCTION +# undef DB_VARIABLE + + SYM_TH_UNIQUE_CONST_THREAD_AREA, + SYM_TH_UNIQUE_REGISTER64, + SYM_TH_UNIQUE_REGISTER32, + SYM_TH_UNIQUE_REGISTER64_THREAD_AREA, + SYM_TH_UNIQUE_REGISTER32_THREAD_AREA, + + SYM_NUM_MESSAGES + }; + + +/* Comment out the following for less verbose output. */ +#ifndef NDEBUG +# define LOG(c) if (__td_debug) write (2, c "\n", strlen (c "\n")) +extern int __td_debug attribute_hidden; +#else +# define LOG(c) +#endif + + +#define DB_DESC_SIZE(desc) ((desc)[0]) +#define DB_DESC_NELEM(desc) ((desc)[1]) +#define DB_DESC_OFFSET(desc) ((desc)[2]) +#define DB_SIZEOF_DESC (3 * sizeof (uint32_t)) +#define DB_DEFINE_DESC(name, size, nelem, offset) \ + const uint32_t name[3] = { (size), (nelem), (offset) } +typedef uint32_t db_desc_t[3]; + + +/* Handle for a process. This type is opaque. */ +struct td_thragent +{ + /* Chain on the list of all agent structures. */ + list_t list; + + /* Delivered by the debugger and we have to pass it back in the + proc callbacks. */ + struct ps_prochandle *ph; + + /* Cached values read from the inferior. */ +# define DB_STRUCT(type) \ + uint32_t ta_sizeof_##type; +# define DB_STRUCT_FIELD(type, field) \ + db_desc_t ta_field_##type##_##field; +# define DB_SYMBOL(name) \ + psaddr_t ta_addr_##name; +# define DB_FUNCTION(name) \ + psaddr_t ta_addr_##name; +# define DB_VARIABLE(name) \ + psaddr_t ta_addr_##name; \ + db_desc_t ta_var_##name; +# include "structs.def" +# undef DB_STRUCT +# undef DB_STRUCT_FIELD +# undef DB_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE + + /* The method of locating a thread's th_unique value. */ + enum + { + ta_howto_unknown, + ta_howto_reg, + ta_howto_reg_thread_area, + ta_howto_const_thread_area + } ta_howto; + union + { + uint32_t const_thread_area; /* Constant argument to ps_get_thread_area. */ + /* These are as if the descriptor of the field in prregset_t, + but DB_DESC_NELEM is overloaded as follows: */ + db_desc_t reg; /* Signed bias applied to register value. */ + db_desc_t reg_thread_area; /* Bits to scale down register value. */ + } ta_howto_data; +}; + + +/* List of all known descriptors. */ +extern list_t __td_agent_list attribute_hidden; + + +/* Function used to test for correct thread agent pointer. */ +static inline bool +ta_ok (const td_thragent_t *ta) +{ + list_t *runp; + + list_for_each (runp, &__td_agent_list) + if (list_entry (runp, td_thragent_t, list) == ta) + return true; + + return false; +} + + +/* Internal wrapper around ps_pglobal_lookup. */ +extern ps_err_e td_lookup (struct ps_prochandle *ps, + int idx, psaddr_t *sym_addr) attribute_hidden; + + + + +/* Store in psaddr_t VAR the address of inferior's symbol NAME. */ +#define DB_GET_SYMBOL(var, ta, name) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK)) + +/* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_GET_FIELD(var, ta, ptr, type, field, idx) \ + _td_fetch_value ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), &(var)) + +#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \ + ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), &(var))) + +extern td_err_e _td_locate_field (td_thragent_t *ta, + db_desc_t desc, int descriptor_name, + psaddr_t idx, + psaddr_t *address) attribute_hidden; + + +/* Like DB_GET_FIELD, but PTR is a local pointer to a structure that + has already been copied in from the inferior. */ +#define DB_GET_FIELD_LOCAL(var, ta, ptr, type, field, idx) \ + _td_fetch_value_local ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), &(var)) + +/* Store in psaddr_t VAR the value of variable NAME[IDX] in the inferior. + A target value smaller than psaddr_t is zero-extended. */ +#define DB_GET_VALUE(var, ta, name, idx) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR \ + : _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \ + (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var))) + +/* Helper functions for those. */ +extern td_err_e _td_fetch_value (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t *result) attribute_hidden; +extern td_err_e _td_fetch_value_local (td_thragent_t *ta, + db_desc_t field, + int descriptor_name, + psaddr_t idx, void *address, + psaddr_t *result) attribute_hidden; + +/* Store psaddr_t VALUE in ((TYPE) PTR)->FIELD[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_PUT_FIELD(ta, ptr, type, field, idx, value) \ + _td_store_value ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), (value)) + +#define DB_PUT_FIELD_LOCAL(ta, ptr, type, field, idx, value) \ + _td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \ + SYM_##type##_FIELD_##field, \ + (psaddr_t) 0 + (idx), (ptr), (value)) + +/* Store psaddr_t VALUE in variable NAME[IDX] in the inferior. + A target field smaller than psaddr_t is zero-extended. */ +#define DB_PUT_VALUE(ta, name, idx, value) \ + (((ta)->ta_addr_##name == 0 \ + && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \ + ? TD_ERR \ + : _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \ + (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value))) + +/* Helper functions for those. */ +extern td_err_e _td_store_value (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, psaddr_t address, + psaddr_t value) attribute_hidden; +extern td_err_e _td_store_value_local (td_thragent_t *ta, + db_desc_t field, int descriptor_name, + psaddr_t idx, void *address, + psaddr_t value) attribute_hidden; + +#define DB_GET_STRUCT(var, ta, ptr, type) \ + ({ td_err_e _err = TD_OK; \ + if ((ta)->ta_sizeof_##type == 0) \ + _err = _td_check_sizeof ((ta), &(ta)->ta_sizeof_##type, \ + SYM_SIZEOF_##type); \ + if (_err == TD_OK) \ + _err = ps_pdread ((ta)->ph, (ptr), \ + (var) = __alloca ((ta)->ta_sizeof_##type), \ + (ta)->ta_sizeof_##type) \ + == PS_OK ? TD_OK : TD_ERR; \ + else \ + (var) = NULL; \ + _err; \ + }) +#define DB_PUT_STRUCT(ta, ptr, type, copy) \ + ({ assert ((ta)->ta_sizeof_##type != 0); \ + ps_pdwrite ((ta)->ph, (ptr), (copy), (ta)->ta_sizeof_##type) \ + == PS_OK ? TD_OK : TD_ERR; \ + }) + +extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, + int sizep_name) attribute_hidden; + +#endif /* thread_dbP.h */ diff --git a/librt/Makefile.in b/librt/Makefile.in index aaa19185a..ea1d03eb8 100644 --- a/librt/Makefile.in +++ b/librt/Makefile.in @@ -9,7 +9,12 @@ subdirs += librt CFLAGS-librt := -DNOT_IN_libc -DIS_IN_librt $(SSP_ALL_CFLAGS) -LDFLAGS-librt.so := $(LDFLAGS) $(call link.asneeded,-lc) +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +LDFLAGS-librt.so := $(LDFLAGS) $(top_builddir)lib/libdl.so \ + $(top_builddir)lib/libpthread.so +else +LDFLAGS-librt.so := $(LDFLAGS) +endif LIBS-librt.so := $(LIBS) @@ -19,22 +24,36 @@ 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)) +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +librt_CSRC := $(filter-out mq_notify.c timer_create.c timer_delete.c \ + timer_getoverr.c timer_gettime.c timer_settime.c, \ + $(notdir $(wildcard $(librt_DIR)/*.c))) +librt_SSRC := $(wildcard $(librt_DIR)/*.S) +librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_CSRC)) +librt_OBJ += $(patsubst $(librt_DIR)/%.S,$(librt_OUT)/%.o,$(librt_SSRC)) +else +librt_SRC := $(filter-out clock_nanosleep.c clock_getcpuclockid.c clock_gettime.c, \ + $(notdir $(wildcard $(librt_DIR)/*.c))) +librt_OBJ := $(patsubst %.c,$(librt_OUT)/%.o,$(librt_SRC)) +endif + +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) 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) + +ifeq ($(DOPIC)$(UCLIBC_HAS_THREADS_NATIVE),yn) +$(top_builddir)lib/librt.so: $(top_builddir)lib/librt.a $(libc.dpend) else $(top_builddir)lib/librt.so: $(librt_OUT)/librt_so.a $(libc.depend) endif diff --git a/librt/clock_getcpuclockid.c b/librt/clock_getcpuclockid.c new file mode 100644 index 000000000..704c57402 --- /dev/null +++ b/librt/clock_getcpuclockid.c @@ -0,0 +1,104 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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..8308329b2 --- /dev/null +++ b/librt/clock_gettime.c @@ -0,0 +1,301 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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 <libc-internal.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..69e60087e --- /dev/null +++ b/librt/clock_nanosleep.c @@ -0,0 +1,96 @@ +/* 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#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/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..27d3f1fd7 100644 --- a/librt/kernel-posix-timers.h +++ b/librt/kernel-posix-timers.h @@ -10,6 +10,20 @@ #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; +#endif + /* Type of timers in the kernel */ typedef int kernel_timer_t; diff --git a/librt/mq_receive.c b/librt/mq_receive.c index c0392b0f9..40447dfb9 100644 --- a/librt/mq_receive.c +++ b/librt/mq_receive.c @@ -6,13 +6,18 @@ #include <stddef.h> #include <sys/syscall.h> #include <mqueue.h> +#warning FIXME: hard dependency on ADVANCED REALTIME feature +librt_hidden_proto(mq_timedreceive) + +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ #ifdef __NR_mq_timedreceive #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) -# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__ +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 + /* * Receive the oldest from highest priority messages. * Stop waiting if abs_timeout expires. @@ -21,31 +26,21 @@ 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) { - return __syscall_mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL); + return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, NULL); } -#elif defined __UCLIBC_HAS_STUBS__ -# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__ -ssize_t mq_timedreceive(mqd_t mqdes attribute_unused, char *msg_ptr attribute_unused, - size_t msg_len attribute_unused, unsigned int *msg_prio attribute_unused, - const struct timespec *abs_timeout attribute_unused) -{ - __set_errno(ENOSYS); - return -1; -} -# endif -ssize_t mq_receive(mqd_t mqdes attribute_unused, char *msg_ptr attribute_unused, - size_t msg_len attribute_unused, unsigned int *msg_prio attribute_unused) -{ - __set_errno(ENOSYS); - return -1; -} -#endif diff --git a/librt/mq_send.c b/librt/mq_send.c index 4c1a492b4..f0fcfa35a 100644 --- a/librt/mq_send.c +++ b/librt/mq_send.c @@ -6,14 +6,18 @@ #include <stddef.h> #include <sys/syscall.h> #include <mqueue.h> +#warning FIXME: hard dependency on ADVANCED REALTIME feature +librt_hidden_proto(mq_timedsend) + +#ifndef __UCLIBC_HAS_THREADS_NATIVE__ #ifdef __NR_mq_timedsend #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); +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 -# if defined __USE_XOPEN2K && defined __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. @@ -21,31 +25,21 @@ static _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 } -# endif + +librt_hidden_def(mq_timedsend) +#endif /* Add a message to queue */ int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio) { - return __syscall_mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL); + return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, NULL); } -#elif defined __UCLIBC_HAS_STUBS__ -# if defined __USE_XOPEN2K && defined __UCLIBC_HAS_ADVANCED_REALTIME__ -int mq_timedsend(mqd_t mqdes attribute_unused, const char *msg_ptr attribute_unused, - size_t msg_len attribute_unused, unsigned int msg_prio attribute_unused, - const struct timespec *abs_timeout attribute_unused) -{ - __set_errno(ENOSYS); - return -1; -} -# endif -int mq_send(mqd_t mqdes attribute_unused, const char *msg_ptr attribute_unused, - size_t msg_len attribute_unused, unsigned int msg_prio attribute_unused) -{ - __set_errno(ENOSYS); - return -1; -} -#endif diff --git a/librt/mq_timedreceive.S b/librt/mq_timedreceive.S new file mode 100644 index 000000000..015eb8842 --- /dev/null +++ b/librt/mq_timedreceive.S @@ -0,0 +1,10 @@ +#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 +PSEUDO_END(__mq_timedreceive) +librt_hidden_def (__mq_timedreceive) +weak_alias (__mq_timedreceive, mq_timedreceive) +librt_hidden_weak (mq_timedreceive) diff --git a/librt/mq_timedsend.S b/librt/mq_timedsend.S new file mode 100644 index 000000000..67758a3b9 --- /dev/null +++ b/librt/mq_timedsend.S @@ -0,0 +1,10 @@ +#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 +PSEUDO_END(__mq_timedsend) +librt_hidden_def (__mq_timedsend) +weak_alias (__mq_timedsend, mq_timedsend) +librt_hidden_weak (mq_timedsend) diff --git a/test/Makefile b/test/Makefile index bd68884d3..857ac8ad9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -26,6 +26,9 @@ endif ifneq ($(UCLIBC_HAS_REGEX),y) DIRS := $(filter-out regex,$(DIRS)) endif +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) + DIRS := $(filter-out tls nptl,$(DIRS)) +endif ifneq ($(UCLIBC_HAS_WCHAR),y) DIRS := $(filter-out locale-mbwc,$(DIRS)) endif @@ -41,7 +44,7 @@ endif test check all: run -run: subdirs_run +run: compile subdirs_run compile: $(top_builddir)/$(LOCAL_INSTALL_PATH) subdirs_compile diff --git a/test/Test.mak b/test/Test.mak index 2dab7f741..0c5629144 100644 --- a/test/Test.mak +++ b/test/Test.mak @@ -72,9 +72,8 @@ define exec_test endef test check all: run -run: $(RUN_TARGETS) compile - -$(RUN_TARGETS): $(TARGETS) +run: $(RUN_TARGETS) +$(RUN_TARGETS): $(exec_test) $(diff_test) ifeq ($(UCLIBC_ONLY),) diff --git a/test/dlopen/Makefile b/test/dlopen/Makefile index ef15d861d..92d14b90e 100644 --- a/test/dlopen/Makefile +++ b/test/dlopen/Makefile @@ -4,4 +4,9 @@ top_builddir=../../ include ../Rules.mak -include Makefile.in +ifneq ($(HAVE_SHARED),y) +TESTS_DISABLED := test3 +LDFLAGS_libtest.so := -lpthread +endif + include ../Test.mak diff --git a/test/nptl/Makefile b/test/nptl/Makefile new file mode 100644 index 000000000..a99c5d16f --- /dev/null +++ b/test/nptl/Makefile @@ -0,0 +1,7 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +top_builddir=../../ +include ../Rules.mak +-include Makefile.in +include ../Test.mak diff --git a/test/nptl/Makefile.in b/test/nptl/Makefile.in new file mode 100644 index 000000000..8c19577aa --- /dev/null +++ b/test/nptl/Makefile.in @@ -0,0 +1,146 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +TESTS := tst-align tst-align2 tst-atfork1 tst-attr1 tst-attr2 tst-attr3 \ + tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 tst-basic1 \ + tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ + tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel6 tst-cancel7 \ + tst-cancel8 tst-cancel9 tst-cancel10 tst-cancel11 tst-cancel12 \ + tst-cancel13 tst-cancel14 tst-cancel15 tst-cancel16 \ + tst-cancel19 tst-cancel20 tst-cancel21 tst-cancel22 \ + tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \ + tst-cleanup4 tst-clock1 tst-clock2 tst-cond1 tst-cond2 \ + tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 tst-cond8 \ + tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \ + tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 \ + tst-cond19 tst-cond20 tst-cond21 tst-detach1 tst-eintr1 \ + tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 tst-exec2 tst-exec3 \ + tst-exec4 tst-exit1 tst-exit2 tst-exit3 tst-flock1 tst-flock2 \ + tst-fork1 tst-fork2 tst-fork3 tst-fork4 tst-initializers1 \ + tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-key1 \ + tst-key2 tst-key3 tst-key4 tst-kill1 tst-kill2 tst-kill3 \ + tst-kill4 tst-kill5 tst-kill6 tst-mutex1 tst-mutex2 tst-mutex3 \ + tst-mutex4 tst-mutex5 tst-mutex6 tst-mutex7 tst-mutex8 \ + tst-mutex9 tst-mutex5a tst-mutex7a tst-once1 tst-once2 \ + tst-once3 tst-once4 tst-popen1 tst-raise1 tst-rwlock1 \ + tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 tst-rwlock6 \ + tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 tst-rwlock11 \ + tst-rwlock12 tst-rwlock13 tst-rwlock14 tst-sched1 tst-sem1 \ + tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 tst-sem8 \ + tst-sem9 tst-signal1 tst-signal2 tst-signal3 tst-signal4 \ + tst-signal5 tst-signal6 tst-spin1 tst-spin2 tst-spin3 \ + tst-stack1 tst-stack2 tst-stdio1 tst-stdio2 tst-sysconf \ + tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tsd1 tst-tsd2 \ + tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1 + +# +# These are for the RT library and POSIX timers. +# +TESTS += tst-clock tst-clock_nanosleep tst-cpuclock1 tst-cpuclock2 \ + tst-cputimer1 tst-cputimer2 tst-cputimer3 tst-mqueue1 \ + tst-mqueue2 tst-mqueue3 tst-mqueue4 tst-mqueue5 tst-mqueue6 \ + tst-mqueue7 tst-mqueue8 tst-mqueue9 tst-timer2 tst-timer3 \ + tst-timer4 tst-timer5 + +ifeq ($(UCLIBC_HAS_OBSOLETE_BSD_SIGNAL),) +TESTS_DISABLED := tst-exec2 tst-exec3 tst-exec4 +endif + +PTDIR := $(top_builddir)libpthread/nptl + +EXTRA_CFLAGS := -DNOT_IN_libc=1 -D_LIBC -D__USE_GNU -std=gnu99 \ + -I$(PTDIR) -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux \ + -I$(PTDIR)/sysdeps/pthread \ + -I$(PTDIR)/sysdeps/pthread/bits \ + -I$(PTDIR)/sysdeps/generic \ + -I$(top_builddir)ldso/include \ + -I$(top_builddir)ldso/ldso/$(TARGET_ARCH) \ + -include $(top_builddir)include/libc-symbols.h + +ifeq ($(TARGET_ARCH),i386) +CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4 +endif +ifeq ($(TARGET_ARCH),i686) +CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4 -msse +endif +CFLAGS_tst-cleanup4aux.o := -W -Wall -sjh +CFLAGS_tst-initializers1.o := -W -Wall -Werror +CFLAGS_tst-tls3.o := tst-tls3mod.so +CFLAGS_tst-tls4.o := tst-tls4moda.so tst-tls4modb.so +CFLAGS_tst-tls5.o := tst-tls5mod.so +CFLAGS_tst-tls3mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls4moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls4modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modc.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modd.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5mode.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modf.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc + +EXTRA_LDFLAGS := -lpthread + +LDFLAGS_tst-cleanup4 := tst-cleanup4aux.o +LDFLAGS_tst-clock2 := -lrt +LDFLAGS_tst-cond11 := -lrt +LDFLAGS_tst-cond19 := -lrt +LDFLAGS_tst-rwlock14 := -lrt +LDFLAGS_tst-tls3 := -ldl -rdynamic +LDFLAGS_tst-tls4 := -ldl +LDFLAGS_tst-tls5 := tst-tls5mod.so +LDFLAGS_tst-clock := -lrt +LDFLAGS_tst-clock_nanosleep := -lrt +LDFLAGS_tst-cpuclock1 := -lrt +LDFLAGS_tst-cpuclock2 := -lrt +LDFLAGS_tst-cputimer1 := -lrt +LDFLAGS_tst-cputimer2 := -lrt +LDFLAGS_tst-cputimer3 := -lrt +LDFLAGS_tst-mqueue1 := -lrt +LDFLAGS_tst-mqueue2 := -lrt +LDFLAGS_tst-mqueue3 := -lrt +LDFLAGS_tst-mqueue4 := -lrt +LDFLAGS_tst-mqueue5 := -lrt +LDFLAGS_tst-mqueue6 := -lrt +LDFLAGS_tst-mqueue7 := -lrt +LDFLAGS_tst-mqueue8 := -lrt +LDFLAGS_tst-mqueue9 := -lrt +LDFLAGS_tst-timer2 := -lrt +LDFLAGS_tst-timer3 := -lrt +LDFLAGS_tst-timer4 := -lrt +LDFLAGS_tst-timer5 := -lrt +LDFLAGS_tst-tls3mod.so := -shared -static-libgcc +LDFLAGS_tst-tls4moda.so := -shared -static-libgcc +LDFLAGS_tst-tls4modb.so := -shared -static-libgcc +LDFLAGS_tst-tls5mod.so := -shared -static-libgcc -Wl,-soname,tst-tls5mod.so +LDFLAGS_tst-tls5moda.so := -shared -static-libgcc +LDFLAGS_tst-tls5modb.so := -shared -static-libgcc +LDFLAGS_tst-tls5modc.so := -shared -static-libgcc +LDFLAGS_tst-tls5modd.so := -shared -static-libgcc +LDFLAGS_tst-tls5mode.so := -shared -static-libgcc +LDFLAGS_tst-tls5modf.so := -shared -static-libgcc + +# +# Special case +# +tst-cleanup4aux.o: + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c tst-cleanup4aux.c -o $@ + +tst-cleanup4: tst-cleanup4aux.o +tst-tls3: tst-tls3mod.so +tst-tls4: tst-tls4moda.so tst-tls4modb.so +tst-tls5: tst-tls5mod.so tst-tls5moda.so tst-tls5modb.so \ + tst-tls5modc.so tst-tls5modd.so tst-tls5mode.so tst-tls5modf.so + +OPTS_tst-cancel7 = --command ./tst-cancel7 +OPTS_tst-mqueue7 = -- ./tst-mqueue7 +OPTS_tst-exec4 = ./tst-exec4 + +RET_tst-clock2 := 1 +RET_tst-cputimer1 := 1 +RET_tst-cputimer2 := 1 +RET_tst-cputimer3 := 1 + +WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" TIMEOUTFACTOR=100 diff --git a/test/nptl/tst-align.c b/test/nptl/tst-align.c new file mode 100644 index 000000000..381db8f4e --- /dev/null +++ b/test/nptl/tst-align.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include "tst-stack-align.h" + +static void * +tf (void *arg) +{ + bool ok = true; + + puts ("in thread"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? NULL : (void *) -1l; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + return 1; + } + + if (res != NULL) + ok = false; + + return ok ? 0 : 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-align2.c b/test/nptl/tst-align2.c new file mode 100644 index 000000000..7d8be53da --- /dev/null +++ b/test/nptl/tst-align2.c @@ -0,0 +1,87 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> +#include "tst-stack-align.h" + +static int +f (void *arg) +{ + bool ok = true; + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? 0 : 1; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + +#ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, + size_t __child_stack_size, int __flags, + void *__arg, ...); + char st[256 * 1024]; + pid_t p = __clone2 (f, st, sizeof (st), 0, 0); +#else + char st[128 * 1024]; + pid_t p = clone (f, st + sizeof (st), 0, 0); +#endif + if (p == -1) + { + printf("clone failed: %m\n"); + return 1; + } + + int e; + if (waitpid (p, &e, __WCLONE) != p) + { + puts ("waitpid failed"); + kill (p, SIGKILL); + return 1; + } + if (!WIFEXITED (e)) + { + if (WIFSIGNALED (e)) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + else + puts ("did not terminate correctly"); + return 1; + } + if (WEXITSTATUS (e) != 0) + ok = false; + + return ok ? 0 : 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-atfork1.c b/test/nptl/tst-atfork1.c new file mode 100644 index 000000000..b42ab4246 --- /dev/null +++ b/test/nptl/tst-atfork1.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static int val; + + +static void +prepare1 (void) +{ + val *= 2; +} + +static void +prepare2 (void) +{ + ++val; +} + +static void +parent1 (void) +{ + val += 4; +} + +static void +parent2 (void) +{ + val *= 4; +} + +static void +child1 (void) +{ + val += 8; +} + +static void +child2 (void) +{ + val *= 8; +} + + +static int +do_test (void) +{ + pid_t pid; + int status = 0; + + if (pthread_atfork (prepare1, parent1, child1) != 0) + { + puts ("1st atfork failed"); + exit (1); + } + if (pthread_atfork (prepare2, parent2, child2) != 0) + { + puts ("2nd atfork failed"); + exit (1); + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid != 0) + { + /* Parent. */ + if (val != 24) + { + printf ("expected val=%d, got %d\n", 24, val); + exit (1); + } + + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + exit (1); + } + } + else + { + /* Child. */ + if (val != 80) + { + printf ("expected val=%d, got %d\n", 80, val); + exit (2); + } + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr1.c b/test/nptl/tst-attr1.c new file mode 100644 index 000000000..13b62a69d --- /dev/null +++ b/test/nptl/tst-attr1.c @@ -0,0 +1,306 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + int i; + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + pthread_mutexattr_t ma; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + pthread_rwlockattr_t rwa; + + if (pthread_rwlockattr_init (&rwa) != 0) + { + puts ("rwlockattr_init failed"); + exit (1); + } + + /* XXX Remove if default value is clear. */ + pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED); + pthread_attr_setschedpolicy (&a, SCHED_OTHER); + pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM); + + for (i = 0; i < 10000; ++i) + { + long int r = random (); + + if (r != PTHREAD_CREATE_DETACHED && r != PTHREAD_CREATE_JOINABLE) + { + int e = pthread_attr_setdetachstate (&a, r); + + if (e == 0) + { + printf ("attr_setdetachstate with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setdetachstate didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("attr_getdetachstate failed"); + exit (1); + } + + if (s != PTHREAD_CREATE_JOINABLE) + { + printf ("\ +detach state changed to %d by invalid setdetachstate call\n", s); + exit (1); + } + } + + if (r != PTHREAD_INHERIT_SCHED && r != PTHREAD_EXPLICIT_SCHED) + { + int e = pthread_attr_setinheritsched (&a, r); + + if (e == 0) + { + printf ("attr_setinheritsched with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setinheritsched didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("attr_getinheritsched failed"); + exit (1); + } + + if (s != PTHREAD_INHERIT_SCHED) + { + printf ("\ +inheritsched changed to %d by invalid setinheritsched call\n", s); + exit (1); + } + } + + if (r != SCHED_OTHER && r != SCHED_RR && r != SCHED_FIFO) + { + int e = pthread_attr_setschedpolicy (&a, r); + + if (e == 0) + { + printf ("attr_setschedpolicy with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setschedpolicy didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("attr_getschedpolicy failed"); + exit (1); + } + + if (s != SCHED_OTHER) + { + printf ("\ +schedpolicy changed to %d by invalid setschedpolicy call\n", s); + exit (1); + } + } + + if (r != PTHREAD_SCOPE_SYSTEM && r != PTHREAD_SCOPE_PROCESS) + { + int e = pthread_attr_setscope (&a, r); + + if (e == 0) + { + printf ("attr_setscope with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setscope didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("attr_getscope failed"); + exit (1); + } + + if (s != PTHREAD_SCOPE_SYSTEM) + { + printf ("\ +contentionscope changed to %d by invalid setscope call\n", s); + exit (1); + } + } + + if (r != PTHREAD_PROCESS_PRIVATE && r != PTHREAD_PROCESS_SHARED) + { + int e = pthread_mutexattr_setpshared (&ma, r); + + if (e == 0) + { + printf ("mutexattr_setpshared with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("mutexattr_setpshared didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_mutexattr_getpshared (&ma, &s) != 0) + { + puts ("mutexattr_getpshared failed"); + exit (1); + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + printf ("\ +pshared changed to %d by invalid mutexattr_setpshared call\n", s); + exit (1); + } + + e = pthread_rwlockattr_setpshared (&rwa, r); + + if (e == 0) + { + printf ("rwlockattr_setpshared with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("rwlockattr_setpshared didn't return EINVAL"); + exit (1); + } + + if (pthread_rwlockattr_getpshared (&rwa, &s) != 0) + { + puts ("rwlockattr_getpshared failed"); + exit (1); + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + printf ("\ +pshared changed to %d by invalid rwlockattr_setpshared call\n", s); + exit (1); + } + } + + if (r != PTHREAD_CANCEL_ENABLE && r != PTHREAD_CANCEL_DISABLE) + { + int e = pthread_setcancelstate (r, NULL); + + if (e == 0) + { + printf ("setcancelstate with value %ld succeeded\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("setcancelstate didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &s) != 0) + { + puts ("setcancelstate failed for PTHREAD_CANCEL_ENABLE"); + exit (1); + } + + if (s != PTHREAD_CANCEL_ENABLE) + { + puts ("invalid setcancelstate changed state"); + exit (1); + } + } + + if (r != PTHREAD_CANCEL_DEFERRED && r != PTHREAD_CANCEL_ASYNCHRONOUS) + { + int e = pthread_setcanceltype (r, NULL); + + if (e == 0) + { + printf ("setcanceltype with value %ld succeeded\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("setcanceltype didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &s) != 0) + { + puts ("setcanceltype failed for PTHREAD_CANCEL_DEFERRED"); + exit (1); + } + + if (s != PTHREAD_CANCEL_DEFERRED) + { + puts ("invalid setcanceltype changed state"); + exit (1); + } + } + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr2.c b/test/nptl/tst-attr2.c new file mode 100644 index 000000000..a60598dd7 --- /dev/null +++ b/test/nptl/tst-attr2.c @@ -0,0 +1,317 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + /* Check default value of detach state. */ + int s; + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("1st attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_JOINABLE) + { + printf ("\ +default detach state wrong: %d, expected %d (PTHREAD_CREATE_JOINABLE)\n", + s, PTHREAD_CREATE_JOINABLE); + exit (1); + } + + int e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED); + if (e != 0) + { + puts ("1st attr_setdetachstate failed"); + exit (1); + } + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("2nd attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_DETACHED) + { + puts ("PTHREAD_CREATE_DETACHED set, but not given back"); + exit (1); + } + + e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_JOINABLE); + if (e != 0) + { + puts ("2nd attr_setdetachstate failed"); + exit (1); + } + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("3rd attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_JOINABLE) + { + puts ("PTHREAD_CREATE_JOINABLE set, but not given back"); + exit (1); + } + + + size_t g; + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("1st attr_getguardsize failed"); + exit (1); + } + if (g != (size_t) sysconf (_SC_PAGESIZE)) + { + printf ("default guardsize %zu, expected %ld (PAGESIZE)\n", + g, sysconf (_SC_PAGESIZE)); + exit (1); + } + + e = pthread_attr_setguardsize (&a, 0); + if (e != 0) + { + puts ("1st attr_setguardsize failed"); + exit (1); + } + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("2nd attr_getguardsize failed"); + exit (1); + } + if (g != 0) + { + printf ("guardsize set to zero but %zu returned\n", g); + exit (1); + } + + e = pthread_attr_setguardsize (&a, 1); + if (e != 0) + { + puts ("2nd attr_setguardsize failed"); + exit (1); + } + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("3rd attr_getguardsize failed"); + exit (1); + } + if (g != 1) + { + printf ("guardsize set to 1 but %zu returned\n", g); + exit (1); + } + + + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("1st attr_getinheritsched failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != PTHREAD_INHERIT_SCHED && s != PTHREAD_EXPLICIT_SCHED) + { + puts ("incorrect default value for inheritsched"); + exit (1); + } + + e = pthread_attr_setinheritsched (&a, PTHREAD_EXPLICIT_SCHED); + if (e != 0) + { + puts ("1st attr_setinheritsched failed"); + exit (1); + } + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("2nd attr_getinheritsched failed"); + exit (1); + } + if (s != PTHREAD_EXPLICIT_SCHED) + { + printf ("inheritsched set to PTHREAD_EXPLICIT_SCHED, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED); + if (e != 0) + { + puts ("2nd attr_setinheritsched failed"); + exit (1); + } + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("3rd attr_getinheritsched failed"); + exit (1); + } + if (s != PTHREAD_INHERIT_SCHED) + { + printf ("inheritsched set to PTHREAD_INHERIT_SCHED, but got %d\n", s); + exit (1); + } + + + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("1st attr_getschedpolicy failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != SCHED_OTHER && s != SCHED_FIFO && s != SCHED_RR) + { + puts ("incorrect default value for schedpolicy"); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_RR); + if (e != 0) + { + puts ("1st attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("2nd attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_RR) + { + printf ("schedpolicy set to SCHED_RR, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_FIFO); + if (e != 0) + { + puts ("2nd attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("3rd attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_FIFO) + { + printf ("schedpolicy set to SCHED_FIFO, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_OTHER); + if (e != 0) + { + puts ("3rd attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("4th attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_OTHER) + { + printf ("schedpolicy set to SCHED_OTHER, but got %d\n", s); + exit (1); + } + + + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("1st attr_getscope failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != PTHREAD_SCOPE_SYSTEM && s != PTHREAD_SCOPE_PROCESS) + { + puts ("incorrect default value for contentionscope"); + exit (1); + } + + e = pthread_attr_setscope (&a, PTHREAD_SCOPE_PROCESS); + if (e != ENOTSUP) + { + if (e != 0) + { + puts ("1st attr_setscope failed"); + exit (1); + } + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("2nd attr_getscope failed"); + exit (1); + } + if (s != PTHREAD_SCOPE_PROCESS) + { + printf ("\ +contentionscope set to PTHREAD_SCOPE_PROCESS, but got %d\n", s); + exit (1); + } + } + + e = pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM); + if (e != 0) + { + puts ("2nd attr_setscope failed"); + exit (1); + } + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("3rd attr_getscope failed"); + exit (1); + } + if (s != PTHREAD_SCOPE_SYSTEM) + { + printf ("contentionscope set to PTHREAD_SCOPE_SYSTEM, but got %d\n", s); + exit (1); + } + + char buf[1]; + e = pthread_attr_setstack (&a, buf, 1); + if (e != EINVAL) + { + puts ("setstack with size 1 did not produce EINVAL"); + exit (1); + } + + e = pthread_attr_setstacksize (&a, 1); + if (e != EINVAL) + { + puts ("setstacksize with size 1 did not produce EINVAL"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr3.c b/test/nptl/tst-attr3.c new file mode 100644 index 000000000..29b4bbe37 --- /dev/null +++ b/test/nptl/tst-attr3.c @@ -0,0 +1,420 @@ +/* pthread_getattr_np test. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +tf (void *arg) +{ + pthread_attr_t a, *ap, a2; + int err; + void *result = NULL; + + if (arg == NULL) + { + ap = &a2; + err = pthread_attr_init (ap); + if (err) + { + error (0, err, "pthread_attr_init failed"); + return tf; + } + } + else + ap = (pthread_attr_t *) arg; + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = tf; + } + + int detachstate1, detachstate2; + err = pthread_attr_getdetachstate (&a, &detachstate1); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else + { + err = pthread_attr_getdetachstate (ap, &detachstate2); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else if (detachstate1 != detachstate2) + { + error (0, 0, "detachstate differs %d != %d", + detachstate1, detachstate2); + result = tf; + } + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = tf; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover thread's stack"); + result = tf; + } + else + printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize, + stacksize); + + size_t guardsize1, guardsize2; + err = pthread_attr_getguardsize (&a, &guardsize1); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else + { + err = pthread_attr_getguardsize (ap, &guardsize2); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else if (guardsize1 != guardsize2) + { + error (0, 0, "guardsize differs %zd != %zd", + guardsize1, guardsize2); + result = tf; + } + else + printf ("thread guardsize %zd\n", guardsize1); + } + + int scope1, scope2; + err = pthread_attr_getscope (&a, &scope1); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else + { + err = pthread_attr_getscope (ap, &scope2); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else if (scope1 != scope2) + { + error (0, 0, "scope differs %d != %d", + scope1, scope2); + result = tf; + } + } + + int inheritsched1, inheritsched2; + err = pthread_attr_getinheritsched (&a, &inheritsched1); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = tf; + } + else + { + err = pthread_attr_getinheritsched (ap, &inheritsched2); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = tf; + } + else if (inheritsched1 != inheritsched2) + { + error (0, 0, "inheritsched differs %d != %d", + inheritsched1, inheritsched2); + result = tf; + } + } + + cpu_set_t c1, c2; + err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); + if (err == 0) + { + err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); + if (err) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = tf; + } + else if (memcmp (&c1, &c2, sizeof (c1))) + { + error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); + result = tf; + } + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + + if (ap == &a2) + { + err = pthread_attr_destroy (ap); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + } + + return result; +} + + +static int +do_test (void) +{ + int result = 0; + pthread_attr_t a; + cpu_set_t c1, c2; + + int err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_attr_getaffinity_np (&a, sizeof (c1), &c1); + if (err && err != ENOSYS) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = 1; + } + + int detachstate; + err = pthread_attr_getdetachstate (&a, &detachstate); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = 1; + } + else if (detachstate != PTHREAD_CREATE_JOINABLE) + { + error (0, 0, "initial thread not joinable"); + result = 1; + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = 1; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover main's stack"); + result = 1; + } + else + printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr, + stackaddr + stacksize, stacksize); + + size_t guardsize; + err = pthread_attr_getguardsize (&a, &guardsize); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = 1; + } + else if (guardsize != 0) + { + error (0, 0, "pthread_attr_getguardsize returned %zd != 0", + guardsize); + result = 1; + } + + int scope; + err = pthread_attr_getscope (&a, &scope); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = 1; + } + else if (scope != PTHREAD_SCOPE_SYSTEM) + { + error (0, 0, "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM", + scope); + result = 1; + } + + int inheritsched; + err = pthread_attr_getinheritsched (&a, &inheritsched); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = 1; + } + else if (inheritsched != PTHREAD_INHERIT_SCHED) + { + error (0, 0, "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED", + inheritsched); + result = 1; + } + + err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); + if (err == 0) + { + err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); + if (err) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = 1; + } + else if (memcmp (&c1, &c2, sizeof (c1))) + { + error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); + result = 1; + } + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + pthread_t th; + err = pthread_create (&th, NULL, tf, NULL); + if (err) + { + error (0, err, "pthread_create #1 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #1 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #2 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #2 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_setguardsize (&a, 16 * sysconf (_SC_PAGESIZE)); + if (err) + { + error (0, err, "pthread_attr_setguardsize failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #3 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #3 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier1.c b/test/nptl/tst-barrier1.c new file mode 100644 index 000000000..2859fb4ca --- /dev/null +++ b/test/nptl/tst-barrier1.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_barrier_t b; + int e; + int cnt; + + e = pthread_barrier_init (&b, NULL, 0); + if (e == 0) + { + puts ("barrier_init with count 0 succeeded"); + return 1; + } + if (e != EINVAL) + { + puts ("barrier_init with count 0 didn't return EINVAL"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 1) != 0) + { + puts ("real barrier_init failed"); + return 1; + } + + for (cnt = 0; cnt < 10; ++cnt) + { + e = pthread_barrier_wait (&b); + + if (e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait didn't return PTHREAD_BARRIER_SERIAL_THREAD"); + return 1; + } + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier2.c b/test/nptl/tst-barrier2.c new file mode 100644 index 000000000..7f588694d --- /dev/null +++ b/test/nptl/tst-barrier2.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-barrier2.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_barrier_t *b; + pthread_barrierattr_t a; + pid_t pid; + int serials = 0; + int cnt; + int status; + int p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("1st barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("2nd barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + /* Just to be sure we don't hang forever. */ + alarm (4); + +#define N 30 + for (cnt = 0; cnt < N; ++cnt) + { + int e; + + e = pthread_barrier_wait (b); + if (e == PTHREAD_BARRIER_SERIAL_THREAD) + ++serials; + else if (e != 0) + { + printf ("%s: barrier_wait returned value %d != 0 and PTHREAD_BARRIER_SERIAL_THREAD\n", + pid == 0 ? "child" : "parent", e); + return 1; + } + } + + alarm (0); + + printf ("%s: was %d times the serial thread\n", + pid == 0 ? "child" : "parent", serials); + + if (pid == 0) + /* The child. Pass the number of times we had the serializing + thread back to the parent. */ + exit (serials); + + if (waitpid (pid, &status, 0) != pid) + { + puts ("waitpid failed"); + return 1; + } + + if (!WIFEXITED (status)) + { + puts ("child exited abnormally"); + return 1; + } + + if (WEXITSTATUS (status) + serials != N) + { + printf ("total number of serials is %d, expected %d\n", + WEXITSTATUS (status) + serials, N); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier3.c b/test/nptl/tst-barrier3.c new file mode 100644 index 000000000..b5478f827 --- /dev/null +++ b/test/nptl/tst-barrier3.c @@ -0,0 +1,154 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Test of POSIX barriers. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NTHREADS 20 + +#define ROUNDS 20 + +static pthread_barrier_t barriers[NTHREADS]; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int counters[NTHREADS]; +static int serial[NTHREADS]; + +static void * +worker (void *arg) +{ + void *result = NULL; + int nr = (long int) arg; + int i; + + for (i = 0; i < ROUNDS; ++i) + { + int j; + int retval; + + if (nr == 0) + { + memset (counters, '\0', sizeof (counters)); + memset (serial, '\0', sizeof (serial)); + } + + retval = pthread_barrier_wait (&barriers[NTHREADS - 1]); + if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d failed to wait for all the others\n", nr); + result = (void *) 1; + } + + for (j = nr; j < NTHREADS; ++j) + { + /* Increment the counter for this round. */ + pthread_mutex_lock (&lock); + ++counters[j]; + pthread_mutex_unlock (&lock); + + /* Wait for the rest. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Test the result. */ + if (nr == 0 && counters[j] != j + 1) + { + printf ("barrier in round %d released but count is %d\n", + j, counters[j]); + result = (void *) 1; + } + + if (retval != 0) + { + if (retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n", + nr, j); + result = (void *) 1; + } + else + { + pthread_mutex_lock (&lock); + ++serial[j]; + pthread_mutex_unlock (&lock); + } + } + + /* Wait for the rest again. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Now we can check whether exactly one thread was serializing. */ + if (nr == 0 && serial[j] != 1) + { + printf ("not exactly one serial thread in round %d\n", j); + result = (void *) 1; + } + } + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 60 +static int +do_test (void) +{ + pthread_t threads[NTHREADS]; + int i; + void *res; + int result = 0; + + /* Initialized the barrier variables. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0) + { + printf ("Failed to initialize barrier %d\n", i); + exit (1); + } + + /* Start the threads. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0) + { + printf ("Failed to start thread %d\n", i); + exit (1); + } + + /* And wait for them. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_join (threads[i], &res) != 0 || res != NULL) + { + printf ("thread %d returned a failure\n", i); + result = 1; + } + else + printf ("joined threads %d\n", i); + + if (result == 0) + puts ("all OK"); + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier4.c b/test/nptl/tst-barrier4.c new file mode 100644 index 000000000..efc27551c --- /dev/null +++ b/test/nptl/tst-barrier4.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This is a test for behavior not guaranteed by POSIX. */ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b1; +static pthread_barrier_t b2; + + +#define N 20 + +static void * +tf (void *arg) +{ + int round = 0; + + while (round++ < 30) + { + if (pthread_barrier_wait (&b1) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b1); + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("tf: 1st barrier_init failed"); + exit (1); + } + } + + if (pthread_barrier_wait (&b2) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b2); + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("tf: 2nd barrier_init failed"); + exit (1); + } + } + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("1st barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("2nd barrier_init failed"); + return 1; + } + + pthread_t th[N - 1]; + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_create (&th[cnt], &at, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + tf (NULL); + + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic1.c b/test/nptl/tst-basic1.c new file mode 100644 index 000000000..7637c8e49 --- /dev/null +++ b/test/nptl/tst-basic1.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> + + +static pid_t pid; + +static void * +tf (void *a) +{ + if (getpid () != pid) + { + write (2, "pid mismatch\n", 13); + _exit (1); + } + + return a; +} + + +int +do_test (void) +{ + pid = getpid (); + +#define N 2 + pthread_t t[N]; + int i; + + for (i = 0; i < N; ++i) + if (pthread_create (&t[i], NULL, tf, (void *) (long int) (i + 1)) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + else + printf ("created thread %d\n", i); + + for (i = 0; i < N; ++i) + { + void *r; + int e; + if ((e = pthread_join (t[i], &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + else if (r != (void *) (long int) (i + 1)) + { + write (2, "result wrong\n", 13); + _exit (1); + } + else + printf ("joined thread %d\n", i); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic2.c b/test/nptl/tst-basic2.c new file mode 100644 index 000000000..1c4632ceb --- /dev/null +++ b/test/nptl/tst-basic2.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + + +#define N 20 + +static pthread_t th[N]; +static pthread_mutex_t lock[N]; + + +static void *tf (void *a) +{ + uintptr_t idx = (uintptr_t) a; + + pthread_mutex_lock (&lock[idx]); + + return pthread_equal (pthread_self (), th[idx]) ? NULL : (void *) 1l; +} + + +int +do_test (void) +{ + if (pthread_equal (pthread_self (), pthread_self ()) == 0) + { + puts ("pthread_equal (pthread_self (), pthread_self ()) failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + { + if (pthread_mutex_init (&lock[i], NULL) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + if (pthread_mutex_lock (&lock[i]) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_mutex_unlock (&lock[i]) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + printf ("created thread %d\n", i); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + int result = 0; + for (i = 0; i < N; ++i) + { + void *r; + int e; + if ((e = pthread_join (th[i], &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + else if (r != NULL) + result = 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic3.c b/test/nptl/tst-basic3.c new file mode 100644 index 000000000..cb4816d2a --- /dev/null +++ b/test/nptl/tst-basic3.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int nrunning = 1; + + +static void +final_test (void) +{ + puts ("final_test has been called"); + +#define THE_SIGNAL SIGUSR1 + kill (getpid (), SIGUSR1); +} + + +static void * +tf (void *a) +{ + if (pthread_join ((pthread_t) a, NULL) != 0) + { + printf ("join failed while %d are running\n", nrunning); + _exit (1); + } + + printf ("%2d left\n", --nrunning); + + return NULL; +} + + +int +do_test (void) +{ +#define N 20 + pthread_t t[N]; + pthread_t last = pthread_self (); + int i; + + atexit (final_test); + + printf ("starting %d + 1 threads\n", N); + for (i = 0; i < N; ++i) + { + if (pthread_create (&t[i], NULL, tf, (void *) last) != 0) + { + puts ("create failed"); + _exit (1); + } + + ++nrunning; + + last = t[i]; + } + + printf ("%2d left\n", --nrunning); + + pthread_exit (NULL); +} + + +#define EXPECTED_SIGNAL THE_SIGNAL +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic4.c b/test/nptl/tst-basic4.c new file mode 100644 index 000000000..6eb6ea9f1 --- /dev/null +++ b/test/nptl/tst-basic4.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void +final_test (void) +{ + puts ("final_test has been called"); + +#define THE_SIGNAL SIGUSR1 + kill (getpid (), SIGUSR1); +} + + +static void * +tf (void *a) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + atexit (final_test); + + pthread_exit (NULL); + } + + int r; + int e = TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)); + if (e != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (! WIFSIGNALED (r)) + { + puts ("child not signled"); + exit (1); + } + + if (WTERMSIG (r) != THE_SIGNAL) + { + puts ("child's termination signal wrong"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic5.c b/test/nptl/tst-basic5.c new file mode 100644 index 000000000..83a8810f1 --- /dev/null +++ b/test/nptl/tst-basic5.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + + +int +do_test (void) +{ + int c = pthread_getconcurrency (); + if (c != 0) + { + puts ("initial concurrencylevel wrong"); + exit (1); + } + + if (pthread_setconcurrency (1) != 0) + { + puts ("setconcurrency failed"); + exit (1); + } + + c = pthread_getconcurrency (); + if (c != 1) + { + puts ("getconcurrency didn't return the value previous set"); + exit (1); + } + + int e = pthread_setconcurrency (-1); + if (e == 0) + { + puts ("setconcurrency of negative value didn't failed"); + exit (1); + } + if (e != EINVAL) + { + puts ("setconcurrency didn't return EINVAL for negative value"); + exit (1); + } + + c = pthread_getconcurrency (); + if (c != 1) + { + puts ("invalid getconcurrency changed level"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic6.c b/test/nptl/tst-basic6.c new file mode 100644 index 000000000..413ae034b --- /dev/null +++ b/test/nptl/tst-basic6.c @@ -0,0 +1,132 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static char *p; + +static pthread_barrier_t b; +#define BT \ + e = pthread_barrier_wait (&b); \ + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) \ + { \ + puts ("barrier_wait failed"); \ + exit (1); \ + } + + +static void * +tf (void *a) +{ + int e; + + BT; + + char *p2 = getcwd (NULL, 0); + if (p2 == NULL) + { + puts ("2nd getcwd failed"); + exit (1); + } + + if (strcmp (p, p2) != 0) + { + printf ("initial cwd mismatch: \"%s\" vs \"%s\"\n", p, p2); + exit (1); + } + + free (p); + free (p2); + + if (chdir ("..") != 0) + { + puts ("chdir failed"); + exit (1); + } + + p = getcwd (NULL, 0); + if (p == NULL) + { + puts ("getcwd failed"); + exit (1); + } + + return a; +} + + +int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + p = getcwd (NULL, 0); + if (p == NULL) + { + puts ("getcwd failed"); + exit (1); + } + + int e; + BT; + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + char *p2 = getcwd (NULL, 0); + if (p2 == NULL) + { + puts ("2nd getcwd failed"); + exit (1); + } + + if (strcmp (p, p2) != 0) + { + printf ("cwd after chdir mismatch: \"%s\" vs \"%s\"\n", p, p2); + exit (1); + } + + free (p); + free (p2); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel1.c b/test/nptl/tst-cancel1.c new file mode 100644 index 000000000..690319d8c --- /dev/null +++ b/test/nptl/tst-cancel1.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +static int cntr; + + +static void +cleanup (void *arg) +{ + if (arg != (void *) 42l) + cntr = 42; + else + cntr = 1; +} + + +static void * +tf (void *arg) +{ + /* Ignore all signals. This must not have any effect on delivering + the cancellation signal. */ + sigset_t ss; + + sigfillset (&ss); + + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + pthread_cleanup_push (cleanup, (void *) 42l); + + int err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (err != 0) + { + printf ("setcanceltype failed: %s\n", strerror (err)); + exit (1); + } + /* The following code is not standard compliant: the mutex functions + must not be called with asynchronous cancellation enabled. */ + + err = pthread_mutex_unlock (&m2); + if (err != 0) + { + printf ("child: mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("child: 1st mutex_lock failed: %s\n", strerror (err)); + exit (1); + } + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + pthread_t th; + int result = 0; + void *retval; + + /* Get the mutexes. */ + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("parent: 1st mutex_lock failed: %s\n", strerror (err)); + return 1; + } + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_cancel (th); + if (err != 0) + { + printf ("cancel failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, &retval); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (retval != PTHREAD_CANCELED) + { + printf ("wrong return value: %p\n", retval); + result = 1; + } + + if (cntr == 42) + { + puts ("cleanup handler called with wrong argument"); + result = 1; + } + else if (cntr != 1) + { + puts ("cleanup handling not called"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel10.c b/test/nptl/tst-cancel10.c new file mode 100644 index 000000000..7af0f2f84 --- /dev/null +++ b/test/nptl/tst-cancel10.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static void +cleanup (void *arg) +{ + /* Just for fun. */ + if (pthread_cancel (pthread_self ()) != 0) + { + puts ("cleanup: cancel failed"); + exit (1); + } + + printf ("cleanup for %ld\n", (long int) arg); +} + + +static void * +tf (void *arg) +{ + long int n = (long int) arg; + + pthread_cleanup_push (cleanup, arg); + + if (pthread_setcanceltype ((n & 1) == 0 + ? PTHREAD_CANCEL_DEFERRED + : PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0) + { + puts ("setcanceltype failed"); + exit (1); + } + + if (pthread_cancel (pthread_self ()) != 0) + { + puts ("cancel failed"); + exit (1); + } + + pthread_testcancel (); + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + +#define N 20 + int i; + pthread_t th[N]; + + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + void *r; + if (pthread_join (th[i], &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel11.c b/test/nptl/tst-cancel11.c new file mode 100644 index 000000000..235aef5c4 --- /dev/null +++ b/test/nptl/tst-cancel11.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static int fd[2]; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + char buf[20]; + read (fd[0], buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel12.c b/test/nptl/tst-cancel12.c new file mode 100644 index 000000000..6fdf5cf5f --- /dev/null +++ b/test/nptl/tst-cancel12.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + sem_wait (&sem); + + pthread_cleanup_pop (0); + + puts ("sem_wait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 1) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Check whether cancellation is honored even before sem_wait does + anything. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel13.c b/test/nptl/tst-cancel13.c new file mode 100644 index 000000000..66ab45509 --- /dev/null +++ b/test/nptl/tst-cancel13.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + sem_wait (&sem); + + pthread_cleanup_pop (0); + + puts ("sem_wait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + /* Give the child a chance to go to sleep in sem_wait. */ + sleep (1); + + /* Check whether cancellation is honored when waiting in sem_wait. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel14.c b/test/nptl/tst-cancel14.c new file mode 100644 index 000000000..592c0864f --- /dev/null +++ b/test/nptl/tst-cancel14.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Timeout in 5 seconds. */ + ts.tv_sec += 5; + + /* This call should block and be cancelable. */ + sem_timedwait (&sem, &ts); + + pthread_cleanup_pop (0); + + puts ("sem_timedwait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 1) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Check whether cancellation is honored even before sem_timedwait does + anything. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel15.c b/test/nptl/tst-cancel15.c new file mode 100644 index 000000000..5fd95022b --- /dev/null +++ b/test/nptl/tst-cancel15.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + int e; + + pthread_cleanup_push (cleanup, NULL); + + e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Timeout in 5 seconds. */ + ts.tv_sec += 5; + + /* This call should block and be cancelable. */ + errno = 0; + e = sem_timedwait (&sem, &ts); + + pthread_cleanup_pop (0); + + printf ("sem_timedwait returned, e = %d, errno = %d\n", e, errno); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + /* Give the child a chance to go to sleep in sem_wait. */ + sleep (1); + + /* Check whether cancellation is honored when waiting in sem_timedwait. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel16.c b/test/nptl/tst-cancel16.c new file mode 100644 index 000000000..709902e97 --- /dev/null +++ b/test/nptl/tst-cancel16.c @@ -0,0 +1,231 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static pthread_barrier_t b2; +static int fd; +static int called; + + +static void +cl (void *arg) +{ + called = 1; +} + + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + /* This call should never return. */ + (void) lockf (fd, F_LOCK, 0); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + char fname[] = "/tmp/cancel16XXXXXX"; + fd = mkstemp (fname); + if (fd == -1) + { + puts ("mkstemp failed"); + return 1; + } + unlink (fname); + + char mem[sizeof (pthread_barrier_t)]; + memset (mem, '\0', sizeof (mem)); + if (TEMP_FAILURE_RETRY (pwrite (fd, mem, sizeof (mem), 0)) != sizeof (mem)) + { + puts ("pwrite failed"); + return 1; + } + + void *p = mmap (NULL, sizeof (mem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + { + puts ("mmap failed"); + return 1; + } + pthread_barrier_t *b = (pthread_barrier_t *) p; + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + if (pthread_barrierattr_setpshared (&ba, 1) != 0) + { + puts ("barrierattr_setshared failed"); + return 1; + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("1st barrier_init failed"); + return 1; + } + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + pid_t pid = fork (); + if (pid == 0) + { + /* Child. Lock the file and wait. */ + if (lockf (fd, F_LOCK, 0) != 0) + { + puts ("child process: lockf failed"); + _exit (1); + } + + int r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child process: 1st barrier_wait failed"); + _exit (1); + } + + /* Make sure the process dies. */ + alarm (5); + + r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child process: 2nd barrier_wait failed"); + _exit (1); + } + + _exit (0); + } + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + int r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 1st barrier_wait failed"); + _exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("2nd barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 2nd barrier_wait failed"); + return 1; + } + + /* Delay. */ + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("join failed"); + return 1; + } + if (result != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + if (called == 0) + { + puts ("cleanup handler not called"); + return 1; + } + + r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 3rd barrier_wait failed"); + return 1; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + if (WEXITSTATUS (status) != 0) + { + printf ("child process exits with %d\n", WEXITSTATUS (status)); + return 1; + } + + if (lockf (fd, F_LOCK, 0) != 0) + { + puts ("main: lockf failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel19.c b/test/nptl/tst-cancel19.c new file mode 100644 index 000000000..7c248ae0f --- /dev/null +++ b/test/nptl/tst-cancel19.c @@ -0,0 +1,287 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/time.h> +#include <unistd.h> + +static void * +tf (void *arg) +{ + return NULL; +} + +static void +handler (int sig) +{ +} + +static void __attribute__ ((noinline)) +clobber_lots_of_regs (void) +{ +#define X1(n) long r##n = 10##n; __asm __volatile ("" : "+r" (r##n)); +#define X2(n) X1(n##0) X1(n##1) X1(n##2) X1(n##3) X1(n##4) +#define X3(n) X2(n##0) X2(n##1) X2(n##2) X2(n##3) X2(n##4) + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#define X1(n) __asm __volatile ("" : : "r" (r##n)); + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#undef X2 +#undef X3 +} + +static int +do_test (void) +{ + pthread_t th; + int old, rc; + int ret = 0; + int fd[2]; + + rc = pipe (fd); + if (rc < 0) + error (EXIT_FAILURE, errno, "couldn't create pipe"); + + rc = pthread_create (&th, NULL, tf, NULL); + if (rc) + error (EXIT_FAILURE, rc, "couldn't create thread"); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "1st pthread_setcanceltype failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "1st pthread_setcanceltype returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[0]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after close returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[1]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd close returned invalid value %d", + old); + ret = 1; + } + + struct sigaction sa = { .sa_handler = handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it; + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after pause returned invalid value %d", + old); + ret = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd pause returned invalid value %d", + old); + ret = 1; + } + + char fname[] = "/tmp/tst-cancel19-dir-XXXXXX\0foo/bar"; + char *enddir = strchr (fname, '\0'); + if (mkdtemp (fname) == NULL) + { + error (0, errno, "mkdtemp failed"); + ret = 1; + } + *enddir = '/'; + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after open returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd open returned invalid value %d", + old); + ret = 1; + } + + *enddir = '\0'; + rmdir (fname); + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after select returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd select returned invalid value %d", + old); + ret = 1; + } + + pthread_join (th, NULL); + + return ret; +} + +#define TIMEOUT 20 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel2.c b/test/nptl/tst-cancel2.c new file mode 100644 index 000000000..6d80f8ae5 --- /dev/null +++ b/test/nptl/tst-cancel2.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + /* The buffer size must be larger than the pipe size so that the + write blocks. */ + char buf[100000]; + + if (write (fd[1], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("write succeeded"); + return (void *) 1l; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the write in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel20.c b/test/nptl/tst-cancel20.c new file mode 100644 index 000000000..d88cb9caf --- /dev/null +++ b/test/nptl/tst-cancel20.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + return NULL; +} + + +static int +do_one_test (void) +{ + in_sh_body = 0; + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + return 1; + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + return 1; + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + return 1; + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel21.c b/test/nptl/tst-cancel21.c new file mode 100644 index 000000000..cc00cc168 --- /dev/null +++ b/test/nptl/tst-cancel21.c @@ -0,0 +1,294 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_t th = (pthread_t) arg; + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + exit (1); + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + exit (1); + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + exit (1); + } + + /* This will cause the read in the initial thread to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + exit (1); + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + exit (1); + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + exit (1); + } + + if (pthread_barrier_destroy (&b)) + { + puts ("barrier destroy failed"); + exit (1); + } + + exit (0); +} + + +static int +do_one_test (void) +{ + in_sh_body = 0; + + pid_t pid = fork (); + + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid) + { + int status; + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed %m\n"); + return 1; + } + + return !WIFEXITED (status) || WEXITSTATUS (status); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + exit (1); +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel22.c b/test/nptl/tst-cancel22.c new file mode 100644 index 000000000..33bfc64a3 --- /dev/null +++ b/test/nptl/tst-cancel22.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_barrier_t b; +int seen; + +static void * +tf (void *arg) +{ + int old; + int r = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old); + if (r != 0) + { + puts ("setcancelstate failed"); + exit (1); + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + for (int i = 0; i < 10; ++i) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + } + + seen = 1; + pthread_setcancelstate (old, NULL); + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + exit (1); +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("thread creation failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + if (seen != 1) + { + puts ("thread cancelled when PTHREAD_CANCEL_DISABLED"); + return 1; + } + + return 0; +} + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel3.c b/test/nptl/tst-cancel3.c new file mode 100644 index 000000000..86c482bcc --- /dev/null +++ b/test/nptl/tst-cancel3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + char buf[100]; + + if (read (fd[0], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("read succeeded"); + return (void *) 1l; + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel6.c b/test/nptl/tst-cancel6.c new file mode 100644 index 000000000..94de85830 --- /dev/null +++ b/test/nptl/tst-cancel6.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + char buf[100]; + fgets (buf, sizeof (buf), arg); + /* This call should never return. */ + return NULL; +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + FILE *fp = fdopen (fd[0], "r"); + if (fp == NULL) + { + puts ("fdopen failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, fp) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + return r != PTHREAD_CANCELED; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel7.c b/test/nptl/tst-cancel7.c new file mode 100644 index 000000000..16cc47cff --- /dev/null +++ b/test/nptl/tst-cancel7.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +const char *command; +const char *pidfile; +char pidfilename[] = "/tmp/tst-cancel7-XXXXXX"; + +static void * +tf (void *arg) +{ + const char *args = " --direct --pidfile "; + char *cmd = alloca (strlen (command) + strlen (args) + + strlen (pidfilename) + 1); + + strcpy (stpcpy (stpcpy (cmd, command), args), pidfilename); + system (cmd); + /* This call should never return. */ + return NULL; +} + + +static void +sl (void) +{ + FILE *f = fopen (pidfile, "w"); + if (f == NULL) + exit (1); + + fprintf (f, "%lld\n", (long long) getpid ()); + fflush (f); + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_SETLK, &fl) != 0) + exit (1); + + sigset_t ss; + sigfillset (&ss); + sigsuspend (&ss); + exit (0); +} + + +static void +do_prepare (int argc, char *argv[]) +{ + if (command == NULL) + command = argv[0]; + + if (pidfile) + sl (); + + int fd = mkstemp (pidfilename); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + write (fd, " ", 1); + close (fd); +} + + +static int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + do + sleep (1); + while (access (pidfilename, R_OK) != 0); + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + sleep (1); + + FILE *f = fopen (pidfilename, "r+"); + if (f == NULL) + { + puts ("no pidfile"); + return 1; + } + + long long ll; + if (fscanf (f, "%lld\n", &ll) != 1) + { + puts ("could not read pid"); + unlink (pidfilename); + return 1; + } + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_GETLK, &fl) != 0) + { + puts ("F_GETLK failed"); + unlink (pidfilename); + return 1; + } + + if (fl.l_type != F_UNLCK) + { + printf ("child %lld still running\n", (long long) fl.l_pid); + if (fl.l_pid == ll) + kill (fl.l_pid, SIGKILL); + + unlink (pidfilename); + return 1; + } + + fclose (f); + + unlink (pidfilename); + + return r != PTHREAD_CANCELED; +} + +#if 0 /* unused */ +static void +do_cleanup (void) +{ + FILE *f = fopen (pidfilename, "r+"); + long long ll; + + if (f != NULL && fscanf (f, "%lld\n", &ll) == 1) + { + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK + && fl.l_pid == ll) + kill (fl.l_pid, SIGKILL); + + fclose (f); + } + + unlink (pidfilename); +} +#endif + +#define OPT_COMMAND 10000 +#define OPT_PIDFILE 10001 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, \ + { "pidfile", required_argument, NULL, OPT_PIDFILE }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; \ + case OPT_PIDFILE: \ + pidfile = optarg; \ + break; +// #define CLEANUP_HANDLER do_cleanup () +#define PREPARE(argc, argv) do_prepare (argc, argv) +#define TEST_FUNCTION do_test () +#define TIMEOUT 5 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel8.c b/test/nptl/tst-cancel8.c new file mode 100644 index 000000000..fc836627d --- /dev/null +++ b/test/nptl/tst-cancel8.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_barrier_t bar; + +static int global; + + +static void +cleanup (void *arg) +{ + global = 1; +} + + +static void * +tf (void *arg) +{ + /* Enable cancellation, but defer it. */ + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0) + { + puts ("setcancelstate failed"); + exit (1); + } + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("setcanceltype failed"); + exit (1); + } + + /* Add cleanup handler. */ + pthread_cleanup_push (cleanup, NULL); + + /* Synchronize with the main thread. */ + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: first barrier_wait failed"); + exit (1); + } + + /* And again. Once this is done the main thread should have canceled + this thread. */ + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: second barrier_wait failed"); + exit (1); + } + + /* Remove the cleanup handler without executing it. */ + pthread_cleanup_pop (0); + + /* Now react on the cancellation. */ + pthread_testcancel (); + + /* This call should never return. */ + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("first barrier_wait failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("second barrier_wait failed"); + exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + if (result != PTHREAD_CANCELED) + { + puts ("thread was not canceled"); + exit (1); + } + + if (global != 0) + { + puts ("cancellation handler has been called"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel9.c b/test/nptl/tst-cancel9.c new file mode 100644 index 000000000..037ef30fd --- /dev/null +++ b/test/nptl/tst-cancel9.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +static void +cleanup (void *arg) +{ + fputs ("in cleanup\n", stdout); +} + + +static void * +tf (void *arg) +{ + int fd = open ("/dev/null", O_RDWR); + if (fd == -1) + { + puts ("cannot open /dev/null"); + exit (1); + } + FILE *fp = fdopen (fd, "w"); + if (fp == NULL) + { + puts ("fdopen failed"); + exit (1); + } + + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + /* fprintf() uses write() which is a cancallation point. */ + fprintf (fp, "foo"); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + sleep (1); + + puts ("cancel now"); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + exit (1); + } + + puts ("waiting for the child"); + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread wasn't canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup0.c b/test/nptl/tst-cleanup0.c new file mode 100644 index 000000000..6fc2209cc --- /dev/null +++ b/test/nptl/tst-cleanup0.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void +endfct (void) +{ + /* We force exit right here. */ + _exit (global); +} + + +static int +do_test (void) +{ + atexit (endfct); + + pthread_cancel (pthread_self ()); + + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + +// pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return 100; +} + + +#define EXPECTED_STATUS 9 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup1.c b/test/nptl/tst-cleanup1.c new file mode 100644 index 000000000..2230e0fbe --- /dev/null +++ b/test/nptl/tst-cleanup1.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void * +tf (void *a) +{ + pthread_cancel (pthread_self ()); + + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *r; + int e; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != 9) + { + printf ("global = %d, expected 9\n", global); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup2.c b/test/nptl/tst-cleanup2.c new file mode 100644 index 000000000..30e10b120 --- /dev/null +++ b/test/nptl/tst-cleanup2.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Bao Duong <bduong@progress.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +static sigjmp_buf jmpbuf; + +static void +sig_handler (int signo) +{ + siglongjmp (jmpbuf, 1); +} + +static int +do_test (void) +{ + char *p = NULL; + struct sigaction sa; + + sa.sa_handler = sig_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGSEGV, &sa, 0)) + { + perror ("installing SIGSEGV handler\n"); + exit (1); + } + + puts ("Attempting to sprintf to null ptr"); + if (setjmp (jmpbuf)) + { + puts ("Exiting main..."); + return 0; + } + + sprintf (p, "This should segv\n"); + + return 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup3.c b/test/nptl/tst-cleanup3.c new file mode 100644 index 000000000..c44277370 --- /dev/null +++ b/test/nptl/tst-cleanup3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void * +tf (void *a) +{ + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + + pthread_exit ((void *) 1l); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *r; + int e; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != (void *) 1l) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != 9) + { + printf ("global = %d, expected 9\n", global); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup4.c b/test/nptl/tst-cleanup4.c new file mode 100644 index 000000000..1489fd31b --- /dev/null +++ b/test/nptl/tst-cleanup4.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* LinuxThreads pthread_cleanup_{push,pop} helpers. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute); + +static int fds[2]; +static pthread_barrier_t b2; +static int global; + +/* Defined in tst-cleanup4aux.c, never compiled with -fexceptions. */ +extern void fn5 (void); +extern void fn7 (void); +extern void fn9 (void); + +void +clh (void *arg) +{ + int val = (long int) arg; + + printf ("clh (%d)\n", val); + + global *= val; + global += val; +} + + +static __attribute__((noinline)) void +fn_read (void) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char c; + read (fds[0], &c, 1); +} + + +__attribute__((noinline)) void +fn0 (void) +{ + pthread_cleanup_push (clh, (void *) 1l); + + fn_read (); + + pthread_cleanup_pop (1); +} + + +__attribute__((noinline)) void +fn1 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 2l); + + fn0 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn2 (void) +{ + pthread_cleanup_push (clh, (void *) 3l); + + fn1 (); + + pthread_cleanup_pop (1); +} + + +static void * +tf (void *a) +{ + switch ((long) a) + { + case 0: + fn2 (); + break; + case 1: + fn5 (); + break; + case 2: + fn7 (); + break; + case 3: + fn9 (); + break; + } + + return NULL; +} + + +int +do_test (void) +{ + int result = 0; + + if (pipe (fds) != 0) + { + puts ("pipe failed"); + exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + const int expect[] = + { + 15, /* 1 2 3 */ + 276, /* 1 4 5 6 */ + 120, /* 1 7 8 */ + 460 /* 1 2 9 10 */ + }; + + long i; + for (i = 0; i < 4; ++i) + { + global = 0; + + printf ("test %ld\n", i); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) i) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cancel (th); + + void *r; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != expect[i]) + { + printf ("global = %d, expected %d\n", global, expect[i]); + result = 1; + } + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup4aux.c b/test/nptl/tst-cleanup4aux.c new file mode 100644 index 000000000..cd1a89ac1 --- /dev/null +++ b/test/nptl/tst-cleanup4aux.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute); + +extern void clh (void *arg); +extern void fn0 (void); +extern void fn1 (void); +extern void fn5 (void); +extern void fn7 (void); +extern void fn9 (void); + + +static __attribute__((noinline)) void +fn3 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 4l); + + fn0 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn4 (void) +{ + pthread_cleanup_push (clh, (void *) 5l); + + fn3 (); + + pthread_cleanup_pop (1); +} + + +void +fn5 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 6l); + + fn4 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn6 (void) +{ + pthread_cleanup_push (clh, (void *) 7l); + + fn0 (); + + pthread_cleanup_pop (1); +} + + +void +fn7 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 8l); + + fn6 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn8 (void) +{ + pthread_cleanup_push (clh, (void *) 9l); + + fn1 (); + + pthread_cleanup_pop (1); +} + + +void +fn9 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 10l); + + fn8 (); + + _pthread_cleanup_pop (&b, 1); +} diff --git a/test/nptl/tst-clock.c b/test/nptl/tst-clock.c new file mode 100644 index 000000000..f2f18874a --- /dev/null +++ b/test/nptl/tst-clock.c @@ -0,0 +1,124 @@ +/* Test program for POSIX clock_* functions. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <string.h> +#include <time.h> + + +/* We want to see output immediately. */ +#define STDOUT_UNBUFFERED + +/* We expect to run at least 10 seconds. */ +#define TIMEOUT 15 + +static int +clock_test (clockid_t cl) +{ + struct timespec old_ts; + struct timespec ts; + struct timespec waitit; + int result = 0; + int i; + + memset (&ts, '\0', sizeof ts); + + waitit.tv_sec = 0; + waitit.tv_nsec = 500000000; + + /* Get and print resolution of the clock. */ + if (clock_getres (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of resolution wrong\n", cl); + result = 1; + } + else + printf ("clock %d: resolution = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + } + else + { + printf ("clock %d: cannot get resolution\n", cl); + result = 1; + } + + memset (&ts, '\0', sizeof ts); + memset (&old_ts, '\0', sizeof old_ts); + + /* Next get the current time value a few times. */ + for (i = 0; i < 10; ++i) + { + if (clock_gettime (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of time wrong (try %d)\n", + cl, i); + result = 1; + } + else + { + printf ("clock %d: time = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + + if (memcmp (&ts, &old_ts, sizeof ts) == 0) + { + printf ("clock %d: time hasn't changed (try %d)\n", cl, i); + result = 1; + + old_ts = ts; + } + } + } + else + { + printf ("clock %d: cannot get time (try %d)\n", cl, i); + result = 1; + } + + /* Wait a bit before the next iteration. */ + nanosleep (&waitit, NULL); + } + + return result; +} + +static int +do_test (void) +{ + clockid_t cl; + int result; + + result = clock_test (CLOCK_REALTIME); + + if (clock_getcpuclockid (0, &cl) == 0) + /* XXX It's not yet a bug when this fails. */ + clock_test (cl); + else + printf("CPU clock unavailble, skipping test\n"); + + return result; +} +#define TEST_FUNCTION do_test () + + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock1.c b/test/nptl/tst-clock1.c new file mode 100644 index 000000000..0848d7701 --- /dev/null +++ b/test/nptl/tst-clock1.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +int +do_test (void) +{ +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 + clockid_t cl; + /* This is really only a linking-test here. */ + int e = pthread_getcpuclockid (pthread_self (), &cl); + if (e != 0) + { +# if _POSIX_THREAD_CPUTIME == 0 + if (sysconf (_SC_THREAD_CPUTIME) >= 0) +# endif + { + puts ("cpuclock advertized, but cannot get ID"); + exit (1); + } + } +#endif + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock2.c b/test/nptl/tst-clock2.c new file mode 100644 index 000000000..49a769bf4 --- /dev/null +++ b/test/nptl/tst-clock2.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +static pthread_barrier_t b2; +static pthread_barrier_t bN; + + +static void * +tf (void *arg) +{ + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + return NULL; +} +#endif + + +int +do_test (void) +{ +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +# define N 10 + +# if _POSIX_THREAD_CPUTIME == 0 + if (sysconf (_SC_THREAD_CPUTIME) < 0) + { + puts ("_POSIX_THREAD_CPUTIME option not available"); + return 1; + } +# endif + + if (pthread_barrier_init (&b2, NULL, 2) != 0 + || pthread_barrier_init (&bN, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + pthread_t th[N + 1]; + clockid_t cl[N + 1]; +# ifndef CLOCK_THREAD_CPUTIME_ID + if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0) + { + puts ("own pthread_getcpuclockid failed"); + return 1; + } +# else + cl[0] = CLOCK_THREAD_CPUTIME_ID; +# endif + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + int e; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0) + { + puts ("pthread_getcpuclockid failed"); + return 1; + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + struct timespec t[N + 1]; + for (i = 0; i < N + 1; ++i) + if (clock_gettime (cl[i], &t[i]) != 0) + { + printf ("clock_gettime round %d failed\n", i); + return 1; + } + + for (i = 0; i < N; ++i) + { + struct timespec diff; + + diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec; + diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec; + if (diff.tv_nsec < 0) + { + diff.tv_nsec += 1000000000; + --diff.tv_sec; + } + + if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000)) + { + printf ("\ +difference between thread %d and %d too small (%ld.%09ld)\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + return 1; + } + + printf ("diff %d->%d: %ld.%09ld\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + } + + ts.tv_sec = 0; + ts.tv_nsec = 0; + for (i = 0; i < N + 1; ++i) + if (clock_settime (cl[i], &ts) != 0) + { + printf ("clock_settime(%d) round %d failed\n", cl[i], i); + return 1; + } + + for (i = 0; i < N + 1; ++i) + { + if (clock_gettime (cl[i], &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (ts.tv_sec > t[i].tv_sec + || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec)) + { + puts ("clock_settime didn't reset clock"); + return 1; + } + } +#endif + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock_nanosleep.c b/test/nptl/tst-clock_nanosleep.c new file mode 100644 index 000000000..98a8b5f57 --- /dev/null +++ b/test/nptl/tst-clock_nanosleep.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + + +/* Test that clock_nanosleep() does sleep. */ +static int +do_test (void) +{ + /* Current time. */ + struct timeval tv1; + (void) gettimeofday (&tv1, NULL); + + struct timespec ts; + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts)); + + /* At least one second must have passed. */ + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + tv2.tv_sec -= tv1.tv_sec; + tv2.tv_usec -= tv1.tv_usec; + if (tv2.tv_usec < 0) + --tv2.tv_sec; + + if (tv2.tv_sec < 1) + { + puts ("clock_nanosleep didn't sleep long enough"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond1.c b/test/nptl/tst-cond1.c new file mode 100644 index 000000000..46085c2b7 --- /dev/null +++ b/test/nptl/tst-cond1.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *p) +{ + int err; + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot get mutex"); + + puts ("child: got mutex; signalling"); + + pthread_cond_signal (&cond); + + puts ("child: unlock"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot unlock"); + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot get mutex"); + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot create thread"); + + puts ("parent: wait for condition"); + + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot wait fir signal"); + + puts ("parent: got signal"); + + err = pthread_join (th, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: failed to join"); + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond10.c b/test/nptl/tst-cond10.c new file mode 100644 index 000000000..34956d468 --- /dev/null +++ b/test/nptl/tst-cond10.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <error.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +#define N 10 +#define ROUNDS 100 + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t bN1; +static pthread_barrier_t b2; + + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("child: 1st mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 1st barrier_wait failed"); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("child: mutex_unlock failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 2nd barrier_wait failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bN1, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int r; + for (r = 0; r < ROUNDS; ++r) + { + printf ("round %d\n", r + 1); + + int i; + pthread_t th[N]; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 1st barrier_wait failed"); + exit (1); + } + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + /* N single signal calls. Without locking. This tests that no + signal gets lost. */ + for (i = 0; i < N; ++i) + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 2nd barrier_wait failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond11.c b/test/nptl/tst-cond11.c new file mode 100644 index 000000000..0de4d5613 --- /dev/null +++ b/test/nptl/tst-cond11.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 +static int +run_test (clockid_t cl) +{ + pthread_condattr_t condattr; + pthread_cond_t cond; + pthread_mutexattr_t mutattr; + pthread_mutex_t mut; + + printf ("clock = %d\n", (int) cl); + + if (pthread_condattr_init (&condattr) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("condattr_setclock failed"); + return 1; + } + + clockid_t cl2; + if (pthread_condattr_getclock (&condattr, &cl2) != 0) + { + puts ("condattr_getclock failed"); + return 1; + } + if (cl != cl2) + { + printf ("condattr_getclock returned wrong value: %d, expected %d\n", + (int) cl2, (int) cl); + return 1; + } + + if (pthread_cond_init (&cond, &condattr) != 0) + { + puts ("cond_init failed"); + return 1; + } + + if (pthread_condattr_destroy (&condattr) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + if (pthread_mutexattr_init (&mutattr) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&mut, &mutattr) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&mutattr) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != EDEADLK) + { + puts ("2nd mutex_lock did not return EDEADLK"); + return 1; + } + + struct timespec ts; + if (clock_gettime (cl, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + /* Wait one second. */ + ++ts.tv_sec; + + int e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("cond_timedwait succeeded"); + return 1; + } + else if (e != ETIMEDOUT) + { + puts ("cond_timedwait did not return ETIMEDOUT"); + return 1; + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&mut) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_cond_destroy (&cond) != 0) + { + puts ("cond_destroy failed"); + return 1; + } + + return 0; +} +#endif + + +static int +do_test (void) +{ +#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1 + + puts ("_POSIX_CLOCK_SELECTION not supported, test skipped"); + return 0; + +#else + + int res = run_test (CLOCK_REALTIME); + +# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0 +# if _POSIX_MONOTONIC_CLOCK == 0 + int e = sysconf (_SC_MONOTONIC_CLOCK); + if (e < 0) + puts ("CLOCK_MONOTONIC not supported"); + else if (e == 0) + { + puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); + res = 1; + } + else +# endif + res |= run_test (CLOCK_MONOTONIC); +# else + puts ("_POSIX_MONOTONIC_CLOCK not defined"); +# endif + + return res; +#endif +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond12.c b/test/nptl/tst-cond12.c new file mode 100644 index 000000000..03e4881c9 --- /dev/null +++ b/test/nptl/tst-cond12.c @@ -0,0 +1,196 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static char fname[] = "/tmp/tst-cond12-XXXXXX"; +static int fd; + + +static void prepare (void); +#define PREPARE(argc, argv) prepare () + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + + +static void +prepare (void) +{ + fd = mkstemp (fname); + if (fd == -1) + { + printf ("mkstemp failed: %m\n"); + exit (1); + } + add_temp_file (fname); + if (ftruncate (fd, 1000) < 0) + { + printf ("ftruncate failed: %m\n"); + exit (1); + } +} + + +static int +do_test (void) +{ + struct + { + pthread_mutex_t m; + pthread_cond_t c; + int var; + } *p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + { + printf ("initial mmap failed: %m\n"); + return 1; + } + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setpshared (&ma, 1) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + if (pthread_mutex_init (&p->m, &ma) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + pthread_condattr_t ca; + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + if (pthread_condattr_setpshared (&ca, 1) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + if (pthread_cond_init (&p->c, &ca) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_condattr_destroy (&ca) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("initial mutex_lock failed"); + return 1; + } + + p->var = 42; + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid == 0) + { + void *oldp = p; + p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + if (p == oldp) + { + puts ("child: mapped to same address"); + kill (getppid (), SIGKILL); + exit (1); + } + + munmap (oldp, sizeof (*p)); + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("child: mutex_lock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + p->var = 0; + +#ifndef USE_COND_SIGNAL + if (pthread_cond_broadcast (&p->c) != 0) + { + puts ("child: cond_broadcast failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#else + if (pthread_cond_signal (&p->c) != 0) + { + puts ("child: cond_signal failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#endif + + if (pthread_mutex_unlock (&p->m) != 0) + { + puts ("child: mutex_unlock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + exit (0); + } + + do + pthread_cond_wait (&p->c, &p->m); + while (p->var != 0); + + if (TEMP_FAILURE_RETRY (waitpid (pid, NULL, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + return 1; + } + + return 0; +} diff --git a/test/nptl/tst-cond13.c b/test/nptl/tst-cond13.c new file mode 100644 index 000000000..29d79b533 --- /dev/null +++ b/test/nptl/tst-cond13.c @@ -0,0 +1,2 @@ +#define USE_COND_SIGNAL 1 +#include "tst-cond12.c" diff --git a/test/nptl/tst-cond14.c b/test/nptl/tst-cond14.c new file mode 100644 index 000000000..106fa8c21 --- /dev/null +++ b/test/nptl/tst-cond14.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond15.c b/test/nptl/tst-cond15.c new file mode 100644 index 000000000..e815e253b --- /dev/null +++ b/test/nptl/tst-cond15.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += p == NULL ? 100 : 1; + + int err = pthread_cond_timedwait (&cond, &mut, &ts); + if ((err != 0 && p == NULL) || (err != ETIMEDOUT && p != NULL)) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 1st mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 2nd mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 3rd mutex_unlock failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create 1st child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot 1st create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf, (void *) 1l); + if (err != 0) + { + printf ("parent: cannot 2nd create thread: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 6 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond16.c b/test/nptl/tst-cond16.c new file mode 100644 index 000000000..00c27eced --- /dev/null +++ b/test/nptl/tst-cond16.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool n, exiting; +FILE *f; +int count; + +void * +tf (void *dummy) +{ + bool loop = true; + + while (loop) + { + pthread_mutex_lock (&lock); + while (n && !exiting) + pthread_cond_wait (&cv, &lock); + n = true; + pthread_mutex_unlock (&lock); + + fputs (".", f); + + pthread_mutex_lock (&lock); + n = false; + if (exiting) + loop = false; +#ifdef UNLOCK_AFTER_BROADCAST + pthread_cond_broadcast (&cv); + pthread_mutex_unlock (&lock); +#else + pthread_mutex_unlock (&lock); + pthread_cond_broadcast (&cv); +#endif + } + + return NULL; +} + +int +do_test (void) +{ + f = fopen ("/dev/null", "w"); + if (f == NULL) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + count = sysconf (_SC_NPROCESSORS_ONLN); + if (count <= 0) + count = 1; + count *= 4; + + pthread_t th[count]; + int i, ret; + for (i = 0; i < count; ++i) + if ((ret = pthread_create (&th[i], NULL, tf, NULL)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + fclose (f); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond17.c b/test/nptl/tst-cond17.c new file mode 100644 index 000000000..0586fa59a --- /dev/null +++ b/test/nptl/tst-cond17.c @@ -0,0 +1,2 @@ +#define UNLOCK_AFTER_BROADCAST 1 +#include "tst-cond16.c" diff --git a/test/nptl/tst-cond18.c b/test/nptl/tst-cond18.c new file mode 100644 index 000000000..9fd81d298 --- /dev/null +++ b/test/nptl/tst-cond18.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool exiting; +int fd, count, spins, nn; + +void * +tf (void *id) +{ + pthread_mutex_lock (&lock); + + if ((long) id == 0) + { + while (!exiting) + { + if ((spins++ % 1000) == 0) + write (fd, ".", 1); + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + int njobs = rand () % (count + 1); + nn = njobs; + if ((rand () % 30) == 0) + pthread_cond_broadcast (&cv); + else + while (njobs--) + pthread_cond_signal (&cv); + } + + pthread_cond_broadcast (&cv); + } + else + { + while (!exiting) + { + while (!nn && !exiting) + pthread_cond_wait (&cv, &lock); + --nn; + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + } + } + + pthread_mutex_unlock (&lock); + return NULL; +} + +int +do_test (void) +{ + fd = open ("/dev/null", O_WRONLY); + if (fd < 0) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + count = sysconf (_SC_NPROCESSORS_ONLN); + if (count <= 0) + count = 1; + count *= 8; + + pthread_t th[count + 1]; + int i, ret; + + for (i = 0; i <= count; ++i) + if ((ret = pthread_create (&th[i], NULL, tf, (void *) (long) i)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + close (fd); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond19.c b/test/nptl/tst-cond19.c new file mode 100644 index 000000000..1c9bb7dd7 --- /dev/null +++ b/test/nptl/tst-cond19.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static int +do_test (void) +{ + int result = 0; + struct timespec ts; + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + ts.tv_nsec = -1; + + int e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("first cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first cond_timedwait did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 2000000000; + + e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("second cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second cond_timedwait did not return EINVAL"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond2.c b/test/nptl/tst-cond2.c new file mode 100644 index 000000000..36f0f2941 --- /dev/null +++ b/test/nptl/tst-cond2.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +static pthread_barrier_t bar; + + +static void * +tf (void *a) +{ + int i = (long int) a; + int err; + + printf ("child %d: lock\n", i); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "locking in child failed"); + + printf ("child %d: sync\n", i); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + printf ("child %d: wait\n", i); + + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: failed to wait", i); + + printf ("child %d: woken up\n", i); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: unlock[2] failed", i); + + printf ("child %d: done\n", i); + + return NULL; +} + + +#define N 10 + + +static int +do_test (void) +{ + pthread_t th[N]; + int i; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + printf ("create thread %d\n", i); + + err = pthread_create (&th[i], &at, tf, (void *) (long int) i); + if (err != 0) + error (EXIT_FAILURE, err, "cannot create thread %d", i); + + printf ("wait for child %d\n", i); + + /* Wait for the child to start up and get the mutex for the + conditional variable. */ + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + puts ("get lock outselves"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut locking failed"); + + puts ("broadcast"); + + /* Wake up all threads. */ + err = pthread_cond_broadcast (&cond); + if (err != 0) + error (EXIT_FAILURE, err, "parent: broadcast failed"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut unlocking failed"); + + /* Join all threads. */ + for (i = 0; i < N; ++i) + { + printf ("join thread %d\n", i); + + err = pthread_join (th[i], NULL); + if (err != 0) + error (EXIT_FAILURE, err, "join of child %d failed", i); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond20.c b/test/nptl/tst-cond20.c new file mode 100644 index 000000000..18918f32e --- /dev/null +++ b/test/nptl/tst-cond20.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define N 10 +#define ROUNDS 1000 +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; +static int count; + +static void * +tf (void *p) +{ + int i; + for (i = 0; i < ROUNDS; ++i) + { + pthread_mutex_lock (&mut); + + if (++count == N) + pthread_cond_signal (&cond2); + +#ifdef TIMED + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + /* Wait three seconds. */ + ts.tv_sec = tv.tv_sec + 3; + ts.tv_nsec = tv.tv_usec * 1000; + pthread_cond_timedwait (&cond, &mut, &ts); +#else + pthread_cond_wait (&cond, &mut); +#endif + + pthread_mutex_unlock (&mut); + + int err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + } + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_mutex_lock (&mut); + + int i, j, err; + pthread_t th[N]; + for (i = 0; i < N; ++i) + if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0) + { + printf ("cannot create thread %d: %s\n", i, strerror (err)); + return 1; + } + + for (i = 0; i < ROUNDS; ++i) + { + pthread_cond_wait (&cond2, &mut); + + if (i & 1) + pthread_mutex_unlock (&mut); + + if (i & 2) + pthread_cond_broadcast (&cond); + else if (i & 4) + for (j = 0; j < N; ++j) + pthread_cond_signal (&cond); + else + { + for (j = 0; j < (i / 8) % N; ++j) + pthread_cond_signal (&cond); + pthread_cond_broadcast (&cond); + } + + if ((i & 1) == 0) + pthread_mutex_unlock (&mut); + + err = pthread_cond_destroy (&cond); + if (err) + { + printf ("pthread_cond_destroy failed: %s\n", strerror (err)); + return 1; + } + + /* Now clobber the cond variable which has been successfully + destroyed above. */ + memset (&cond, (char) i, sizeof (cond)); + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + pthread_mutex_lock (&mut); + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + count = 0; + err = pthread_cond_init (&cond, NULL); + if (err) + { + printf ("pthread_cond_init failed: %s\n", strerror (err)); + return 1; + } + } + + for (i = 0; i < N; ++i) + if ((err = pthread_join (th[i], NULL)) != 0) + { + printf ("failed to join thread %d: %s\n", i, strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond21.c b/test/nptl/tst-cond21.c new file mode 100644 index 000000000..89cb771b5 --- /dev/null +++ b/test/nptl/tst-cond21.c @@ -0,0 +1,3 @@ +#include <sys/time.h> +#define TIMED 1 +#include "tst-cond20.c" diff --git a/test/nptl/tst-cond3.c b/test/nptl/tst-cond3.c new file mode 100644 index 000000000..cb9eb8558 --- /dev/null +++ b/test/nptl/tst-cond3.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +/* Note that this test requires more than the standard. It is + required that there are no spurious wakeups if only more readers + are added. This is a reasonable demand. */ + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +#define N 10 + + +static void * +tf (void *arg) +{ + int i = (long int) arg; + int err; + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("child %d mutex_lock failed: %s\n", i, strerror (err)); + exit (1); + } + + /* This call should never return. */ + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ + exit (1); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + int i; + + for (i = 0; i < N; ++i) + { + pthread_t th; + + if (i != 0) + { + /* Release the mutex. */ + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + err = pthread_create (&th, NULL, tf, (void *) (long int) i); + if (err != 0) + { + printf ("create %d failed: %s\n", i, strerror (err)); + return 1; + } + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("mutex_lock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_cond_wait (&cond, &mut); + + puts ("cond_wait returned"); + return 1; +} + + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond4.c b/test/nptl/tst-cond4.c new file mode 100644 index 000000000..4d8859616 --- /dev/null +++ b/test/nptl/tst-cond4.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <stdint.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + int p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("1st mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("2nd mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + return 1; + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + return 1; + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("1st condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default value for pshared in condattr wrong"); + return 1; + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("2nd condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared condattr still not set"); + return 1; + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + return 1; + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + return 1; + } + + do + if (pthread_cond_wait (cond, mut2) != 0) + { + puts ("child: cond_wait failed"); + return 1; + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + return 1; + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + return 1; + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + return 1; + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond5.c b/test/nptl/tst-cond5.c new file mode 100644 index 000000000..efa207b5d --- /dev/null +++ b/test/nptl/tst-cond5.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_mutex_t mut; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + + +static int +do_test (void) +{ + pthread_mutexattr_t ma; + int err; + struct timespec ts; + struct timeval tv; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + + if (pthread_mutex_init (&mut, &ma) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + /* Get the mutex. */ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Waiting for the condition will fail. But we want the timeout here. */ + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + /* This could in theory happen but here without any signal and + additional waiter it should not. */ + puts ("cond_timedwait succeeded"); + exit (1); + } + else if (err != ETIMEDOUT) + { + printf ("cond_timedwait returned with %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond6.c b/test/nptl/tst-cond6.c new file mode 100644 index 000000000..8c5fe2093 --- /dev/null +++ b/test/nptl/tst-cond6.c @@ -0,0 +1,234 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <stdint.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond6.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + exit (1); + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + exit (1); + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + exit (1); + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + exit (1); + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + exit (1); + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + exit (1); + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + exit (1); + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + exit (1); + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + exit (1); + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + exit (1); + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + else if (pid == 0) + { + struct timespec ts; + struct timeval tv; + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + exit (1); + } + + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + do + if (pthread_cond_timedwait (cond, mut2, &ts) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + exit (1); + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + exit (1); + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + exit (1); + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond7.c b/test/nptl/tst-cond7.c new file mode 100644 index 000000000..5ab7b8f8f --- /dev/null +++ b/test/nptl/tst-cond7.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +typedef struct + { + pthread_cond_t cond; + pthread_mutex_t lock; + pthread_t h; + } T; + + +static volatile bool done; + + +static void * +tf (void *arg) +{ + puts ("child created"); + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + T *t = (T *) arg; + + if (pthread_mutex_lock (&t->lock) != 0) + { + puts ("child: lock failed"); + exit (1); + } + + done = true; + + if (pthread_cond_signal (&t->cond) != 0) + { + puts ("child: cond_signal failed"); + exit (1); + } + + if (pthread_cond_wait (&t->cond, &t->lock) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&t->lock) != 0) + { + puts ("child: unlock failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + int i; +#define N 100 + T *t[N]; + for (i = 0; i < N; ++i) + { + printf ("round %d\n", i); + + t[i] = (T *) malloc (sizeof (T)); + if (t[i] == NULL) + { + puts ("out of memory"); + exit (1); + } + + if (pthread_mutex_init (&t[i]->lock, NULL) != 0 + || pthread_cond_init (&t[i]->cond, NULL) != 0) + { + puts ("an _init function failed"); + exit (1); + } + + if (pthread_mutex_lock (&t[i]->lock) != 0) + { + puts ("initial mutex_lock failed"); + exit (1); + } + + done = false; + + if (pthread_create (&t[i]->h, NULL, tf, t[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + do + if (pthread_cond_wait (&t[i]->cond, &t[i]->lock) != 0) + { + puts ("cond_wait failed"); + exit (1); + } + while (! done); + + /* Release the lock since the cancel handler will get it. */ + if (pthread_mutex_unlock (&t[i]->lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (t[i]->h) != 0) + { + puts ("cancel failed"); + exit (1); + } + + puts ("parent: joining now"); + + void *result; + if (pthread_join (t[i]->h, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != PTHREAD_CANCELED) + { + puts ("result != PTHREAD_CANCELED"); + exit (1); + } + } + + for (i = 0; i < N; ++i) + free (t[i]); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond8.c b/test/nptl/tst-cond8.c new file mode 100644 index 000000000..9c97a96fa --- /dev/null +++ b/test/nptl/tst-cond8.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pthread_barrier_t bar; + + +static void +ch (void *arg) +{ + int e = pthread_mutex_lock (&mut); + if (e == 0) + { + puts ("mutex not locked at all by cond_wait"); + exit (1); + } + + if (e != EDEADLK) + { + puts ("no deadlock error signaled"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("ch: cannot unlock mutex"); + exit (1); + } + + puts ("ch done"); +} + + +static void * +tf1 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + pthread_cond_wait (&cond, &mut); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static void * +tf2 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + pthread_cond_timedwait (&cond, &mut, &ts); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_barrier_init (&bar, NULL, 2); + if (err != 0) + { + puts ("parent: cannot init barrier"); + exit (1); + } + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf1, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf2, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond9.c b/test/nptl/tst-cond9.c new file mode 100644 index 000000000..2a8477dd8 --- /dev/null +++ b/test/nptl/tst-cond9.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + + +static void * +tf (void *arg) +{ + int err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + puts ("creating thread"); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != (void *) 1l) + { + puts ("thread has wrong return value"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock1.c b/test/nptl/tst-cpuclock1.c new file mode 100644 index 000000000..024df6314 --- /dev/null +++ b/test/nptl/tst-cpuclock1.c @@ -0,0 +1,307 @@ +/* Test program for process CPU clocks. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static int +do_test (void) +{ + int result = 0; + clockid_t cl; + int e; + pid_t dead_child, child; + + /* Fork a child and let it die, to give us a PID known not be valid + (assuming PIDs don't wrap around during the test). */ + { + dead_child = fork (); + if (dead_child == 0) + _exit (0); + if (dead_child < 0) + { + perror ("fork"); + return 1; + } + int x; + if (wait (&x) != dead_child) + { + perror ("wait"); + return 2; + } + } + + /* POSIX says we should get ESRCH for this. */ + e = clock_getcpuclockid (dead_child, &cl); + if (e != ENOSYS && e != ESRCH && e != EPERM) + { + printf ("clock_getcpuclockid on dead PID %d => %s\n", + dead_child, strerror (e)); + result = 1; + } + + /* Now give us a live child eating up CPU time. */ + child = fork (); + if (child == 0) + { + chew_cpu (); + _exit (1); + } + if (child < 0) + { + perror ("fork"); + return 1; + } + + e = clock_getcpuclockid (child, &cl); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + goto done; + } + if (e != 0) + { + printf ("clock_getcpuclockid on live PID %d => %s\n", + child, strerror (e)); + result = 1; + goto done; + } + + const clockid_t child_clock = cl; + struct timespec res; + if (clock_getres (child_clock, &res) < 0) + { + printf ("clock_getres on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d clock %lx resolution %lu.%.9lu\n", + child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec); + + struct timespec before, after; + if (clock_gettime (child_clock, &before) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d before sleep => %lu.%.9lu\n", + child, before.tv_sec, before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (child_clock, &after) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d after sleep => %lu.%.9lu\n", + child, after.tv_sec, after.tv_nsec); + + struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec, + .tv_nsec = after.tv_nsec - before.tv_nsec }; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 + || diff.tv_nsec > 600000000 + || diff.tv_nsec < 100000000) + { + printf ("before - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + sleeptime.tv_nsec = 100000000; + e = clock_nanosleep (child_clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for other process clock: %s\n", + strerror (e)); + } + else if (e != 0) + { + printf ("clock_nanosleep on other process clock: %s\n", strerror (e)); + result = 1; + } + else + { + struct timespec afterns; + if (clock_gettime (child_clock, &afterns) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + } + else + { + struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec, + .tv_nsec = afterns.tv_nsec - after.tv_nsec }; + if (d.tv_nsec < 0) + { + --d.tv_sec; + d.tv_nsec += 1000000000; + } + if (d.tv_sec > 0 + || d.tv_nsec < sleeptime.tv_nsec + || d.tv_nsec > sleeptime.tv_nsec * 2) + { + printf ("nanosleep time %lu.%.9lu outside reasonable range\n", + d.tv_sec, d.tv_nsec); + result = 1; + } + } + } + + if (kill (child, SIGKILL) != 0) + { + perror ("kill"); + result = 2; + goto done; + } + + /* Wait long enough to let the child finish dying. */ + + sleeptime.tv_nsec = 200000000; + nanosleep (&sleeptime, NULL); + + struct timespec dead; + if (clock_gettime (child_clock, &dead) < 0) + { + printf ("clock_gettime on dead PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("dead PID %d => %lu.%.9lu\n", + child, dead.tv_sec, dead.tv_nsec); + + diff.tv_sec = dead.tv_sec - after.tv_sec; + diff.tv_nsec = dead.tv_nsec - after.tv_nsec; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 || diff.tv_nsec > 200000000) + { + printf ("dead - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + /* Now reap the child and verify that its clock is no longer valid. */ + { + int x; + if (waitpid (child, &x, 0) != child) + { + perror ("waitpid"); + result = 1; + } + } + + if (clock_gettime (child_clock, &dead) == 0) + { + printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_gettime on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + if (clock_getres (child_clock, &dead) == 0) + { + printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_getres on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + return result; + + done: + { + if (kill (child, SIGKILL) != 0 && errno != ESRCH) + { + perror ("kill"); + return 2; + } + int x; + if (waitpid (child, &x, 0) != child && errno != ECHILD) + { + perror ("waitpid"); + return 2; + } + } + + return result; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock2.c b/test/nptl/tst-cpuclock2.c new file mode 100644 index 000000000..d1621f3d0 --- /dev/null +++ b/test/nptl/tst-cpuclock2.c @@ -0,0 +1,332 @@ +/* Test program for process and thread CPU clocks. + Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +#if (_POSIX_THREADS - 0) <= 0 + +# define TEST_FUNCTION 0 + +#else + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> + +static pthread_barrier_t barrier; + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + pthread_barrier_wait (&barrier); + + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static unsigned long long int +tsdiff (const struct timespec *before, const struct timespec *after) +{ + struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec, + .tv_nsec = after->tv_nsec - before->tv_nsec }; + while (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + return diff.tv_sec * 1000000000ULL + diff.tv_nsec; +} + +static unsigned long long int +test_nanosleep (clockid_t clock, const char *which, + const struct timespec *before, int *bad) +{ + const struct timespec sleeptime = { .tv_nsec = 100000000 }; + int e = clock_nanosleep (clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for %s CPU clock: %s\n", + which, strerror (e)); + return 0; + } + if (e != 0) + { + printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e)); + *bad = 1; + return 0; + } + + struct timespec after; + if (clock_gettime (clock, &after) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return 0; + } + + unsigned long long int diff = tsdiff (before, &after); + if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2) + { + printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diff); + *bad = 1; + return diff; + } + + struct timespec sleeptimeabs = sleeptime; + sleeptimeabs.tv_sec += after.tv_sec; + sleeptimeabs.tv_nsec += after.tv_nsec; + while (sleeptimeabs.tv_nsec > 1000000000) + { + ++sleeptimeabs.tv_sec; + sleeptimeabs.tv_nsec -= 1000000000; + } + e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL); + if (e != 0) + { + printf ("absolute clock_nanosleep on %s CPU clock: %s\n", + which, strerror (e)); + *bad = 1; + return diff; + } + + struct timespec afterabs; + if (clock_gettime (clock, &afterabs) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return diff; + } + + unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs); + if (sleepdiff > sleeptime.tv_nsec) + { + printf ("\ +absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n", + which, sleepdiff); + *bad = 1; + } + + unsigned long long int diffabs = tsdiff (&after, &afterabs); + if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2) + { + printf ("\ +absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diffabs); + *bad = 1; + } + + return diff + diffabs; +} + + + +static int +do_test (void) +{ + int result = 0; + clockid_t process_clock, th_clock, my_thread_clock; + int e; + pthread_t th; + + e = clock_getcpuclockid (0, &process_clock); + if (e != 0) + { + printf ("clock_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (pthread_self (), &my_thread_clock); + if (e != 0) + { + printf ("pthread_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + /* This is a kludge. This test fails if the semantics of thread and + process clocks are wrong. The old code using hp-timing without kernel + support has bogus semantics if there are context switches. We don't + fail to report failure when the proper functionality is not available + in the kernel. It so happens that Linux kernels without correct CPU + clock support also lack CPU timer support, so we use use that to guess + that we are using the bogus code and not test it. */ + timer_t t; + if (timer_create (my_thread_clock, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + puts ("No support for CPU clocks with good semantics, skipping test"); + return 0; + } + timer_delete (t); + + + pthread_barrier_init (&barrier, NULL, 2); + + e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (th, &th_clock); + if (e == ENOENT || e == ENOSYS || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + + pthread_barrier_wait (&barrier); + + struct timespec res; + if (clock_getres (th_clock, &res) < 0) + { + printf ("clock_getres on thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + result = 1; + return 1; + } + printf ("live thread clock %lx resolution %lu.%.9lu\n", + (unsigned long int) th_clock, res.tv_sec, res.tv_nsec); + + struct timespec process_before, process_after; + if (clock_gettime (process_clock, &process_before) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + struct timespec before, after; + if (clock_gettime (th_clock, &before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread before sleep => %lu.%.9lu\n", + before.tv_sec, before.tv_nsec); + + struct timespec me_before, me_after; + if (clock_gettime (my_thread_clock, &me_before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread before sleep => %lu.%.9lu\n", + me_before.tv_sec, me_before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (th_clock, &after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread after sleep => %lu.%.9lu\n", + after.tv_sec, after.tv_nsec); + + if (clock_gettime (process_clock, &process_after) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + if (clock_gettime (my_thread_clock, &me_after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread after sleep => %lu.%.9lu\n", + me_after.tv_sec, me_after.tv_nsec); + + unsigned long long int th_diff = tsdiff (&before, &after); + unsigned long long int pdiff = tsdiff (&process_before, &process_after); + unsigned long long int my_diff = tsdiff (&me_before, &me_after); + + if (th_diff < 100000000 || th_diff > 600000000) + { + printf ("thread before - after %llu outside reasonable range\n", + th_diff); + result = 1; + } + + if (my_diff > 100000000) + { + printf ("self thread before - after %llu outside reasonable range\n", + my_diff); + result = 1; + } + + if (pdiff < th_diff) + { + printf ("process before - after %llu outside reasonable range (%llu)\n", + pdiff, th_diff); + result = 1; + } + + process_after.tv_nsec += test_nanosleep (th_clock, "thread", + &after, &result); + process_after.tv_nsec += test_nanosleep (process_clock, "process", + &process_after, &result); + test_nanosleep (CLOCK_PROCESS_CPUTIME_ID, + "PROCESS_CPUTIME_ID", &process_after, &result); + + pthread_cancel (th); + + e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL); + if (e != EINVAL) + { + printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n", + strerror (e)); + result = 1; + } + + return result; +} +# define TIMEOUT 8 +# define TEST_FUNCTION do_test () +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cputimer1.c b/test/nptl/tst-cputimer1.c new file mode 100644 index 000000000..8f5dd76cf --- /dev/null +++ b/test/nptl/tst-cputimer1.c @@ -0,0 +1,68 @@ +/* Tests for POSIX timer implementation using process CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on our own process CPU clock by having a worker thread + eating CPU. First make sure we can make such timers at all. */ + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer2.c b/test/nptl/tst-cputimer2.c new file mode 100644 index 000000000..397d7998c --- /dev/null +++ b/test/nptl/tst-cputimer2.c @@ -0,0 +1,83 @@ +/* Tests for POSIX timer implementation using thread CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +static clockid_t worker_thread_clock; + +#define TEST_CLOCK worker_thread_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "thread CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on a thread CPU clock by having a worker thread eating + CPU. First make sure we can make such timers at all. */ + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + e = pthread_getcpuclockid (th, &worker_thread_clock); + if (e == EPERM || e == ENOENT || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + if (e != 0) + { + printf ("pthread_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer3.c b/test/nptl/tst-cputimer3.c new file mode 100644 index 000000000..056766a37 --- /dev/null +++ b/test/nptl/tst-cputimer3.c @@ -0,0 +1,130 @@ +/* Tests for POSIX timer implementation using another process's CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <signal.h> +#include <sys/wait.h> + +static clockid_t child_clock; + +#define TEST_CLOCK child_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "other-process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static pid_t child; +static void +cleanup_child (void) +{ + if (child <= 0) + return; + if (kill (child, SIGKILL) < 0 && errno != ESRCH) + printf ("cannot kill child %d: %m\n", child); + else + { + int status; + errno = 0; + if (waitpid (child, &status, 0) != child) + printf ("waitpid %d: %m\n", child); + } +} +#define CLEANUP_HANDLER cleanup_child () + +static int +setup_test (void) +{ + /* Test timers on a process CPU clock by having a child process eating + CPU. First make sure we can make such timers at all. */ + + int pipefd[2]; + if (pipe (pipefd) < 0) + { + printf ("pipe: %m\n"); + exit (1); + } + + child = fork (); + + if (child == 0) + { + char c; + close (pipefd[1]); + if (read (pipefd[0], &c, 1) == 1) + chew_cpu (); + _exit (1); + } + + if (child < 0) + { + printf ("fork: %m\n"); + exit (1); + } + + atexit (&cleanup_child); + + close (pipefd[0]); + + int e = clock_getcpuclockid (child, &child_clock); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + return 1; + } + if (e != 0) + { + printf ("clock_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + /* Get the child started chewing. */ + if (write (pipefd[1], "x", 1) != 1) + { + printf ("write to pipe: %m\n"); + return 1; + } + close (pipefd[1]); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-detach1.c b/test/nptl/tst-detach1.c new file mode 100644 index 000000000..7b27f6ead --- /dev/null +++ b/test/nptl/tst-detach1.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Give the child a chance to finish. */ + sleep (1); + + if (pthread_detach (th) != 0) + { + puts ("detach failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr1.c b/test/nptl/tst-eintr1.c new file mode 100644 index 000000000..43a5df5b9 --- /dev/null +++ b/test/nptl/tst-eintr1.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static void * +tf2 (void *arg) +{ + return arg; +} + + +static void * +tf1 (void *arg) +{ + while (1) + { + pthread_t th; + + int e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + if (e == EINTR) + { + puts ("pthread_create returned EINTR"); + exit (1); + } + + char buf[100]; + printf ("tf1: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + e = pthread_join (th, NULL); + if (e != 0) + { + if (e == EINTR) + { + puts ("pthread_join returned EINTR"); + exit (1); + } + + char buf[100]; + printf ("tf1: pthread_join failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + } +} + + +static int +do_test (void) +{ + setup_eintr (SIGUSR1, NULL); + + int i; + for (i = 0; i < 10; ++i) + { + pthread_t th; + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) + { + char buf[100]; + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + } + + (void) tf1 (NULL); + /* NOTREACHED */ + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr2.c b/test/nptl/tst-eintr2.c new file mode 100644 index 000000000..8cbbc5a02 --- /dev/null +++ b/test/nptl/tst-eintr2.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "eintr.c" + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf1 (void *arg) +{ + struct timespec ts; + struct timeval tv; + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10000; + + /* This call must never return. */ + int e = pthread_mutex_timedlock (&m1, &ts); + char buf[100]; + printf ("tf1: mutex_timedlock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + exit (1); +} + + +static void * +tf2 (void *arg) +{ + while (1) + { + int e = pthread_mutex_lock (&m2); + if (e != 0) + { + puts ("tf2: mutex_lock failed"); + exit (1); + } + e = pthread_mutex_unlock (&m2); + if (e != 0) + { + puts ("tf2: mutex_unlock failed"); + exit (1); + } + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + } +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&m1) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + setup_eintr (SIGUSR1, NULL); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) + { + printf ("main: 1st pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + printf ("main: 2nd pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_mutex_lock (&m1); + printf ("main: mutex_lock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr3.c b/test/nptl/tst-eintr3.c new file mode 100644 index 000000000..eecab48b1 --- /dev/null +++ b/test/nptl/tst-eintr3.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static void * +tf (void *arg) +{ + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock (&m); + /* This call must not return. */ + pthread_mutex_lock (&m); + + puts ("tf: mutex_lock returned"); + exit (1); +} + + +static int +do_test (void) +{ + pthread_t self = pthread_self (); + + setup_eintr (SIGUSR1, &self); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_join (th, NULL); + + if (e == EINTR) + puts ("pthread_join returned with EINTR"); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr4.c b/test/nptl/tst-eintr4.c new file mode 100644 index 000000000..dffbdd605 --- /dev/null +++ b/test/nptl/tst-eintr4.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static int +do_test (void) +{ + pthread_t self = pthread_self (); + + setup_eintr (SIGUSR1, &self); + + pthread_barrier_t b; + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + /* This call must never return. */ + int e = pthread_barrier_wait (&b); + + if (e == EINTR) + puts ("pthread_join returned with EINTR"); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr5.c b/test/nptl/tst-eintr5.c new file mode 100644 index 000000000..91473ec4c --- /dev/null +++ b/test/nptl/tst-eintr5.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "eintr.c" + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; + + +static void * +tf (void *arg) +{ + struct timespec ts; + struct timeval tv; + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10000; + + /* This call must never return. */ + int e = pthread_cond_timedwait (&c, &m, &ts); + char buf[100]; + printf ("tf: cond_timedwait returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + exit (1); +} + + +static int +do_test (void) +{ + setup_eintr (SIGUSR1, NULL); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_cond_wait (&c, &m); + printf ("main: cond_wait returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec2.c b/test/nptl/tst-exec2.c new file mode 100644 index 000000000..432da32ef --- /dev/null +++ b/test/nptl/tst-exec2.c @@ -0,0 +1,154 @@ +/* Thread with running thread calls exec. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void * +tf (void *arg) +{ + pthread_t th = (pthread_t) arg; + + if (pthread_join (th, NULL) == 0) + { + puts ("thread in parent joined!?"); + exit (1); + } + + puts ("join in thread in parent returned!?"); + exit (1); +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + /* Not interested in knowing when the pipe is closed. */ + if (sigignore (SIGPIPE) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Use the fd for stdout. This is kind of ugly because it + substitutes the fd of stdout but we know what we are doing + here... */ + if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO) + { + puts ("dup2 failed"); + exit (1); + } + + close (fd[0]); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL); + + puts ("execl failed"); + exit (1); + } + + close (fd[1]); + + char buf[200]; + ssize_t n; + bool seen_pid = false; + while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0) + { + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + + if (*endp != '\n') + { + printf ("didn't parse whole line: \"%s\"\n", buf); + exit (1); + } + if (endp == buf) + { + puts ("read empty line"); + exit (1); + } + + if (rpid != pid) + { + printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid); + exit (1); + } + + if (seen_pid) + { + puts ("found more than one PID line"); + exit (1); + } + seen_pid = true; + } + + close (fd[0]); + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (!seen_pid) + { + puts ("didn't get PID"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec3.c b/test/nptl/tst-exec3.c new file mode 100644 index 000000000..be49b048c --- /dev/null +++ b/test/nptl/tst-exec3.c @@ -0,0 +1,152 @@ +/* Thread calls exec. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void * +tf (void *arg) +{ + execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL); + + puts ("execl failed"); + exit (1); +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + /* Not interested in knowing when the pipe is closed. */ + if (sigignore (SIGPIPE) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Use the fd for stdout. This is kind of ugly because it + substitutes the fd of stdout but we know what we are doing + here... */ + if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO) + { + puts ("dup2 failed"); + exit (1); + } + + close (fd[0]); + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_join (th, NULL) == 0) + { + puts ("join succeeded!?"); + exit (1); + } + + puts ("join returned!?"); + exit (1); + } + + close (fd[1]); + + char buf[200]; + ssize_t n; + bool seen_pid = false; + while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0) + { + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + + if (*endp != '\n') + { + printf ("didn't parse whole line: \"%s\"\n", buf); + exit (1); + } + if (endp == buf) + { + puts ("read empty line"); + exit (1); + } + + if (rpid != pid) + { + printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid); + exit (1); + } + + if (seen_pid) + { + puts ("found more than one PID line"); + exit (1); + } + seen_pid = true; + } + + close (fd[0]); + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (!seen_pid) + { + puts ("didn't get PID"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec4.c b/test/nptl/tst-exec4.c new file mode 100644 index 000000000..b3920a030 --- /dev/null +++ b/test/nptl/tst-exec4.c @@ -0,0 +1,116 @@ +/* Signal handler and mask set in thread which calls exec. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + /* Ignore SIGUSR1 and block SIGUSR2. */ + if (sigignore (SIGUSR1) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, SIGUSR2); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("1st run: sigmask failed"); + exit (1); + } + + char **oldargv = (char **) arg; + size_t n = 1; + while (oldargv[n] != NULL) + ++n; + + char **argv = (char **) alloca ((n + 1) * sizeof (char *)); + for (n = 0; oldargv[n + 1] != NULL; ++n) + argv[n] = oldargv[n + 1]; + argv[n++] = (char *) "--direct"; + argv[n] = NULL; + + execv (argv[0], argv); + + puts ("execv failed"); + + exit (1); +} + + +static int +do_test (int argc, char *argv[]) +{ + if (argc == 1) + { + /* This is the second call. Perform the test. */ + struct sigaction sa; + + if (sigaction (SIGUSR1, NULL, &sa) != 0) + { + puts ("2nd run: sigaction failed"); + return 1; + } + if (sa.sa_handler != SIG_IGN) + { + puts ("SIGUSR1 not ignored"); + return 1; + } + + sigset_t ss; + if (pthread_sigmask (SIG_SETMASK, NULL, &ss) != 0) + { + puts ("2nd run: sigmask failed"); + return 1; + } + if (! sigismember (&ss, SIGUSR2)) + { + puts ("SIGUSR2 not blocked"); + return 1; + } + + return 0; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, argv) != 0) + { + puts ("create failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th, NULL); + + puts ("join returned"); + + return 1; +} + +#define TEST_FUNCTION do_test (argc, argv) +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit1.c b/test/nptl/tst-exit1.c new file mode 100644 index 000000000..44175f76c --- /dev/null +++ b/test/nptl/tst-exit1.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* NOTE: this tests functionality beyond POSIX. POSIX does not allow + exit to be called more than once. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + /* Do nothing. */ + if (pthread_join (th, NULL) == 0) + { + puts ("join succeeded!?"); + exit (1); + } + + puts ("join returned!?"); + exit (1); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit2.c b/test/nptl/tst-exit2.c new file mode 100644 index 000000000..3f5ff27b0 --- /dev/null +++ b/test/nptl/tst-exit2.c @@ -0,0 +1,40 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + while (1) + sleep (100); + + /* NOTREACHED */ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + return 1; + } + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit3.c b/test/nptl/tst-exit3.c new file mode 100644 index 000000000..da92c82c0 --- /dev/null +++ b/test/nptl/tst-exit3.c @@ -0,0 +1,81 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +static void * +tf2 (void *arg) +{ + while (1) + sleep (100); + + /* NOTREACHED */ + return NULL; +} + + +static void * +tf (void *arg) +{ + pthread_t th; + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + exit (1); + } + + /* Terminate only this thread. */ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-flock1.c b/test/nptl/tst-flock1.c new file mode 100644 index 000000000..ed2472d3a --- /dev/null +++ b/test/nptl/tst-flock1.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/file.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static int fd; + + +static void * +tf (void *arg) +{ + if (flock (fd, LOCK_SH | LOCK_NB) != 0) + { + puts ("second flock failed"); + exit (1); + } + + pthread_mutex_unlock (&lock); + + return NULL; +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-flock1-XXXXXX"; + + fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + write (fd, "foobar xyzzy", 12); + + if (flock (fd, LOCK_EX | LOCK_NB) != 0) + { + puts ("first flock failed"); + exit (1); + } + + pthread_mutex_lock (&lock); + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + pthread_mutex_lock (&lock); + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + close (fd); + + return result != NULL; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-flock2.c b/test/nptl/tst-flock2.c new file mode 100644 index 000000000..8ef3206cc --- /dev/null +++ b/test/nptl/tst-flock2.c @@ -0,0 +1,260 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER; +static int fd; + + +static void * +tf (void *arg) +{ + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 10 + }; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("fourth fcntl failed"); + exit (1); + } + + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock2); + + return NULL; +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-flock2-XXXXXX"; + + fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + return 1; + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + pthread_barrier_t *b; + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + return 1; + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 10 + }; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("first fcntl failed"); + return 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + if (pid == 0) + { + /* Make sure the child does not stay around indefinitely. */ + alarm (10); + + /* Try to get the lock. */ + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("child: second flock succeeded"); + return 1; + } + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_UNLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("third fcntl failed"); + return 1; + } + } + + pthread_barrier_wait (b); + + pthread_t th; + if (pid == 0) + { + if (pthread_mutex_lock (&lock) != 0) + { + puts ("1st locking of lock failed"); + return 1; + } + + if (pthread_mutex_lock (&lock2) != 0) + { + puts ("1st locking of lock2 failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("2nd locking of lock failed"); + return 1; + } + + puts ("child locked file"); + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_WRLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("fifth fcntl succeeded"); + return 1; + } + + puts ("file locked by child"); + } + + pthread_barrier_wait (b); + + if (pid == 0) + { + if (pthread_mutex_unlock (&lock2) != 0) + { + puts ("unlock of lock2 failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + puts ("child's thread terminated"); + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_WRLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("fifth fcntl succeeded"); + return 1; + } + + puts ("file still locked"); + } + + pthread_barrier_wait (b); + + if (pid == 0) + { + _exit (0); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + puts ("child terminated"); + + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("sixth fcntl failed"); + return 1; + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-fork1.c b/test/nptl/tst-fork1.c new file mode 100644 index 000000000..33c4ed84f --- /dev/null +++ b/test/nptl/tst-fork1.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +static void * +thread_function (void * arg) +{ + int i = (intptr_t) arg; + int status; + pid_t pid; + pid_t pid2; + + pid = fork (); + switch (pid) + { + case 0: + printf ("%ld for %d\n", (long int) getpid (), i); + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 * i }; + nanosleep (&ts, NULL); + _exit (i); + break; + case -1: + printf ("fork: %m\n"); + return (void *) 1l; + break; + } + + pid2 = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (pid2 != pid) + { + printf ("waitpid returned %ld, expected %ld\n", + (long int) pid2, (long int) pid); + return (void *) 1l; + } + + printf ("%ld with %d, expected %d\n", + (long int) pid, WEXITSTATUS (status), i); + + return WEXITSTATUS (status) == i ? NULL : (void *) 1l; +} + +#define N 5 +static const int t[N] = { 7, 6, 5, 4, 3 }; + +int +main (void) +{ + pthread_t th[N]; + int i; + int result = 0; + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], NULL, thread_function, + (void *) (intptr_t) t[i]) != 0) + { + printf ("creation of thread %d failed\n", i); + exit (1); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + void *v; + if (pthread_join (th[i], &v) != 0) + { + printf ("join of thread %d failed\n", i); + result = 1; + } + else if (v != NULL) + { + printf ("join %d successful, but child failed\n", i); + result = 1; + } + else + printf ("join %d successful\n", i); + } + + return result; +} diff --git a/test/nptl/tst-fork2.c b/test/nptl/tst-fork2.c new file mode 100644 index 000000000..07d6c2266 --- /dev/null +++ b/test/nptl/tst-fork2.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static pid_t initial_pid; + + +static void * +tf (void *arg) +{ + if (getppid () != initial_pid) + { + printf ("getppid in thread returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + return (void *) -1; + } + + return NULL; +} + + +int +main (void) +{ + initial_pid = getpid (); + + pid_t child = fork (); + if (child == 0) + { + if (getppid () != initial_pid) + { + printf ("first getppid returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + exit (result == NULL ? 0 : 1); + } + else if (child == -1) + { + puts ("initial fork failed"); + return 1; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + printf ("waitpid failed: %m\n"); + return 1; + } + + return status; +} diff --git a/test/nptl/tst-fork3.c b/test/nptl/tst-fork3.c new file mode 100644 index 000000000..bc73853a5 --- /dev/null +++ b/test/nptl/tst-fork3.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static pid_t initial_pid; + + +static void * +tf2 (void *arg) +{ + if (getppid () != initial_pid) + { + printf ("getppid in thread returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + return (void *) -1; + } + + return NULL; +} + + +static void * +tf1 (void *arg) +{ + pid_t child = fork (); + if (child == 0) + { + if (getppid () != initial_pid) + { + printf ("first getppid returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + exit (1); + } + + pthread_t th2; + if (pthread_create (&th2, NULL, tf2, NULL) != 0) + { + puts ("child: pthread_create failed"); + exit (1); + } + + void *result; + if (pthread_join (th2, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + exit (result == NULL ? 0 : 1); + } + else if (child == -1) + { + puts ("initial fork failed"); + exit (1); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + exit (status); +} + + +int +main (void) +{ + initial_pid = getpid (); + + pthread_t th1; + if (pthread_create (&th1, NULL, tf1, NULL) != 0) + { + puts ("parent: pthread_create failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th1, NULL); + + return 1; +} diff --git a/test/nptl/tst-fork4.c b/test/nptl/tst-fork4.c new file mode 100644 index 000000000..cca19f406 --- /dev/null +++ b/test/nptl/tst-fork4.c @@ -0,0 +1,65 @@ +/* Test of fork updating child universe's pthread structures. + Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_t me = pthread_self (); + + pid_t pid = fork (); + + if (pid < 0) + { + printf ("fork: %m\n"); + return 1; + } + + if (pid == 0) + { + int err = pthread_kill (me, SIGTERM); + printf ("pthread_kill returned: %s\n", strerror (err)); + return 3; + } + + int status; + errno = 0; + if (wait (&status) != pid) + printf ("wait failed: %m\n"); + else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGTERM) + { + printf ("child correctly died with SIGTERM\n"); + return 0; + } + else + printf ("child died with bad status %#x\n", status); + + return 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-initializers1.c b/test/nptl/tst-initializers1.c new file mode 100644 index 000000000..ccd27286e --- /dev/null +++ b/test/nptl/tst-initializers1.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2005. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> + +pthread_mutex_t mtx_normal = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mtx_recursive = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +pthread_mutex_t mtx_errorchk = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; +pthread_mutex_t mtx_adaptive = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; +pthread_rwlock_t rwl_normal = PTHREAD_RWLOCK_INITIALIZER; +pthread_rwlock_t rwl_writer + = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +int +main (void) +{ + if (mtx_normal.__data.__kind != PTHREAD_MUTEX_TIMED_NP) + return 1; + if (mtx_recursive.__data.__kind != PTHREAD_MUTEX_RECURSIVE_NP) + return 1; + if (mtx_errorchk.__data.__kind != PTHREAD_MUTEX_ERRORCHECK_NP) + return 1; + if (mtx_adaptive.__data.__kind != PTHREAD_MUTEX_ADAPTIVE_NP) + return 1; + if (rwl_normal.__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) + return 1; + if (rwl_writer.__data.__flags + != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + return 1; + return 0; +} diff --git a/test/nptl/tst-join1.c b/test/nptl/tst-join1.c new file mode 100644 index 000000000..95a78ba0b --- /dev/null +++ b/test/nptl/tst-join1.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + pthread_t mh = (pthread_t) arg; + void *result; + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("unlock failed"); + exit (1); + } + + if (pthread_join (mh, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != (void *) 42l) + { + printf ("result wrong: expected %p, got %p\n", (void *) 42, result); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("1st lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("2nd lock failed"); + exit (1); + } + + pthread_exit ((void *) 42); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join2.c b/test/nptl/tst-join2.c new file mode 100644 index 000000000..2cfab8b0e --- /dev/null +++ b/test/nptl/tst-join2.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&lock) != 0) + { + puts ("child: mutex_lock failed"); + return NULL; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("mutex_create failed"); + exit (1); + } + + void *status; + int val = pthread_tryjoin_np (th, &status); + if (val == 0) + { + puts ("1st tryjoin succeeded"); + exit (1); + } + else if (val != EBUSY) + { + puts ("1st tryjoin didn't return EBUSY"); + exit (1); + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + while ((val = pthread_tryjoin_np (th, &status)) != 0) + { + if (val != EBUSY) + { + printf ("tryjoin returned %s (%d), expected only 0 or EBUSY\n", + strerror (val), val); + exit (1); + } + + /* Delay minimally. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + } + + if (status != (void *) 42l) + { + printf ("return value %p, expected %p\n", status, (void *) 42l); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join3.c b/test/nptl/tst-join3.c new file mode 100644 index 000000000..df1135fb5 --- /dev/null +++ b/test/nptl/tst-join3.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&lock) != 0) + { + puts ("child: mutex_lock failed"); + return NULL; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("mutex_create failed"); + exit (1); + } + + void *status; + struct timespec ts; + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 200000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + int val = pthread_timedjoin_np (th, &status, &ts); + if (val == 0) + { + puts ("1st timedjoin succeeded"); + exit (1); + } + else if (val != ETIMEDOUT) + { + puts ("1st timedjoin didn't return ETIMEDOUT"); + exit (1); + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + while (1) + { + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 200000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + val = pthread_timedjoin_np (th, &status, &ts); + if (val == 0) + break; + + if (val != ETIMEDOUT) + { + printf ("timedjoin returned %s (%d), expected only 0 or ETIMEDOUT\n", + strerror (val), val); + exit (1); + } + } + + if (status != (void *) 42l) + { + printf ("return value %p, expected %p\n", status, (void *) 42l); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join4.c b/test/nptl/tst-join4.c new file mode 100644 index 000000000..b13a51011 --- /dev/null +++ b/test/nptl/tst-join4.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t bar; + + +static void * +tf (void *arg) +{ + if (pthread_barrier_wait (&bar) != 0) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bar, NULL, 3) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + pthread_t th[2]; + + if (pthread_create (&th[0], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED) != 0) + { + puts ("attr_setdetachstate failed"); + exit (1); + } + + if (pthread_create (&th[1], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + if (pthread_detach (th[0]) != 0) + { + puts ("could not detach 1st thread"); + exit (1); + } + + int err = pthread_detach (th[0]); + if (err == 0) + { + puts ("second detach of 1st thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("second detach of 1st thread returned %d, not EINVAL\n", err); + exit (1); + } + + err = pthread_detach (th[1]); + if (err == 0) + { + puts ("detach of 2nd thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("detach of 2nd thread returned %d, not EINVAL\n", err); + exit (1); + } + + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join5.c b/test/nptl/tst-join5.c new file mode 100644 index 000000000..b08af6e43 --- /dev/null +++ b/test/nptl/tst-join5.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static void * +tf1 (void *arg) +{ + pthread_join ((pthread_t) arg, NULL); + + puts ("1st join returned"); + + return (void *) 1l; +} + + +static void * +tf2 (void *arg) +{ + int a; + a = pthread_join ((pthread_t) arg, NULL); + + puts ("2nd join returned"); + printf("a = %i\n", a); + + return (void *) 1l; +} + + +static int +do_test (void) +{ + pthread_t th; + + int err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("1st circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("1st circular join %d, not EDEADLK\n", err); + exit (1); + } + + if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 1st thread"); + exit (1); + } + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + printf ("cannot join 1st thread: %d\n", err); + exit (1); + } + if (r != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + exit (1); + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + exit (1); + } + + if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 2nd thread"); + exit (1); + } + + if (pthread_join (th, &r) != 0) + { + puts ("cannot join 2nd thread"); + exit (1); + } + if (r != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + exit (1); + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + exit (1); + } + + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key1.c b/test/nptl/tst-key1.c new file mode 100644 index 000000000..dfbe58417 --- /dev/null +++ b/test/nptl/tst-key1.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + int max; +#ifdef PTHREAD_KEYS_MAX + max = PTHREAD_KEYS_MAX; +#else + max = _POSIX_THREAD_KEYS_MAX; +#endif + pthread_key_t *keys = alloca (max * sizeof (pthread_key_t)); + + int i; + for (i = 0; i < max; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + else + { + printf ("created key %d\n", i); + + if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + } + + for (i = 0; i < max; ++i) + { + if (pthread_getspecific (keys[i]) != (void *) (i + 100l)) + { + write (2, "getspecific failed\n", 19); + _exit (1); + } + + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + } + + /* Now it must be once again possible to allocate keys. */ + if (pthread_key_create (&keys[0], NULL) != 0) + { + write (2, "2nd key_create failed\n", 22); + _exit (1); + } + + if (pthread_key_delete (keys[0]) != 0) + { + write (2, "2nd key_delete failed\n", 22); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key2.c b/test/nptl/tst-key2.c new file mode 100644 index 000000000..c5493322c --- /dev/null +++ b/test/nptl/tst-key2.c @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +#define N 2 + + +static int cnt0; +static void +f0 (void *p) +{ + ++cnt0; +} + + +static int cnt1; +static void +f1 (void *p) +{ + ++cnt1; +} + + +static void (*fcts[N]) (void *) = +{ + f0, + f1 +}; + + +static void * +tf (void *arg) +{ + pthread_key_t *key = (pthread_key_t *) arg; + + if (pthread_setspecific (*key, (void *) -1l) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_key_t keys[N]; + + int i; + for (i = 0; i < N; ++i) + if (pthread_key_create (&keys[i], fcts[i]) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &keys[1]) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + write (2, "join failed\n", 12); + _exit (1); + } + + if (cnt0 != 0) + { + write (2, "cnt0 != 0\n", 10); + _exit (1); + } + + if (cnt1 != 1) + { + write (2, "cnt1 != 1\n", 10); + _exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key3.c b/test/nptl/tst-key3.c new file mode 100644 index 000000000..73cb7417a --- /dev/null +++ b/test/nptl/tst-key3.c @@ -0,0 +1,156 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +#define N 2 + + +static int cnt0; +static void +f0 (void *p) +{ + ++cnt0; +} + + +static int cnt1; +static void +f1 (void *p) +{ + ++cnt1; +} + + +static void (*fcts[N]) (void *) = +{ + f0, + f1 +}; + + +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + pthread_key_t *key = (pthread_key_t *) arg; + + if (pthread_setspecific (*key, (void *) -1l) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + + pthread_barrier_wait (&b); + + const struct timespec t = { .tv_sec = 1000, .tv_nsec = 0 }; + while (1) + nanosleep (&t, NULL); + + /* NOTREACHED */ + return NULL; +} + + +int +do_test (void) +{ + pthread_key_t keys[N]; + + int i; + for (i = 0; i < N; ++i) + if (pthread_key_create (&keys[i], fcts[i]) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + write (2, "barrier_init failed\n", 20); + _exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &keys[1]) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + pthread_barrier_wait (&b); + + if (pthread_cancel (th) != 0) + { + write (2, "cancel failed\n", 14); + _exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + write (2, "join failed\n", 12); + _exit (1); + } + + if (status != PTHREAD_CANCELED) + { + write (2, "thread not canceled\n", 20); + _exit (1); + } + + /* Note that the TSD destructors not necessarily have to have + finished by the time pthread_join returns. At least according to + POSIX. We implement the stronger requirement that they indeed + have run and therefore these tests succeed. */ + if (cnt0 != 0) + { + write (2, "cnt0 != 0\n", 10); + _exit (1); + } + + if (cnt1 != 1) + { + write (2, "cnt1 != 1\n", 10); + _exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + + if (pthread_barrier_destroy (&b) != 0) + { + write (2, "barrier_destroy failed\n", 23); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key4.c b/test/nptl/tst-key4.c new file mode 100644 index 000000000..0a5b448e5 --- /dev/null +++ b/test/nptl/tst-key4.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#ifdef PTHREAD_KEYS_MAX +const int max = PTHREAD_KEYS_MAX; +#else +const int max = _POSIX_THREAD_KEYS_MAX; +#endif +static pthread_key_t *keys; + + +static void * +tf1 (void *arg) +{ + int i; + for (i = 0; i < max; ++i) + if (pthread_setspecific (keys[i], (void *) (long int) (i + 1)) != 0) + { + puts ("setspecific failed"); + exit (1); + } + + return NULL; +} + + +static void * +tf2 (void *arg) +{ + int i; + for (i = 0; i < max; ++i) + if (pthread_getspecific (keys[i]) != NULL) + { + printf ("getspecific for key %d not NULL\n", i); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + keys = alloca (max * sizeof (pthread_key_t)); + + int i; + for (i = 0; i < max; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + puts ("key_create failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < 10; ++i) + { + int j; +#define N 2 + pthread_t th[N]; + for (j = 0; j < N; ++j) + if (pthread_create (&th[j], NULL, tf1, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("1st join failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_create (&th[j], NULL, tf2, NULL) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("2nd join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill1.c b/test/nptl/tst-kill1.c new file mode 100644 index 000000000..9eaf29be7 --- /dev/null +++ b/test/nptl/tst-kill1.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + +static void * +tf (void *a) +{ + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* This call should never return. */ + pthread_cond_wait (&c, &m); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it doesn't catch and which will + cause the process to terminate. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th, NULL); + + return 0; +} + + +#define EXPECTED_SIGNAL SIGUSR1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill2.c b/test/nptl/tst-kill2.c new file mode 100644 index 000000000..1e3dc4104 --- /dev/null +++ b/test/nptl/tst-kill2.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + +static void * +tf (void *a) +{ + /* Block SIGUSR1. */ + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* Compute timeout. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + /* Timeout: 1sec. */ + ts.tv_sec += 1; + + /* This call should never return. */ + if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT) + { + puts ("cond_timedwait didn't time out"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it has blocked. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != NULL) + { + puts ("return value wrong"); + exit (1); + } + + return 0; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill3.c b/test/nptl/tst-kill3.c new file mode 100644 index 000000000..9ea8d553b --- /dev/null +++ b/test/nptl/tst-kill3.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + + +static void +handler (int sig) +{ + write (1, "handler called\n", 15); + _exit (1); +} + + +static void * +tf (void *a) +{ + /* Block SIGUSR1. */ + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* Compute timeout. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + /* Timeout: 1sec. */ + ts.tv_sec += 1; + + /* This call should never return. */ + if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT) + { + puts ("cond_timedwait didn't time out"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + if (sigaction (SIGUSR1, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it has blocked. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != NULL) + { + puts ("return value wrong"); + exit (1); + } + + return 0; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill4.c b/test/nptl/tst-kill4.c new file mode 100644 index 000000000..4e7ff5eaf --- /dev/null +++ b/test/nptl/tst-kill4.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *a) +{ + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + /* The following only works because we assume here something about + the implementation. Namely, that the memory allocated for the + thread descriptor is not going away, that the the TID field is + cleared and therefore the signal is sent to process 0, and that + we can savely assume there is no other process with this ID at + that time. */ + int e = pthread_kill (th, 0); + if (e == 0) + { + puts ("pthread_kill succeeded"); + exit (1); + } + if (e != ESRCH) + { + puts ("pthread_kill didn't return ESRCH"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill5.c b/test/nptl/tst-kill5.c new file mode 100644 index 000000000..12560943c --- /dev/null +++ b/test/nptl/tst-kill5.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + + +int +do_test (void) +{ + /* XXX This test might require architecture and system specific changes. + There is no guarantee that this signal number is invalid. */ + int e = pthread_kill (pthread_self (), SIGRTMAX + 10); + if (e == 0) + { + puts ("kill didn't failed"); + exit (1); + } + if (e != EINVAL) + { + puts ("error not EINVAL"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill6.c b/test/nptl/tst-kill6.c new file mode 100644 index 000000000..26e82d98f --- /dev/null +++ b/test/nptl/tst-kill6.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_t receiver; +static sem_t sem; +static pthread_barrier_t b; + +static void +handler (int sig) +{ + if (sig != SIGUSR1) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + if (pthread_self () != receiver) + { + write (STDOUT_FILENO, "not the intended receiver\n", 26); + _exit (1); + } + + if (sem_post (&sem) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + + +static void * +tf (void *a) +{ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + if (sigaction (SIGUSR1, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + +#define N 20 + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + pthread_t th[N]; + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + for (i = 0; i < N * 10; ++i) + { + receiver = th[i % N]; + + if (pthread_kill (receiver, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue.h b/test/nptl/tst-mqueue.h new file mode 100644 index 000000000..8e73be51c --- /dev/null +++ b/test/nptl/tst-mqueue.h @@ -0,0 +1,84 @@ +/* Common code for message queue passing tests. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <mqueue.h> +#include <search.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/uio.h> +#include <unistd.h> + +static int temp_mq_fd; + +/* Add temporary files in list. */ +static void +__attribute__ ((unused)) +add_temp_mq (const char *name) +{ + struct iovec iov[2]; + iov[0].iov_base = (char *) name; + iov[0].iov_len = strlen (name); + iov[1].iov_base = (char *) "\n"; + iov[1].iov_len = 1; + if (writev (temp_mq_fd, iov, 2) != iov[0].iov_len + 1) + printf ("Could not record temp mq filename %s\n", name); +} + +/* Delete all temporary message queues. */ +static void +do_cleanup (void) +{ + if (lseek (temp_mq_fd, 0, SEEK_SET) != 0) + return; + + FILE *f = fdopen (temp_mq_fd, "r"); + if (f == NULL) + return; + + char *line = NULL; + size_t n = 0; + ssize_t rets; + while ((rets = getline (&line, &n, f)) > 0) + { + if (line[rets - 1] != '\n') + continue; + + line[rets - 1] = '\0'; + mq_unlink (line); + } + fclose (f); +} + +static void +do_prepare (void) +{ + char name [] = "/tmp/tst-mqueueN.XXXXXX"; + temp_mq_fd = mkstemp (name); + if (temp_mq_fd == -1) + { + printf ("Could not create temporary file %s: %m\n", name); + exit (1); + } + unlink (name); +} + +#define PREPARE(argc, argv) do_prepare () +#define CLEANUP_HANDLER do_cleanup () diff --git a/test/nptl/tst-mqueue1.c b/test/nptl/tst-mqueue1.c new file mode 100644 index 000000000..70e42377b --- /dev/null +++ b/test/nptl/tst-mqueue1.c @@ -0,0 +1,417 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static int +intcmp (const void *a, const void *b) +{ + if (*(unsigned char *)a < *(unsigned char *)b) + return 1; + if (*(unsigned char *)a > *(unsigned char *)b) + return -1; + return 0; +} + +static int +check_attrs (struct mq_attr *attr, int nonblock, long cnt) +{ + int result = 0; + + if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1) + { + printf ("attributes don't match those passed to mq_open\n" + "mq_maxmsg %ld, mq_msgsize %ld\n", + attr->mq_maxmsg, attr->mq_msgsize); + result = 1; + } + + if ((attr->mq_flags & O_NONBLOCK) != nonblock) + { + printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock); + result = 1; + } + + if (attr->mq_curmsgs != cnt) + { + printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt); + result = 1; + } + + return result; +} + +static int +do_one_test (mqd_t q, const char *name, int nonblock) +{ + int result = 0; + + char v [] + = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 }; + + struct mq_attr attr; + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_receive (q, &v[0], 1, NULL) != -1) + { + puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + --ts.tv_sec; + else + { + ts.tv_sec = time (NULL) - 1; + ts.tv_nsec = 0; + } + + int ret; + for (int i = 0; i < 10; ++i) + { + if (i & 1) + ret = mq_send (q, &v[i], 1, v[i] >> 4); + else + ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts); + + if (ret) + { + printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed"); + result = 1; + } + } + + ret = mq_timedsend (q, &v[10], 1, 8, &ts); + if (ret != -1) + { + puts ("mq_timedsend on full queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedsend on full queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_send (q, &v[10], 1, 8); + if (ret != -1) + { + puts ("mq_send on full non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_send on full non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + result = 1; + } + else if (pid == 0) + { + result = 0; + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + q = mq_open (name, O_RDONLY | nonblock); + if (q == (mqd_t) -1) + { + printf ("mq_open in child failed: %m\n"); + exit (1); + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + char vr[11] = { }; + unsigned int prio; + ssize_t rets; + + if (mq_send (q, &v[0], 1, 1) != -1) + { + puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + for (int i = 0; i < 10; ++i) + { + if (i & 1) + rets = mq_receive (q, &vr[i], 1, &prio); + else + rets = mq_timedreceive (q, &vr[i], 1, &prio, &ts); + + if (rets != 1) + { + if (rets == -1) + printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed"); + else + printf ("mq_%sreceive returned %zd != 1\n", + (i & 1) ? "" : "timed", rets); + result = 1; + } + else if (prio != (unsigned int) vr[i] >> 4) + { + printf ("unexpected priority %x for value %02x\n", prio, + vr[i]); + result = 1; + } + } + + qsort (v, 10, 1, intcmp); + if (memcmp (v, vr, 10) != 0) + { + puts ("messages not received in expected order"); + result = 1; + } + + rets = mq_timedreceive (q, &vr[10], 1, &prio, &ts); + if (rets != -1) + { + puts ("mq_timedreceive on empty queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedreceive on empty queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_receive (q, &vr[10], 1, &prio); + if (ret != -1) + { + puts ("mq_receive on empty non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_receive on empty non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + exit (result); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed: %d\n", status); + result = 1; + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + return result; +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + result |= do_one_test (q, name, 0); + + mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK); + if (q2 == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + q2 = q; + result = 1; + } + else + { + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + q = q2; + result |= do_one_test (q, name, O_NONBLOCK); + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + { + attr.mq_flags ^= O_NONBLOCK; + + struct mq_attr attr2; + memset (&attr2, 0x55, sizeof (attr2)); + if (mq_setattr (q, &attr, &attr2) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK) + || attr.mq_maxmsg != attr2.mq_maxmsg + || attr.mq_msgsize != attr2.mq_msgsize + || attr.mq_curmsgs != 0 + || attr2.mq_curmsgs != 0) + { + puts ("mq_setattr returned unexpected values in *omqstat"); + result = 1; + } + else + { + result |= do_one_test (q, name, 0); + + if (mq_setattr (q, &attr2, NULL) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else + result |= do_one_test (q, name, O_NONBLOCK); + } + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_close (q) != -1) + { + puts ("second mq_close did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("second mq_close did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue2.c b/test/nptl/tst-mqueue2.c new file mode 100644 index 000000000..1948965c6 --- /dev/null +++ b/test/nptl/tst-mqueue2.c @@ -0,0 +1,477 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static void +alrm_handler (int sig) +{ +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with O_EXCL unexpectedly succeeded"); + result = 1; + } + else if (errno != EEXIST) + { + printf ("mq_open did not fail with EEXIST: %m\n"); + result = 1; + } + + char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3]; + snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ()); + + attr.mq_maxmsg = -2; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_maxmsg did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + attr.mq_maxmsg = 2; + attr.mq_msgsize = -56; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_msgsize unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_msgsize did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + char buf[3]; + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ts.tv_sec += 10; + else + { + ts.tv_sec = time (NULL) + 10; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0) + { + puts ("mq_timedreceive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_timedreceive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -1; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = 1000000000; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it = { .it_value = { .tv_sec = 1 } }; + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_receive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_nsec = 0; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + buf[0] = '6'; + buf[1] = '7'; + if (mq_send (q, buf, 2, 3) != 0 + || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0)) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q, buf, 3, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 4 || memcmp (buf, "8 ", 3) != 0) + { + printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + rets = mq_receive (q, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "67 ", 3) != 0) + { + printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + buf[0] = '2'; + buf[1] = '1'; + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + if ((mq_timedsend (q, buf, 2, 5, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0)) + || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec, + (mq_timedsend (q, buf, 1, 4, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0)))) + { + printf ("mq_timedsend failed: %m\n"); + result = 1; + } + + buf[0] = '-'; + ts.tv_nsec = 1000000001; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = -2; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with megatove tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_send (q, buf, 2, 8) == 0) + { + puts ("mq_send on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_send on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_sec += 10; + ts.tv_nsec = 0; + if (mq_timedsend (q, buf, 2, 7, &ts) == 0) + { + puts ("mq_timedsend on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedsend on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + rets = mq_timedreceive (q, buf, 2, &prio, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, &prio); + if (rets != 2) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 2\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "21 ", 3) != 0) + { + printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_receive (q, buf, 1, NULL) == 0) + { + puts ("mq_receive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_receive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -ts.tv_nsec; + rets = mq_timedreceive (q, buf, 2, NULL, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, NULL); + if (rets != 1) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 1\n", rets); + result = 1; + } + else if (memcmp (buf, "31 ", 3) != 0) + { + printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_send (q, "", 0, 2) != 0) + { + printf ("mq_send with msg_len 0 failed: %m\n"); + result = 1; + } + + rets = mq_receive (q, buf, 2, &prio); + if (rets) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 0\n", rets); + result = 1; + } + + long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX); + if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max) + { + if (mq_send (q, buf, 1, mq_prio_max) == 0) + { + puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_send with MQ_PRIO_MAX priority did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, mq_prio_max - 1) != 0) + { + printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n"); + result = 1; + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDWR); + if (q2 != (mqd_t) -1) + { + printf ("mq_open of unlinked %s without O_CREAT unexpectedly" + "succeeded\n", name); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_open of unlinked %s without O_CREAT did not fail with " + "ENOENT: %m\n", name); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, 2) == 0) + { + puts ("mq_send on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_getattr (q, &attr) == 0) + { + puts ("mq_getattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&attr, 0, sizeof (attr)); + if (mq_setattr (q, &attr, NULL) == 0) + { + puts ("mq_setattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1) + { + puts ("mq_unlink of non-existant message queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_unlink of non-existant message queue did not fail with " + "ENOENT: %m\n"); + result = 1; + } + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue3.c b/test/nptl/tst-mqueue3.c new file mode 100644 index 000000000..990e05728 --- /dev/null +++ b/test/nptl/tst-mqueue3.c @@ -0,0 +1,244 @@ +/* Test SIGEV_THREAD handling for POSIX message queues. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +static pid_t pid; +static mqd_t m; +static const char message[] = "hello"; + +# define MAXMSG 10 +# define MSGSIZE 10 +# define UNIQUE 42 + + +static void +fct (union sigval s) +{ + /* Put the mq in non-blocking mode. */ + struct mq_attr attr; + if (mq_getattr (m, &attr) != 0) + { + printf ("%s: mq_getattr failed: %m\n", __FUNCTION__); + exit (1); + } + attr.mq_flags |= O_NONBLOCK; + if (mq_setattr (m, &attr, NULL) != 0) + { + printf ("%s: mq_setattr failed: %m\n", __FUNCTION__); + exit (1); + } + + /* Check the values. */ + if (attr.mq_maxmsg != MAXMSG) + { + printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_maxmsg, MAXMSG); + exit (1); + } + if (attr.mq_msgsize != MAXMSG) + { + printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_msgsize, MSGSIZE); + exit (1); + } + + /* Read the message. */ + char buf[attr.mq_msgsize]; + ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL)); + if (n != sizeof (message)) + { + printf ("%s: length of message wrong: is %zd, expected %zu\n", + __FUNCTION__, n, sizeof (message)); + exit (1); + } + if (memcmp (buf, message, sizeof (message)) != 0) + { + printf ("%s: message wrong: is \"%s\", expected \"%s\"\n", + __FUNCTION__, buf, message); + exit (1); + } + + exit (UNIQUE); +} + + +int +do_test (void) +{ + char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b; + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + /* Name for the message queue. */ + char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)]; + snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld", + (long int) getpid ()); + + /* Create the message queue. */ + struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE }; + m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (m == -1) + { + if (errno == ENOSYS) + { + puts ("not implemented"); + return 0; + } + + puts ("mq_open failed"); + return 1; + } + + /* Unlink the message queue right away. */ + if (mq_unlink (mqname) != 0) + { + puts ("mq_unlink failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + if (pid == 0) + { + /* Request notification via thread. */ + struct sigevent ev; + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_value.sival_ptr = NULL; + ev.sigev_notify_attributes = NULL; + + /* Tell the kernel. */ + if (mq_notify (m,&ev) != 0) + { + puts ("mq_notify failed"); + exit (1); + } + + /* Tell the parent we are ready. */ + (void) pthread_barrier_wait (b); + + /* Make sure the process goes away eventually. */ + alarm (10); + + /* Do nothing forever. */ + while (1) + pause (); + } + + /* Wait for the child process to register to notification method. */ + (void) pthread_barrier_wait (b); + + /* Send the message. */ + if (mq_send (m, message, sizeof (message), 1) != 0) + { + kill (pid, SIGKILL); + puts ("mq_send failed"); + return 1; + } + + int r; + if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid) + { + kill (pid, SIGKILL); + puts ("waitpid failed"); + return 1; + } + + return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1; +} +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue4.c b/test/nptl/tst-mqueue4.c new file mode 100644 index 000000000..aa31706f8 --- /dev/null +++ b/test/nptl/tst-mqueue4.c @@ -0,0 +1,288 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX]; + char *p; + p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ()); + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + *p = '.'; + memset (p + 1, 'x', NAME_MAX + 1 - (p - name)); + name[NAME_MAX + 1] = '\0'; + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open with NAME_MAX long name compoment failed with: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + name[NAME_MAX + 1] = 'x'; + name[NAME_MAX + 2] = '\0'; + q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with too long name component unexpectedly succeeded"); + mq_unlink (name); + mq_close (q2); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_open with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + if (mq_unlink (name) == 0) + { + puts ("mq_unlink with too long name component unexpectedly succeeded"); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_unlink with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + *p = '\0'; + attr.mq_maxmsg = 1; + attr.mq_msgsize = 3; + q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_EXCL failed with %m\n"); + result = 1; + } + + char buf[3]; + strcpy (buf, "jk"); + if (mq_send (q, buf, 2, 4) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_send (q, buf + 1, 1, 5) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_getattr (q2, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 2) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedsend (q2, buf, 1, 1, &ts) == 0) + { + puts ("mq_timedsend unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDONLY, 0600); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + mqd_t q3 = mq_open (name, O_RDONLY, 0600); + if (q3 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q2, buf, 2, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "k ", 3) != 0) + { + printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_getattr (q3, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 1) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + rets = mq_receive (q3, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "jk ", 3) != 0) + { + printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1) + { + puts ("mq_timedreceive on empty queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedreceive on empty queue did not fail with " + "ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue5.c b/test/nptl/tst-mqueue5.c new file mode 100644 index 000000000..97571da8a --- /dev/null +++ b/test/nptl/tst-mqueue5.c @@ -0,0 +1,1014 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 3 + +#if _POSIX_THREADS +# include <pthread.h> + +volatile int rtmin_cnt; +volatile pid_t rtmin_pid; +volatile uid_t rtmin_uid; +volatile int rtmin_code; +volatile union sigval rtmin_sigval; + +static void +rtmin_handler (int sig, siginfo_t *info, void *ctx) +{ + if (sig != SIGRTMIN) + abort (); + ++rtmin_cnt; + rtmin_pid = info->si_pid; + rtmin_uid = info->si_uid; + rtmin_code = info->si_code; + rtmin_sigval = info->si_value; +} + +#define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +#define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +struct thr_data +{ + const char *name; + pthread_barrier_t *b3; + mqd_t q; +}; + +static void * +thr (void *arg) +{ + pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3; + mqd_t q = ((struct thr_data *)arg)->q; + const char *name = ((struct thr_data *)arg)->name; + int result = 0; + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 0xdeadbeef) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef); + result = 1; + } + + struct sigevent ev; + memset (&ev, 0x82, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + if (mq_notify (q, NULL) != 0) + { + printf ("second mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q4 = mq_open (name, O_RDONLY); + if (q4 == (mqd_t) -1) + { + printf ("mq_open in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q4, NULL) != 0) + { + printf ("mq_notify in thread (q4, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q4) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q5 = mq_open (name, O_WRONLY); + if (q5 == (mqd_t) -1) + { + printf ("mq_open O_WRONLY in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q5, NULL) != 0) + { + printf ("mq_notify in thread (q5, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q5) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + + return (void *) (long) result; +} + +static void +do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3, + mqd_t q) +{ + int result = 0; + + struct sigevent ev; + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which makes notification available. */ + + (void) pthread_barrier_wait (b2); + + rtmin_cnt = 0; + + if (mq_notify (q, &ev) != 0) + { + printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal in child caught too early"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify. */ + /* Parent calls mqsend (q), which makes notification available + and triggers a signal in the child. */ + /* Parent successfully calls mq_notify SIGEV_SIGNAL. */ + + (void) pthread_barrier_wait (b2); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_ptr != &ev) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev); + result = 1; + } + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Parent verifies caught SIGRTMIN. */ + + mqd_t q2 = mq_open (name, O_RDWR); + if (q2 == (mqd_t) -1) + { + printf ("mq_open in child failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent mq_open's another mqd_t for the same queue (q3). */ + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q2, &ev) != 0) + { + printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent successfully calls mq_notify { SIGEV_NONE } on q3. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &b2; + if (mq_notify (q, &ev) == 0) + { + puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mq_close on q3, which makes the queue available again for + notification. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x13, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in child (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + struct thr_data thr_data = { .name = name, .b3 = b3, .q = q }; + pthread_t th; + int ret = pthread_create (&th, NULL, thr, &thr_data); + if (ret) + { + errno = ret; + printf ("pthread_created failed with: %m\n"); + result = 1; + } + + /* Wait till thr calls mq_receive on the empty queue q and blocks on it. */ + sleep (1); + + memset (&ev, 0x5f, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 0xdeadbeef; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which should wake up mqrecv (q) + in the thread but no notification should be sent. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught while thr was blocked on mq_receive"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been received. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + memset (&ev, 0x6a, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = do_child; + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL), which should unregister the above + notification. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0x7b, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = thr; + if (mq_notify (q, &ev) != 0) + { + printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0xe1, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 127; + if (mq_notify (q, &ev) != 0) + { + printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + void *thr_ret; + ret = pthread_join (th, &thr_ret); + if (ret) + { + errno = ret; + printf ("pthread_join failed: %m\n"); + result = 1; + } + else if (thr_ret) + result = 1; + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + exit (result); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b2; + b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrier_t *b3; + b3 = b2 + 1; + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b2, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (b3, &a, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + /* Implementation-defined behaviour, so don't fail, + just inform. */ + printf ("second mq_notify (q, NULL) failed with: %m\n"); + } + + struct sigaction sa = { .sa_sigaction = rtmin_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 26; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqsend (q); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != getpid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 26) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n", + rtmin_pid, getpid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + ev.sigev_value.sival_int = 75; + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork () failed: %m\n"); + mq_unlink (name); + return 1; + } + + if (pid == 0) + do_child (name, b2, b3, q); + + /* Child unsuccessfully attempts to mq_notify. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify SIGEV_SIGNAL now. */ + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 15; + if (mq_notify (q, &ev) == 0) + { + puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child verifies caught SIGRTMIN signal. */ + /* Child calls mq_send (q) which triggers SIGRTMIN signal here. */ + + (void) pthread_barrier_wait (b2); + + /* Child mq_open's another mqd_t for the same queue (q2). */ + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != pid + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 15) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n", + rtmin_pid, pid, rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child calls mq_close on q2, which makes the queue available again for + notification. */ + + mqd_t q3 = mq_open (name, O_RDWR); + if (q3 == (mqd_t) -1) + { + printf ("mq_open q3 in parent failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x12, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q3, &ev) != 0) + { + printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_NONE } on q. */ + /* Child successfully calls mq_notify NULL on q. */ + + (void) pthread_barrier_wait (b2); + + /* Child creates new thread. */ + /* Thread blocks on mqrecv (q). */ + /* Child sleeps for 1sec so that thread has time to reach that point. */ + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been caught. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL). */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL). */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed with status %d\n", status); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue6.c b/test/nptl/tst-mqueue6.c new file mode 100644 index 000000000..5c9ee69e1 --- /dev/null +++ b/test/nptl/tst-mqueue6.c @@ -0,0 +1,305 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#if _POSIX_THREADS +# include <pthread.h> + +# define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +# define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +volatile int fct_cnt, fct_err; +size_t fct_guardsize; + +static void +fct (union sigval s) +{ + mqd_t q = *(mqd_t *) s.sival_ptr; + + pthread_attr_t nattr; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("pthread_getattr_np failed: %m\n"); + fct_err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &fct_guardsize); + if (ret) + { + errno = ret; + printf ("pthread_attr_getguardsize failed: %m\n"); + fct_err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + fct_err = 1; + } + } + + ++fct_cnt; + fct_err |= mqsend (q); +} + +# define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + fct_guardsize = 1; + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + size_t ps = sysconf (_SC_PAGESIZE); + if (pthread_attr_setguardsize (&nattr, 32 * ps)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 0) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 1) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 0) + { + printf ("fct_guardsize %zd != 0\n", fct_guardsize); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 1) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 2) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 32 * ps) + { + printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_int = 0; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (fct_err) + result = 1; + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue7.c b/test/nptl/tst-mqueue7.c new file mode 100644 index 000000000..34222f834 --- /dev/null +++ b/test/nptl/tst-mqueue7.c @@ -0,0 +1,109 @@ +/* Test all open message queues descriptors are closed during exec*. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#define OPT_AFTEREXEC 20000 + +static mqd_t after_exec = (mqd_t) -1; + +#define CMDLINE_OPTIONS \ + { "after-exec", required_argument, NULL, OPT_AFTEREXEC }, + +#define CMDLINE_PROCESS \ + case OPT_AFTEREXEC: \ + after_exec = (mqd_t) strtoul (optarg, NULL, 0); \ + break; + +static int +do_after_exec (void) +{ + int result = 0; + + struct mq_attr attr; + if (mq_getattr (after_exec, &attr) == 0) + { + puts ("mq_getattr after exec unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr after exec did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +static int +do_test (int argc, char **argv) +{ + if (after_exec != (mqd_t) -1) + return do_after_exec (); + + char name[sizeof "/tst-mqueue7-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue7-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + return 1; + } + + char after_exec_arg[sizeof "--after-exec=0x" + sizeof (long) * 3]; + snprintf (after_exec_arg, sizeof (after_exec_arg), + "--after-exec=0x%lx", (long) q); + + const char *newargv[argc + 2]; + for (int i = 1; i < argc; ++i) + newargv[i - 1] = argv[i]; + newargv[argc - 1] = "--direct"; + newargv[argc] = after_exec_arg; + newargv[argc + 1] = NULL; + + /* Verify that exec* has the effect of mq_close (q). */ + execv (newargv[0], (char * const *) newargv); + printf ("execv failed: %m\n"); + return 1; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue8.c b/test/nptl/tst-mqueue8.c new file mode 100644 index 000000000..7e902aa60 --- /dev/null +++ b/test/nptl/tst-mqueue8.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +static pthread_barrier_t b; + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + +#define TF_MQ_RECEIVE 0L +#define TF_MQ_TIMEDRECEIVE 1L +#define TF_MQ_SEND 2L +#define TF_MQ_TIMEDSEND 3L + +static const char *names[] + = { "mq_receive", "mq_timedreceive", "mq_send", "mq_timedsend" }; + +static mqd_t q; +static struct timespec never; + +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); + + char c = ' '; + + switch ((long) arg) + { + case TF_MQ_SEND: + TEMP_FAILURE_RETRY (mq_send (q, &c, 1, 1)); + break; + case TF_MQ_TIMEDSEND: + TEMP_FAILURE_RETRY (mq_timedsend (q, &c, 1, 1, &never)); + break; + case TF_MQ_RECEIVE: + TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + break; + case TF_MQ_TIMEDRECEIVE: + TEMP_FAILURE_RETRY (mq_timedreceive (q, &c, 1, NULL, &never)); + break; + } + + pthread_cleanup_pop (0); + + printf ("tf: %s returned\n", names[(long) arg]); + + exit (1); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + char name[sizeof "/tst-mqueue8-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue8-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (clock_gettime (CLOCK_REALTIME, &never) == 0) + never.tv_sec += 100; + else + { + never.tv_sec = time (NULL) + 100; + never.tv_nsec = 0; + } + + int result = 0; + for (long l = TF_MQ_RECEIVE; l <= TF_MQ_TIMEDSEND; ++l) + { + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("1st %s create failed\n", names[l]); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + printf ("going to cancel %s in-time\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("1st cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("1st join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("1st %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("in-time %s cancellation succeeded\n", names[l]); + + cl_called = 0; + + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("2nd %s create failed\n", names[l]); + result = 1; + continue; + } + + printf ("going to cancel %s early\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("2nd cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + if (pthread_join (th, &status) != 0) + { + printf ("2nd join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("2nd %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("early %s cancellation succeeded\n", names[l]); + + if (l == TF_MQ_TIMEDRECEIVE) + { + /* mq_receive and mq_timedreceive are tested on empty mq. + For mq_send and mq_timedsend we need to make it full. + If this fails, there is no point in doing further testing. */ + char c = ' '; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + break; + } + } + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue9.c b/test/nptl/tst-mqueue9.c new file mode 100644 index 000000000..fb057d4ad --- /dev/null +++ b/test/nptl/tst-mqueue9.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + if (geteuid () != 0) + { + puts ("this test requires root"); + return 0; + } + + char name[sizeof "/tst-mqueue9-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue9-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else + add_temp_mq (name); + + if (seteuid (1) != 0) + { + printf ("failed to seteuid (1): %m\n"); + mq_unlink (name); + return 0; + } + + int result = 0; + if (mq_unlink (name) == 0) + { + puts ("mq_unlink unexpectedly succeeded"); + result = 1; + } + else if (errno != EACCES) + { + printf ("mq_unlink did not fail with EACCES: %m\n"); + result = 1;; + } + + if (seteuid (0) != 0) + { + printf ("failed to seteuid (0): %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed with: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex1.c b/test/nptl/tst-mutex1.c new file mode 100644 index 000000000..50b5ccaf0 --- /dev/null +++ b/test/nptl/tst-mutex1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_mutex_t m; + + if (pthread_mutex_init (&m, NULL) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex2.c b/test/nptl/tst-mutex2.c new file mode 100644 index 000000000..f589a1ea1 --- /dev/null +++ b/test/nptl/tst-mutex2.c @@ -0,0 +1,223 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + int e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("child: 1st mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("child: 1st mutex_unlock error != EPERM"); + exit (1); + } + + e = pthread_mutex_trylock (&m); + if (e == 0) + { + puts ("child: 1st trylock suceeded"); + exit (1); + } + if (e != EBUSY) + { + puts ("child: 1st trylock didn't return EBUSY"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 1st barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 2nd barrier_wait failed"); + exit (1); + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("child: 2nd mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("child: 2nd mutex_unlock error != EPERM"); + exit (1); + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("child: 2nd trylock failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("child: 3rd mutex_unlock failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + int e; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if ((e = pthread_mutex_unlock (&m)) == 0) + { + puts ("1st mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("1st mutex_unlock error != EPERM"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if ((e = pthread_mutex_lock (&m)) == 0) + { + puts ("2nd mutex_lock succeeded"); + exit (1); + } + else if (e != EDEADLK) + { + puts ("2nd mutex_lock error != EDEADLK"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + exit (1); + } + + if ((e = pthread_mutex_unlock (&m)) == 0) + { + puts ("3rd mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("3rd mutex_unlock error != EPERM"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + exit (1); + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + exit (1); + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex3.c b/test/nptl/tst-mutex3.c new file mode 100644 index 000000000..8e57924ba --- /dev/null +++ b/test/nptl/tst-mutex3.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + int e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("1st mutex_unlock in child succeeded"); + exit (1); + } + if (e != EPERM) + { + puts ("1st mutex_unlock in child didn't return EPERM"); + exit (1); + } + + e = pthread_mutex_trylock (&m); + if (e == 0) + { + puts ("mutex_trylock in second thread succeeded"); + exit (1); + } + if (e != EBUSY) + { + puts ("mutex_trylock returned wrong value"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("2nd mutex_unlock in child succeeded"); + exit (1); + } + if (e != EPERM) + { + puts ("2nd mutex_unlock in child didn't return EPERM"); + exit (1); + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("2nd mutex_trylock in second thread failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("3rd mutex_unlock in second thread failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("1st trylock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("3rd mutex_unlock failed"); + return 1; + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("4th mutex_unlock succeeded"); + return 1; + } + if (e != EPERM) + { + puts ("4th mutex_unlock didn't return EPERM"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex4.c b/test/nptl/tst-mutex4.c new file mode 100644 index 000000000..0ce7313ca --- /dev/null +++ b/test/nptl/tst-mutex4.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-mutex4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t a; + pid_t pid; + char *p; + int err; + int s; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + p = (char *) (m + 1); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&a, &s) != 0) + { + puts ("1st mutexattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&a, &s) != 0) + { + puts ("2nd mutexattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_mutex_init (m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + err = pthread_mutex_trylock (m); + if (err == 0) + { + puts ("mutex_trylock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("mutex_trylock didn't return EBUSY"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + puts ("child: 1st mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_mutex_lock (m) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (*p != 1) + { + puts ("*p != 1"); + return 1; + } + + puts ("parent done"); + } + + return 0; +} + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex5.c b/test/nptl/tst-mutex5.c new file mode 100644 index 000000000..eb35b78d3 --- /dev/null +++ b/test/nptl/tst-mutex5.c @@ -0,0 +1,186 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +#ifndef TYPE +# define TYPE PTHREAD_MUTEX_NORMAL +#endif + + +static int +do_test (void) +{ + pthread_mutex_t m; + struct timespec ts; + struct timeval tv; + struct timeval tv2; + int err; + pthread_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, TYPE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_trylock (&m) == 0) + { + puts ("mutex_trylock succeeded"); + return 1; + } + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + + err = pthread_mutex_timedlock (&m, &ts); + if (err == 0) + { + puts ("timedlock succeeded"); + return 1; + } + else if (err != ETIMEDOUT) + { + printf ("timedlock error != ETIMEDOUT: %d\n", err); + return 1; + } + else + { + int clk_tck = sysconf (_SC_CLK_TCK); + + gettimeofday (&tv2, NULL); + + tv2.tv_sec -= tv.tv_sec; + tv2.tv_usec -= tv.tv_usec; + if (tv2.tv_usec < 0) + { + tv2.tv_usec += 1000000; + tv2.tv_sec -= 1; + } + + /* Be a bit tolerant, add one CLK_TCK. */ + tv2.tv_usec += 1000000 / clk_tck; + if (tv2.tv_usec >= 1000000) + { + tv2.tv_usec -= 1000000; + ++tv2.tv_sec; + } + + if (tv2.tv_sec < 2) + { + printf ("premature timeout: %ld.%06ld difference\n", + tv2.tv_sec, tv2.tv_usec); + return 1; + } + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + /* The following makes the ts value invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_mutex_timedlock (&m, &ts); + if (err == 0) + { + puts ("2nd timedlock succeeded"); + return 1; + } + else if (err != EINVAL) + { + printf ("2nd timedlock error != EINVAL: %d\n", err); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + if (pthread_mutex_timedlock (&m, &ts) != 0) + { + puts ("3rd timedlock failed"); + } + + (void) gettimeofday (&tv2, NULL); + + /* Check that timedlock didn't delay. We use a limit of 0.1 secs. */ + timersub (&tv2, &tv, &tv2); + if (tv2.tv_sec > 0 || tv2.tv_usec > 100000) + { + puts ("3rd timedlock didn't return right away"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("final mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + return 0; +} + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex5a.c b/test/nptl/tst-mutex5a.c new file mode 100644 index 000000000..f91eec0d7 --- /dev/null +++ b/test/nptl/tst-mutex5a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP +#include "tst-mutex5.c" diff --git a/test/nptl/tst-mutex6.c b/test/nptl/tst-mutex6.c new file mode 100644 index 000000000..f066c62ed --- /dev/null +++ b/test/nptl/tst-mutex6.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + pthread_mutex_t m; + + if (pthread_mutex_init (&m, NULL) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex7.c b/test/nptl/tst-mutex7.c new file mode 100644 index 000000000..a9b9f318c --- /dev/null +++ b/test/nptl/tst-mutex7.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <time.h> + + +#ifndef INIT +# define INIT PTHREAD_MUTEX_INITIALIZER +#endif + + +static pthread_mutex_t lock = INIT; + + +#define ROUNDS 1000 +#define N 100 + + +static void * +tf (void *arg) +{ + int nr = (long int) arg; + int cnt; + struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 }; + + for (cnt = 0; cnt < ROUNDS; ++cnt) + { + if (pthread_mutex_lock (&lock) != 0) + { + printf ("thread %d: failed to get the lock\n", nr); + return (void *) 1l; + } + + if (pthread_mutex_unlock (&lock) != 0) + { + printf ("thread %d: failed to release the lock\n", nr); + return (void *) 1l; + } + + nanosleep (&ts, NULL); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + pthread_t th[N]; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("locking in parent failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0) + { + printf ("creating thread %d failed\n", cnt); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("unlocking in parent failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + printf ("joining thread %d failed\n", cnt); + return 1; + } + + return 0; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex7a.c b/test/nptl/tst-mutex7a.c new file mode 100644 index 000000000..f08799ae7 --- /dev/null +++ b/test/nptl/tst-mutex7a.c @@ -0,0 +1,2 @@ +#define INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#include "tst-mutex7.c" diff --git a/test/nptl/tst-mutex8.c b/test/nptl/tst-mutex8.c new file mode 100644 index 000000000..80ebe71f0 --- /dev/null +++ b/test/nptl/tst-mutex8.c @@ -0,0 +1,367 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This test checks behavior not required by POSIX. */ +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t *m; +static pthread_barrier_t b; +static pthread_cond_t c; +static bool done; + + +static void +cl (void *arg) +{ + if (pthread_mutex_unlock (m) != 0) + { + puts ("cl: mutex_unlocked failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (m) != 0) + { + puts ("tf: mutex_lock failed"); + return (void *) 1l; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return (void *) 1l; + } + + if (arg == NULL) + do + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + while (! done); + else + do + { + pthread_cleanup_push (cl, NULL); + + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + + pthread_cleanup_pop (0); + } + while (! done); + + if (pthread_mutex_unlock (m) != 0) + { + puts ("tf: mutex_unlock failed"); + return (void *) 1l; + } + + return NULL; +} + + +static int +check_type (const char *mas, pthread_mutexattr_t *ma) +{ + if (pthread_mutex_init (m, ma) != 0) + { + printf ("1st mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("immediate mutex_destroy failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("2nd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("1st mutex_lock failed for %s\n", mas); + return 1; + } + + int e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("mutex_destroy of self-locked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("1st mutex_unlock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_trylock (m) != 0) + { + printf ("mutex_trylock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of self-trylocked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("2nd mutex_unlock failed for %s\n", mas); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + done = false; + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("2nd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("3rd mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of condvar-used mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas); + return 1; + } + + done = true; + if (pthread_cond_signal (&c) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != NULL) + { + puts ("thread didn't return NULL"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-use failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("3rd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_create (&th, NULL, tf, (void *) 1) != 0) + { + puts ("2nd create failed"); + return 1; + } + done = false; + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("3rd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("4th mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n", + mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", + mas); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cond_cancel failed"); + return 1; + } + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-canceled failed for %s\n", mas); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + pthread_mutex_t mm; + m = &mm; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_cond_init (&c, NULL) != 0) + { + puts ("cond_init failed"); + return 1; + } + + puts ("check normal mutex"); + int res = check_type ("normal", NULL); + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("1st mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("1st mutexattr_settype failed"); + return 1; + } + puts ("check recursive mutex"); + res |= check_type ("recursive", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("1st mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("2nd mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("2nd mutexattr_settype failed"); + return 1; + } + puts ("check error-checking mutex"); + res |= check_type ("error-checking", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("2nd mutexattr_destroy failed"); + return 1; + } + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex9.c b/test/nptl/tst-mutex9.c new file mode 100644 index 000000000..3748584b1 --- /dev/null +++ b/test/nptl/tst-mutex9.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/time.h> + +int gettimeofday(struct timeval *tv, struct timezone *tz); + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-mutex9.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t a; + pid_t pid; + char *p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + p = (char *) (m + 1); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_trylock (m) == 0) + { + puts ("child: mutex_trylock succeeded"); + exit (1); + } + + if (pthread_mutex_unlock (m) == 0) + { + puts ("child: mutex_unlock succeeded"); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + + int e = pthread_mutex_timedlock (m, &ts); + if (e == 0) + { + puts ("child: mutex_timedlock succeeded"); + exit (1); + } + if (e != ETIMEDOUT) + { + puts ("child: mutex_timedlock didn't time out"); + exit (1); + } + + alarm (1); + + pthread_mutex_lock (m); + + puts ("child: mutex_lock returned"); + + exit (0); + } + + sleep (2); + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + if (! WIFSIGNALED (status)) + { + puts ("child not killed by signal"); + return 1; + } + if (WTERMSIG (status) != SIGALRM) + { + puts ("child not killed by SIGALRM"); + return 1; + } + + return 0; +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once1.c b/test/nptl/tst-once1.c new file mode 100644 index 000000000..87ed51c82 --- /dev/null +++ b/test/nptl/tst-once1.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> + + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int global; + +static void +once_handler (void) +{ + ++global; +} + + +static int +do_test (void) +{ + pthread_once (&once, once_handler); + pthread_once (&once, once_handler); + + if (global != 1) + { + printf ("global = %d, expected 1\n", global); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once2.c b/test/nptl/tst-once2.c new file mode 100644 index 000000000..c60634538 --- /dev/null +++ b/test/nptl/tst-once2.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +#define N 100 + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int global; + +static void +once_handler (void) +{ + struct timespec ts; + + ++global; + + ts.tv_sec = 2; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); +} + + +static void * +tf (void *arg) +{ + pthread_once (&once, once_handler); + + if (global != 1) + { + printf ("thread %ld: global == %d\n", (long int) arg, global); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + pthread_t th[N]; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0) + { + printf ("creation of thread %d failed\n", cnt); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + printf ("join of thread %d failed\n", cnt); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once3.c b/test/nptl/tst-once3.c new file mode 100644 index 000000000..43b354a39 --- /dev/null +++ b/test/nptl/tst-once3.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +#define N 100 + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +static pthread_barrier_t bar; + +static int global; +static int cl_called; + +static void +once_handler1 (void) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("once_handler1: mutex_lock failed"); + exit (1); + } + puts ("once_handler1: locked"); + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler1: barrier_wait failed"); + exit (1); + } + + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ + exit (42); +} + +static void +once_handler2 (void) +{ + global = 1; +} + + +static void +cl (void *arg) +{ + cl_called = 1; +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cl, NULL) + + pthread_once (&once, once_handler1); + + pthread_cleanup_pop (0); + + /* We should never get here. */ + puts ("pthread_once in tf returned"); + exit (1); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("first create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + /* We unlock the mutex so that we catch the case where the pthread_cond_wait + call incorrectly resumes and tries to get the mutex. */ + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + /* Cancel the thread. */ + puts ("going to cancel"); + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + pthread_join (th, &result); + if (result != PTHREAD_CANCELED) + { + puts ("join didn't return PTHREAD_CANCELED"); + return 1; + } + + if (cl_called != 1) + { + puts ("cleanup handler not called"); + return 1; + } + + pthread_once (&once, once_handler2); + + if (global != 1) + { + puts ("global still 0"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once4.c b/test/nptl/tst-once4.c new file mode 100644 index 000000000..35bae3c0e --- /dev/null +++ b/test/nptl/tst-once4.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +static pthread_barrier_t bar; + +static int global; +static int cl_called; + +static void +once_handler1 (void) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("once_handler1: mutex_lock failed"); + exit (1); + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler1: barrier_wait failed"); + exit (1); + } + + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ +} + + +static void +once_handler2 (void) +{ + global = 1; +} + + +static void +cl (void *arg) +{ + ++cl_called; +} + + +static void * +tf1 (void *arg) +{ + pthread_cleanup_push (cl, NULL); + + pthread_once (&once, once_handler1); + + pthread_cleanup_pop (0); + + /* We should never get here. */ + puts ("pthread_once in tf returned"); + exit (1); +} + + +static void * +tf2 (void *arg) +{ + pthread_cleanup_push (cl, NULL); + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler2: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_pop (0); + + pthread_once (&once, once_handler2); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th[2]; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th[0], NULL, tf1, NULL) != 0) + { + puts ("first create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("first barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + /* We unlock the mutex so that we catch the case where the pthread_cond_wait + call incorrectly resumes and tries to get the mutex. */ + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_create (&th[1], NULL, tf2, NULL) != 0) + { + puts ("second create failed"); + return 1; + } + + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("second barrier_wait failed"); + return 1; + } + + /* Give the second thread a chance to reach the pthread_once call. */ + sleep (2); + + /* Cancel the thread. */ + if (pthread_cancel (th[0]) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + pthread_join (th[0], &result); + if (result != PTHREAD_CANCELED) + { + puts ("first join didn't return PTHREAD_CANCELED"); + return 1; + } + + puts ("joined first thread"); + + pthread_join (th[1], &result); + if (result != NULL) + { + puts ("second join didn't return PTHREAD_CANCELED"); + return 1; + } + + if (global != 1) + { + puts ("global still 0"); + return 1; + } + + if (cl_called != 1) + { + printf ("cl_called = %d\n", cl_called); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-popen1.c b/test/nptl/tst-popen1.c new file mode 100644 index 000000000..a9d077371 --- /dev/null +++ b/test/nptl/tst-popen1.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +dummy (void *x) +{ + return NULL; +} + +static char buf[sizeof "something\n"]; + +static int +do_test (void) +{ + FILE *f; + pthread_t p; + int err; + + f = popen ("echo something", "r"); + if (f == NULL) + error (EXIT_FAILURE, errno, "popen failed"); + if (fgets (buf, sizeof (buf), f) == NULL) + error (EXIT_FAILURE, 0, "fgets failed"); + if (strcmp (buf, "something\n")) + error (EXIT_FAILURE, 0, "read wrong data"); + if (pclose (f)) + error (EXIT_FAILURE, errno, "pclose returned non-zero"); + if ((err = pthread_create (&p, NULL, dummy, NULL))) + error (EXIT_FAILURE, err, "pthread_create failed"); + if ((err = pthread_join (p, NULL))) + error (EXIT_FAILURE, err, "pthread_join failed"); + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-raise1.c b/test/nptl/tst-raise1.c new file mode 100644 index 000000000..5ea9886a4 --- /dev/null +++ b/test/nptl/tst-raise1.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <error.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> + +volatile int count; + +void +sh (int sig) +{ + ++count; +} + +int +main (void) +{ + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (SIGUSR1, &sa, NULL) < 0) + { + printf ("sigaction failed: %m\n"); + exit (1); + } + if (raise (SIGUSR1) < 0) + { + printf ("first raise failed: %m\n"); + exit (1); + } + if (raise (SIGUSR1) < 0) + { + printf ("second raise failed: %m\n"); + exit (1); + } + if (count != 2) + { + printf ("signal handler not called 2 times\n"); + exit (1); + } + exit (0); +} diff --git a/test/nptl/tst-rwlock1.c b/test/nptl/tst-rwlock1.c new file mode 100644 index 000000000..c97e0e60f --- /dev/null +++ b/test/nptl/tst-rwlock1.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("1st rwlock_rdlock failed"); + return 1; + } + puts ("1st rwlock_rdlock succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("2nd rwlock_rdlock failed"); + return 1; + } + puts ("2nd rwlock_rdlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("1st rwlock_unlock failed"); + return 1; + } + puts ("1st rwlock_unlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("2nd rwlock_unlock failed"); + return 1; + } + puts ("2nd rwlock_unlock succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("1st rwlock_wrlock failed"); + return 1; + } + puts ("1st rwlock_wrlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("3rd rwlock_unlock failed"); + return 1; + } + puts ("3rd rwlock_unlock succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("2nd rwlock_wrlock failed"); + return 1; + } + puts ("2nd rwlock_wrlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("4th rwlock_unlock failed"); + return 1; + } + puts ("4th rwlock_unlock succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("3rd rwlock_rdlock failed"); + return 1; + } + puts ("3rd rwlock_rdlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("5th rwlock_unlock failed"); + return 1; + } + puts ("5th rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock10.c b/test/nptl/tst-rwlock10.c new file mode 100644 index 000000000..43156eae6 --- /dev/null +++ b/test/nptl/tst-rwlock10.c @@ -0,0 +1,21 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock8.c" diff --git a/test/nptl/tst-rwlock11.c b/test/nptl/tst-rwlock11.c new file mode 100644 index 000000000..ed9af7edc --- /dev/null +++ b/test/nptl/tst-rwlock11.c @@ -0,0 +1,21 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock9.c" diff --git a/test/nptl/tst-rwlock12.c b/test/nptl/tst-rwlock12.c new file mode 100644 index 000000000..91f25d3b1 --- /dev/null +++ b/test/nptl/tst-rwlock12.c @@ -0,0 +1,208 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-rwlock12.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t ma; + pthread_rwlock_t *r; + pthread_rwlockattr_t ra; + pid_t pid; + int status = 0; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t)) + & ~(__alignof (pthread_rwlock_t) - 1)); + /* The following assumes alignment for a mutex is at least as high + as that for a rwlock. Which is true in our case. */ + m = (pthread_mutex_t *) (r + 1); + + if (pthread_rwlockattr_init (&ra) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_rwlockattr_setpshared (&ra, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("rwlockattr_setpshared failed"); + return 1; + } + + if (pthread_rwlock_init (r, &ra) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutex_init (m, &ma) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + /* Lock the mutex. */ + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Lock the mutex. */ + if (pthread_mutex_lock (m) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + /* Try to get the rwlock. */ + if (pthread_rwlock_trywrlock (r) == 0) + { + puts ("rwlock_trywrlock succeeded"); + return 1; + } + + /* Try again. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000000 }; + int e = pthread_rwlock_timedwrlock (r, &ts); + if (e == 0) + { + puts ("rwlock_timedwrlock succeeded"); + return 1; + } + if (e != ETIMEDOUT) + { + puts ("rwlock_timedwrlock didn't return ETIMEDOUT"); + status = 1; + } + + if (pthread_rwlock_tryrdlock (r) == 0) + { + puts ("rwlock_tryrdlock succeeded"); + return 1; + } + + e = pthread_rwlock_timedrdlock (r, &ts); + if (e == 0) + { + puts ("rwlock_timedrdlock succeeded"); + return 1; + } + if (e != ETIMEDOUT) + { + puts ("rwlock_timedrdlock didn't return ETIMEDOUT"); + status = 1; + } + } + else + { + /* Lock the rwlock for writing. */ + if (pthread_rwlock_wrlock (r) != 0) + { + puts ("rwlock_wrlock failed"); + kill (pid, SIGTERM); + return 1; + } + + /* Allow the child to run. */ + if (pthread_mutex_unlock (m) != 0) + { + puts ("mutex_unlock failed"); + kill (pid, SIGTERM); + return 1; + } + + /* Just wait for the child. */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGTERM); + return 1; + } + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock13.c b/test/nptl/tst-rwlock13.c new file mode 100644 index 000000000..61d5b83e1 --- /dev/null +++ b/test/nptl/tst-rwlock13.c @@ -0,0 +1,71 @@ +/* Copyright (C) 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int ret; + + memset (&r, 0xaa, sizeof (r)); + if ((ret = pthread_rwlock_init (&r, NULL)) != 0) + { + printf ("rwlock_init failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_rdlock (&r)) != 0) + { + printf ("rwlock_rdlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_unlock (&r)) != 0) + { + printf ("rwlock_unlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_wrlock (&r)) != 0) + { + printf ("rwlock_wrlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_unlock (&r)) != 0) + { + printf ("second rwlock_unlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_destroy (&r)) != 0) + { + printf ("second rwlock_destroy failed: %d\n", ret); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock14.c b/test/nptl/tst-rwlock14.c new file mode 100644 index 000000000..fc0d3d219 --- /dev/null +++ b/test/nptl/tst-rwlock14.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +static pthread_barrier_t b; +static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER; + + +static void * +tf (void *arg) +{ + /* Lock the read-write lock. */ + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("tf: cannot lock rwlock"); + exit (EXIT_FAILURE); + } + + pthread_t mt = *(pthread_t *) arg; + + pthread_barrier_wait (&b); + + /* This call will never return. */ + pthread_join (mt, NULL); + + return NULL; +} + + +static int +do_test (void) +{ + int result = 0; + struct timespec ts; + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t me = pthread_self (); + pthread_t th; + if (pthread_create (&th, NULL, tf, &me) != 0) + { + puts ("create failed"); + return 1; + } + + /* Wait until the rwlock is locked. */ + pthread_barrier_wait (&b); + + ts.tv_nsec = -1; + + int e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("first rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { + puts ("first rwlock_timedwrlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first rwlock_timedwrlock did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 1000000000; + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("second rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("second rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 0x100001000LL; + if (ts.tv_nsec != 0x100001000LL) + ts.tv_nsec = 2000000000; + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("third rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("third rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("third rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("third rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + if (result == 0) + puts ("no bugs"); + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock2.c b/test/nptl/tst-rwlock2.c new file mode 100644 index 000000000..6f38682b8 --- /dev/null +++ b/test/nptl/tst-rwlock2.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int e; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("1st rwlock_wrlock failed"); + return 1; + } + puts ("1st rwlock_wrlock succeeded"); + + e = pthread_rwlock_tryrdlock (&r); + if (e == 0) + { + puts ("rwlock_tryrdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY"); + + e = pthread_rwlock_trywrlock (&r); + if (e == 0) + { + puts ("rwlock_trywrlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_trywrlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_trywrlock on rwlock with writer failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("1st rwlock_unlock failed"); + return 1; + } + puts ("1st rwlock_unlock succeeded"); + + if (pthread_rwlock_tryrdlock (&r) != 0) + { + puts ("rwlock_tryrdlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_tryrdlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_trywrlock (&r); + if (e == 0) + { + puts ("rwlock_trywrlock on rwlock with reader succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_trywrlock on rwlock with reader return value != EBUSY"); + return 1; + } + puts ("rwlock_trywrlock on rwlock with reader failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("2nd rwlock_unlock failed"); + return 1; + } + puts ("2nd rwlock_unlock succeeded"); + + if (pthread_rwlock_trywrlock (&r) != 0) + { + puts ("rwlock_trywrlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_trywrlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_tryrdlock (&r); + if (e == 0) + { + puts ("rwlock_tryrdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("3rd rwlock_unlock failed"); + return 1; + } + puts ("3rd rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock3.c b/test/nptl/tst-rwlock3.c new file mode 100644 index 000000000..c1cac876d --- /dev/null +++ b/test/nptl/tst-rwlock3.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This test case checks more than standard compliance. An + implementation may provide this service but it is not required to + do so. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int e; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_trywrlock (&r) != 0) + { + puts ("rwlock_trywrlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_trywrlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_rdlock (&r); + if (e == 0) + { + puts ("rwlock_rdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EDEADLK) + { + puts ("rwlock_rdlock on rwlock with writer failed != EDEADLK"); + return 1; + } + puts ("rwlock_rdlock on rwlock with writer failed with EDEADLK"); + + e = pthread_rwlock_wrlock (&r); + if (e == 0) + { + puts ("rwlock_wrlock on rwlock with writer succeeded"); + return 1; + } + if (e != EDEADLK) + { + puts ("rwlock_wrlock on rwlock with writer failed != EDEADLK"); + return 1; + } + puts ("rwlock_wrlock on rwlock with writer failed with EDEADLK"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("rwlock_unlock failed"); + return 1; + } + puts ("rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock4.c b/test/nptl/tst-rwlock4.c new file mode 100644 index 000000000..8de0121b3 --- /dev/null +++ b/test/nptl/tst-rwlock4.c @@ -0,0 +1,190 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-rwlock4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_rwlock_t *r; + pthread_rwlockattr_t a; + pid_t pid; + char *p; + int err; + int s; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t)) + & ~(__alignof (pthread_rwlock_t) - 1)); + p = (char *) (r + 1); + + if (pthread_rwlockattr_init (&a) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_rwlockattr_getpshared (&a, &s) != 0) + { + puts ("1st rwlockattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("rwlockattr_setpshared failed"); + return 1; + } + + if (pthread_rwlockattr_getpshared (&a, &s) != 0) + { + puts ("2nd rwlockattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_rwlock_init (r, &a) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_rwlock_rdlock (r) != 0) + { + puts ("rwlock_rdlock failed"); + return 1; + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + puts ("rwlockattr_destroy failed"); + return 1; + } + + err = pthread_rwlock_trywrlock (r); + if (err == 0) + { + puts ("rwlock_trywrlock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("rwlock_trywrlock didn't return EBUSY"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_rwlock_unlock (r) != 0) + { + puts ("child: 1st rwlock_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_rwlock_wrlock (r) != 0) + { + puts ("parent: rwlock_wrlock failed"); + return 1; + } + + if (*p != 1) + { + puts ("*p != 1"); + return 1; + } + + puts ("parent done"); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock5.c b/test/nptl/tst-rwlock5.c new file mode 100644 index 000000000..a04eb2670 --- /dev/null +++ b/test/nptl/tst-rwlock5.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t r; + + +static void * +tf (void *arg) +{ + if (pthread_rwlock_wrlock (&r) == 0) + { + puts ("child: rwlock_wrlock succeeded"); + exit (1); + } + + puts ("child: rwlock_wrlock returned"); + + exit (1); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("rwlock_wrlock failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + /* This call should never return. */ + pthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock6.c b/test/nptl/tst-rwlock6.c new file mode 100644 index 000000000..3b525b9d5 --- /dev/null +++ b/test/nptl/tst-rwlock6.c @@ -0,0 +1,226 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + + +static int kind[] = + { + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + }; + + +static void * +tf (void *arg) +{ + pthread_rwlock_t *r = arg; + + /* Timeout: 0.3 secs. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 300000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + puts ("child calling timedrdlock"); + + int err = pthread_rwlock_timedrdlock (r, &ts); + if (err == 0) + { + puts ("rwlock_timedrdlock returned"); + pthread_exit ((void *) 1l); + } + + if (err != ETIMEDOUT) + { + printf ("err = %s (%d), expected %s (%d)\n", + strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT); + pthread_exit ((void *) 1l); + } + + puts ("1st child timedrdlock done"); + + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + timersub (&tv2, &tv, &tv); + + if (tv.tv_usec < 200000) + { + puts ("timeout too short"); + pthread_exit ((void *) 1l); + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10; + /* Note that the following operation makes ts invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_rwlock_timedrdlock (r, &ts); + if (err == 0) + { + puts ("2nd timedrdlock succeeded"); + pthread_exit ((void *) 1l); + } + if (err != EINVAL) + { + puts ("2nd timedrdlock did not return EINVAL"); + pthread_exit ((void *) 1l); + } + + puts ("2nd child timedrdlock done"); + + return NULL; +} + + +static int +do_test (void) +{ + size_t cnt; + for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) + { + pthread_rwlock_t r; + pthread_rwlockattr_t a; + + if (pthread_rwlockattr_init (&a) != 0) + { + printf ("round %Zu: rwlockattr_t failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0) + { + printf ("round %Zu: rwlockattr_setkind failed\n", cnt); + exit (1); + } + + if (pthread_rwlock_init (&r, &a) != 0) + { + printf ("round %Zu: rwlock_init failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + printf ("round %Zu: rwlockattr_destroy failed\n", cnt); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ++ts.tv_sec; + + /* Get a write lock. */ + int e = pthread_rwlock_timedwrlock (&r, &ts); + if (e != 0) + { + printf ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e); + exit (1); + } + + puts ("1st timedwrlock done"); + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ++ts.tv_sec; + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("timedrdlock succeeded"); + exit (1); + } + if (e != EDEADLK) + { + puts ("timedrdlock did not return EDEADLK"); + exit (1); + } + + puts ("1st timedrdlock done"); + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ++ts.tv_sec; + e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { + puts ("2nd timedwrlock succeeded"); + exit (1); + } + if (e != EDEADLK) + { + puts ("2nd timedwrlock did not return EDEADLK"); + exit (1); + } + + puts ("2nd timedwrlock done"); + + pthread_t th; + if (pthread_create (&th, NULL, tf, &r) != 0) + { + printf ("round %Zu: create failed\n", cnt); + exit (1); + } + + puts ("started thread"); + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("round %Zu: join failed\n", cnt); + exit (1); + } + if (status != NULL) + { + printf ("failure in round %Zu\n", cnt); + exit (1); + } + + puts ("joined thread"); + + if (pthread_rwlock_destroy (&r) != 0) + { + printf ("round %Zu: rwlock_destroy failed\n", cnt); + exit (1); + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock7.c b/test/nptl/tst-rwlock7.c new file mode 100644 index 000000000..1f34c0650 --- /dev/null +++ b/test/nptl/tst-rwlock7.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + + +static int kind[] = + { + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + }; + + +static void * +tf (void *arg) +{ + pthread_rwlock_t *r = arg; + + /* Timeout: 0.3 secs. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 300000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + int err = pthread_rwlock_timedwrlock (r, &ts); + if (err == 0) + { + puts ("rwlock_timedwrlock returned"); + pthread_exit ((void *) 1l); + } + + if (err != ETIMEDOUT) + { + printf ("err = %s (%d), expected %s (%d)\n", + strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT); + pthread_exit ((void *) 1l); + } + + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + timersub (&tv2, &tv, &tv); + + if (tv.tv_usec < 200000) + { + puts ("timeout too short"); + pthread_exit ((void *) 1l); + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10; + /* Note that the following operation makes ts invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_rwlock_timedwrlock (r, &ts); + if (err == 0) + { + puts ("2nd timedwrlock succeeded"); + pthread_exit ((void *) 1l); + } + if (err != EINVAL) + { + puts ("2nd timedwrlock did not return EINVAL"); + pthread_exit ((void *) 1l); + } + + return NULL; +} + + +static int +do_test (void) +{ + size_t cnt; + for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) + { + pthread_rwlock_t r; + pthread_rwlockattr_t a; + + if (pthread_rwlockattr_init (&a) != 0) + { + printf ("round %Zu: rwlockattr_t failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0) + { + printf ("round %Zu: rwlockattr_setkind failed\n", cnt); + exit (1); + } + + if (pthread_rwlock_init (&r, &a) != 0) + { + printf ("round %Zu: rwlock_init failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + printf ("round %Zu: rwlockattr_destroy failed\n", cnt); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ++ts.tv_sec; + + /* Get a read lock. */ + if (pthread_rwlock_timedrdlock (&r, &ts) != 0) + { + printf ("round %Zu: rwlock_timedrdlock failed\n", cnt); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &r) != 0) + { + printf ("round %Zu: create failed\n", cnt); + exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("round %Zu: join failed\n", cnt); + exit (1); + } + if (status != NULL) + { + printf ("failure in round %Zu\n", cnt); + exit (1); + } + + if (pthread_rwlock_destroy (&r) != 0) + { + printf ("round %Zu: rwlock_destroy failed\n", cnt); + exit (1); + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock8.c b/test/nptl/tst-rwlock8.c new file mode 100644 index 000000000..7eeaea885 --- /dev/null +++ b/test/nptl/tst-rwlock8.c @@ -0,0 +1,164 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#define NWRITERS 15 +#define WRITETRIES 10 +#define NREADERS 15 +#define READTRIES 15 + +#define DELAY 1000000 + +#ifndef INIT +# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#endif + +static pthread_rwlock_t lock = INIT; + + +static void * +writer_thread (void *nr) +{ + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < WRITETRIES; ++n) + { + printf ("writer thread %ld tries again\n", (long int) nr); + + if (pthread_rwlock_wrlock (&lock) != 0) + { + puts ("wrlock failed"); + exit (1); + } + + printf ("writer thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for writer failed"); + exit (1); + } + + printf ("writer thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static void * +reader_thread (void *nr) +{ + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < READTRIES; ++n) + { + printf ("reader thread %ld tries again\n", (long int) nr); + + if (pthread_rwlock_rdlock (&lock) != 0) + { + puts ("rdlock failed"); + exit (1); + } + + printf ("reader thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for reader failed"); + exit (1); + } + + printf ("reader thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t thwr[NWRITERS]; + pthread_t thrd[NREADERS]; + int n; + void *res; + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < NWRITERS; ++n) + if (pthread_create (&thwr[n], NULL, writer_thread, + (void *) (long int) n) != 0) + { + puts ("writer create failed"); + exit (1); + } + + for (n = 0; n < NREADERS; ++n) + if (pthread_create (&thrd[n], NULL, reader_thread, + (void *) (long int) n) != 0) + { + puts ("reader create failed"); + exit (1); + } + + /* Wait for all the threads. */ + for (n = 0; n < NWRITERS; ++n) + if (pthread_join (thwr[n], &res) != 0) + { + puts ("writer join failed"); + exit (1); + } + for (n = 0; n < NREADERS; ++n) + if (pthread_join (thrd[n], &res) != 0) + { + puts ("reader join failed"); + exit (1); + } + + return 0; +} + +#define TIMEOUT 30 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock9.c b/test/nptl/tst-rwlock9.c new file mode 100644 index 000000000..a5522ce48 --- /dev/null +++ b/test/nptl/tst-rwlock9.c @@ -0,0 +1,203 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +#define NWRITERS 15 +#define WRITETRIES 10 +#define NREADERS 15 +#define READTRIES 15 + +#define TIMEOUT 1000000 +#define DELAY 1000000 + +#ifndef INIT +# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#endif + +static pthread_rwlock_t lock = INIT; + + +static void * +writer_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < WRITETRIES; ++n) + { + int e; + do + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_nsec += 2 * TIMEOUT; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + printf ("writer thread %ld tries again\n", (long int) nr); + + e = pthread_rwlock_timedwrlock (&lock, &ts); + if (e != 0 && e != ETIMEDOUT) + { + puts ("timedwrlock failed"); + exit (1); + } + } + while (e == ETIMEDOUT); + + printf ("writer thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for writer failed"); + exit (1); + } + + printf ("writer thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static void * +reader_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < READTRIES; ++n) + { + int e; + do + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_nsec += TIMEOUT; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + printf ("reader thread %ld tries again\n", (long int) nr); + + e = pthread_rwlock_timedrdlock (&lock, &ts); + if (e != 0 && e != ETIMEDOUT) + { + puts ("timedrdlock failed"); + exit (1); + } + } + while (e == ETIMEDOUT); + + printf ("reader thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for reader failed"); + exit (1); + } + + printf ("reader thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t thwr[NWRITERS]; + pthread_t thrd[NREADERS]; + int n; + void *res; + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < NWRITERS; ++n) + if (pthread_create (&thwr[n], NULL, writer_thread, + (void *) (long int) n) != 0) + { + puts ("writer create failed"); + exit (1); + } + + for (n = 0; n < NREADERS; ++n) + if (pthread_create (&thrd[n], NULL, reader_thread, + (void *) (long int) n) != 0) + { + puts ("reader create failed"); + exit (1); + } + + /* Wait for all the threads. */ + for (n = 0; n < NWRITERS; ++n) + if (pthread_join (thwr[n], &res) != 0) + { + puts ("writer join failed"); + exit (1); + } + for (n = 0; n < NREADERS; ++n) + if (pthread_join (thrd[n], &res) != 0) + { + puts ("reader join failed"); + exit (1); + } + + return 0; +} + +#undef TIMEOUT +#define TIMEOUT 30 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sched1.c b/test/nptl/tst-sched1.c new file mode 100644 index 000000000..4d0702c79 --- /dev/null +++ b/test/nptl/tst-sched1.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> + + +static int global; + +static void * +tf (void *a) +{ + global = 1; + + return 0; +} + + +int +do_test (void) +{ + pthread_t th; + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setschedpolicy (&at, SCHED_OTHER) != 0) + { + puts ("attr_setschedpolicy failed"); + return 1; + } + + struct sched_param pa; + if (sched_getparam (getpid (), &pa) != 0) + { + puts ("sched_getschedparam failed"); + return 1; + } + + if (pthread_attr_setschedparam (&at, &pa) != 0) + { + puts ("attr_setschedparam failed"); + return 1; + } + + if (pthread_attr_setinheritsched (&at, PTHREAD_EXPLICIT_SCHED) != 0) + { + puts ("attr_setinheritsched failed"); + return 1; + } + + if (pthread_create (&th, &at, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int e = pthread_join (th, NULL); + if (e != 0) + { + printf ("join failed: %d\n", e); + return 1; + } + + if (global == 0) + { + puts ("thread didn't run"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem1.c b/test/nptl/tst-sem1.c new file mode 100644 index 000000000..32d59eb36 --- /dev/null +++ b/test/nptl/tst-sem1.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + sem_t s; + + if (sem_init (&s, 0, 1) == -1) + { + puts ("init failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("1st wait failed"); + return 1; + } + + if (sem_post (&s) == -1) + { + puts ("1st post failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_trywait (&s)) == -1) + { + puts ("1st trywait failed"); + return 1; + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_trywait (&s)) != -1) + { + puts ("2nd trywait succeeded"); + return 1; + } + else if (errno != EAGAIN) + { + puts ("2nd trywait did not set errno to EAGAIN"); + return 1; + } + + if (sem_post (&s) == -1) + { + puts ("2nd post failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("2nd wait failed"); + return 1; + } + + if (sem_destroy (&s) == -1) + { + puts ("destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem2.c b/test/nptl/tst-sem2.c new file mode 100644 index 000000000..026939ef9 --- /dev/null +++ b/test/nptl/tst-sem2.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + sem_t s; + + if (sem_init (&s, 0, 0) == -1) + { + puts ("init failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("wait failed"); + return 1; + } + + /* We should never get here. */ + puts ("wait succeeded"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem3.c b/test/nptl/tst-sem3.c new file mode 100644 index 000000000..91b9f0877 --- /dev/null +++ b/test/nptl/tst-sem3.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +int +main (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-sem3.XXXXXX"; + char data[ps]; + void *mem; + int fd; + sem_t *s; + pid_t pid; + char *p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + exit (1); + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + exit (1); + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + exit (1); + } + + s = (sem_t *) (((uintptr_t) mem + __alignof (sem_t)) + & ~(__alignof (sem_t) - 1)); + p = (char *) (s + 1); + + if (sem_init (s, 1, 1) == -1) + { + puts ("init failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("1st wait failed"); + exit (1); + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_trywait (s)) != -1) + { + puts ("trywait succeeded"); + exit (1); + } + else if (errno != EAGAIN) + { + puts ("trywait didn't return EAGAIN"); + exit (1); + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + exit (1); + } + + if (sem_post (s) == -1) + { + puts ("child: 1st post failed"); + exit (1); + } + + puts ("child done"); + } + else + { + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + printf ("parent: 2nd wait failed: %m\n"); + exit (1); + } + + if (*p != 1) + { + puts ("*p != 1"); + exit (1); + } + + puts ("parent done"); + } + + exit (0); +} diff --git a/test/nptl/tst-sem4.c b/test/nptl/tst-sem4.c new file mode 100644 index 000000000..ccffbdd77 --- /dev/null +++ b/test/nptl/tst-sem4.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + sem_t *s2; + pid_t pid; + int val; + + s = sem_open ("/glibc-tst-sem4", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + on_exit (remove_sem, (void *) "/glibc-tst-sem4"); + + /* We have the semaphore object. Now try again with O_EXCL, this + should fail. */ + s2 = sem_open ("/glibc-tst-sem4", O_CREAT | O_EXCL, 0600, 1); + if (s2 != SEM_FAILED) + { + puts ("2nd sem_open didn't fail"); + return 1; + } + if (errno != EEXIST) + { + puts ("2nd sem_open returned wrong error"); + return 1; + } + + /* Check the value. */ + if (sem_getvalue (s, &val) == -1) + { + puts ("getvalue failed"); + return 1; + } + if (val != 1) + { + printf ("initial value wrong: got %d, expected 1\n", val); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("1st sem_wait failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid == 0) + { + /* Child. */ + + /* Check the value. */ + if (sem_getvalue (s, &val) == -1) + { + puts ("child: getvalue failed"); + return 1; + } + if (val != 0) + { + printf ("child: value wrong: got %d, expect 0\n", val); + return 1; + } + + if (sem_post (s) == -1) + { + puts ("child: post failed"); + return 1; + } + } + else + { + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("2nd sem_wait failed"); + return 1; + } + + if (sem_getvalue (s, &val) == -1) + { + puts ("parent: 2nd getvalue failed"); + return 1; + } + if (val != 0) + { + printf ("parent: value wrong: got %d, expected 0\n", val); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-sem5.c b/test/nptl/tst-sem5.c new file mode 100644 index 000000000..cb85b8e76 --- /dev/null +++ b/test/nptl/tst-sem5.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +static int +do_test (void) +{ + sem_t s; + struct timespec ts; + struct timeval tv; + + if (sem_init (&s, 0, 1) == -1) + { + puts ("sem_init failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("sem_wait failed"); + return 1; + } + + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + return 1; + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* We wait for half a second. */ + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1) + { + puts ("sem_timedwait succeeded"); + return 1; + } + if (errno != ETIMEDOUT) + { + printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n", + errno); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem6.c b/test/nptl/tst-sem6.c new file mode 100644 index 000000000..49240d962 --- /dev/null +++ b/test/nptl/tst-sem6.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static void +handler (int sig) +{ + struct sigaction sa; + + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGALRM, &sa, NULL); + + /* Rearm the timer. */ + alarm (1); +} + + +static int +do_test (void) +{ + sem_t s; + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGALRM, &sa, NULL); + + if (sem_init (&s, 0, 0) == -1) + { + puts ("init failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + int res = sem_wait (&s); + if (res == 0) + { + puts ("wait succeeded"); + return 1; + } + if (res != -1 || errno != EINTR) + { + puts ("wait didn't fail with EINTR"); + return 1; + } + + return 0; +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem7.c b/test/nptl/tst-sem7.c new file mode 100644 index 000000000..a85c73e71 --- /dev/null +++ b/test/nptl/tst-sem7.c @@ -0,0 +1,109 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + sem_t *s2; + sem_t *s3; + + s = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + on_exit (remove_sem, (void *) "/glibc-tst-sem7"); + + /* We have the semaphore object. Now try again. We should get the + same address. */ + s2 = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1); + if (s2 == SEM_FAILED) + { + puts ("2nd sem_open failed"); + return 1; + } + if (s != s2) + { + puts ("2nd sem_open didn't return the same address"); + return 1; + } + + /* And again, this time without O_CREAT. */ + s3 = sem_open ("/glibc-tst-sem7", 0); + if (s3 == SEM_FAILED) + { + puts ("3rd sem_open failed"); + return 1; + } + if (s != s3) + { + puts ("3rd sem_open didn't return the same address"); + return 1; + } + + /* Now close the handle. Three times. */ + if (sem_close (s2) != 0) + { + puts ("1st sem_close failed"); + return 1; + } + if (sem_close (s) != 0) + { + puts ("2nd sem_close failed"); + return 1; + } + if (sem_close (s3) != 0) + { + puts ("3rd sem_close failed"); + return 1; + } + + return 0; +} diff --git a/test/nptl/tst-sem8.c b/test/nptl/tst-sem8.c new file mode 100644 index 000000000..5dea575e9 --- /dev/null +++ b/test/nptl/tst-sem8.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + int i; + + on_exit (remove_sem, (void *) "/glibc-tst-sem8"); + + for (i = 0; i < 3; ++i) + { + s = sem_open ("/glibc-tst-sem8", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + /* Now close the handle. */ + if (sem_close (s) != 0) + { + puts ("sem_close failed"); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-sem9.c b/test/nptl/tst-sem9.c new file mode 100644 index 000000000..cdd8eaa30 --- /dev/null +++ b/test/nptl/tst-sem9.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + int i; + + on_exit (remove_sem, (void *) "/glibc-tst-sem9"); + + for (i = 0; i < 3; ++i) + { + s = sem_open ("/glibc-tst-sem9", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + /* Now close the handle. */ + if (sem_close (s) != 0) + { + puts ("sem_close failed"); + return 1; + } + + /* And remove it. */ + if (sem_unlink ("/glibc-tst-sem9") != 0) + { + puts ("sem_unlink failed"); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-signal1.c b/test/nptl/tst-signal1.c new file mode 100644 index 000000000..3022f1846 --- /dev/null +++ b/test/nptl/tst-signal1.c @@ -0,0 +1,189 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static sigset_t ss; +static pthread_barrier_t *b; + + +static void * +tf (void *arg) +{ + sigdelset (&ss, SIGINT); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("2nd pthread_sigmask failed"); + exit (1); + } + + pthread_barrier_wait (b); + + int sig; + int res = sigwait (&ss, &sig); + if (res == 0) + { + printf ("sigwait returned successfully with signal %d\n", sig); + exit (1); + } + + printf ("sigwait returned with %s (%d)\n", strerror (res), res); + + return NULL; +} + + +static void +receiver (void) +{ + pthread_t th; + + /* Make sure the process doesn't run forever. */ + alarm (10); + + sigfillset (&ss); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + if (pthread_join (th, NULL) == 0) + { + puts ("thread joined?!"); + exit (1); + } + + _exit (0); +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-signal1-XXXXXX"; + + int fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + exit (1); + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + exit (1); + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + exit (1); + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + receiver (); + + pthread_barrier_wait (b); + + /* Wait a bit more. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + + /* Send the signal. */ + puts ("sending the signal now"); + kill (pid, SIGINT); + + /* Wait for the process to terminate. */ + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("wrong child reported terminated"); + exit (1); + } + + if (!WIFSIGNALED (status)) + { + puts ("child wasn't signalled"); + exit (1); + } + + if (WTERMSIG (status) != SIGINT) + { + puts ("child not terminated with SIGINT"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal2.c b/test/nptl/tst-signal2.c new file mode 100644 index 000000000..3f2c75d1f --- /dev/null +++ b/test/nptl/tst-signal2.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <string.h> + + +static sigset_t ss; +static pthread_barrier_t *b; + + +static void * +tf (void *arg) +{ + pthread_barrier_wait (b); + + puts ("child: calling sigwait now"); + + int sig; + int err; + err = sigwait (&ss, &sig); + if (err != 0) + { + printf ("sigwait returned unsuccessfully: %s (%d)\n", + strerror (err), err); + _exit (1); + } + + puts ("sigwait returned"); + + if (sig != SIGINT) + { + printf ("caught signal %d, expected %d (SIGINT)\n", sig, SIGINT); + _exit (1); + } + + puts ("child thread terminating now"); + + return NULL; +} + + +static void +receiver (void) +{ + pthread_t th; + + /* Make sure the process doesn't run forever. */ + alarm (10); + + sigfillset (&ss); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + _exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("thread didn't join"); + _exit (1); + } + + puts ("join succeeded"); + + _exit (0); +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-signal1-XXXXXX"; + + int fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + exit (1); + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + exit (1); + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + exit (1); + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + receiver (); + + pthread_barrier_wait (b); + + /* Wait a bit more. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + + /* Send the signal. */ + puts ("sending the signal now"); + kill (pid, SIGINT); + + /* Wait for the process to terminate. */ + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("wrong child reported terminated"); + exit (1); + } + + if (!WIFEXITED (status)) + { + if (WIFSIGNALED (status)) + printf ("child exited with signal %d\n", WTERMSIG (status)); + else + puts ("child didn't exit normally"); + exit (1); + } + + if (WEXITSTATUS (status) != 0) + { + printf ("exit status %d != 0\n", WEXITSTATUS (status)); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal3.c b/test/nptl/tst-signal3.c new file mode 100644 index 000000000..e4756c56a --- /dev/null +++ b/test/nptl/tst-signal3.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +/* Number of different signalss to use. Also is the number of + threads. */ +#define N 10 +/* Maximum number of threads in flight at any one time. */ +#define INFLIGHT 5 +/* Number of signals sent in total. */ +#define ROUNDS 10000 + + +static int received[N][N]; +static int nsig[N]; +static pthread_t th[N]; +static sem_t sem; +static pthread_mutex_t lock[N]; +static pthread_t th_main; +static int sig0; + +static void +handler (int sig) +{ + int i; + for (i = 0; i < N; ++i) + if (pthread_equal (pthread_self (), th[i])) + break; + + if (i == N) + { + if (pthread_equal (pthread_self (), th_main)) + puts ("signal received by main thread"); + else + printf ("signal received by unknown thread (%lx)\n", + (unsigned long int) pthread_self ()); + exit (1); + } + + ++received[i][sig - sig0]; + + sem_post (&sem); +} + + +static void * +tf (void *arg) +{ + int idx = (long int) arg; + + sigset_t ss; + sigemptyset (&ss); + + int i; + for (i = 0; i <= idx; ++i) + sigaddset (&ss, sig0 + i); + + if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0) + { + printf ("thread %d: pthread_sigmask failed\n", i); + exit (1); + } + + pthread_mutex_lock (&lock[idx]); + + return NULL; +} + + +static int +do_test (void) +{ + /* Block all signals. */ + sigset_t ss; + sigfillset (&ss); + + th_main = pthread_self (); + + sig0 = SIGRTMIN; + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + exit (1); + } + + /* Install the handler. */ + int i; + for (i = 0; i < N; ++i) + { + struct sigaction sa = + { + .sa_handler = handler, + .sa_flags = 0 + }; + sigfillset (&sa.sa_mask); + + if (sigaction (sig0 + i, &sa, NULL) != 0) + { + printf ("sigaction for signal %d failed\n", i); + exit (1); + } + } + + if (sem_init (&sem, 0, INFLIGHT) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + if (pthread_mutex_init (&lock[i], NULL) != 0) + { + printf ("mutex_init[%d] failed\n", i); + } + + if (pthread_mutex_lock (&lock[i]) != 0) + { + printf ("mutex_lock[%d] failed\n", i); + } + + if (pthread_create (&th[i], &a, tf, (void *) (long int) i) != 0) + { + printf ("create of thread %d failed\n", i); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + int result = 0; + unsigned int r = 42; + pid_t pid = getpid (); + + for (i = 0; i < ROUNDS; ++i) + { + if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0) + { + printf ("sem_wait round %d failed: %m\n", i); + exit (1); + } + + int s = rand_r (&r) % N; + + kill (pid, sig0 + s); + } + + void *status; + for (i = 0; i < N; ++i) + { + if (pthread_mutex_unlock (&lock[i]) != 0) + { + printf ("unlock %d failed\n", i); + exit (1); + } + + if (pthread_join (th[i], &status) != 0) + { + printf ("join %d failed\n", i); + result = 1; + } + else if (status != NULL) + { + printf ("%d: result != NULL\n", i); + result = 1; + } + } + + int total = 0; + for (i = 0; i < N; ++i) + { + int j; + + for (j = 0; j <= i; ++j) + total += received[i][j]; + + for (j = i + 1; j < N; ++j) + if (received[i][j] != 0) + { + printf ("thread %d received signal SIGRTMIN+%d\n", i, j); + result = 1; + } + } + + if (total != ROUNDS) + { + printf ("total number of handled signals is %d, expected %d\n", + total, ROUNDS); + result = 1; + } + + printf ("A total of %d signals sent and received\n", total); + for (i = 0; i < N; ++i) + { + printf ("thread %2d:", i); + + int j; + for (j = 0; j <= i; ++j) + { + printf (" %5d", received[i][j]); + nsig[j] += received[i][j]; + } + + putchar ('\n'); + + } + + printf ("\nTotal :"); + for (i = 0; i < N; ++i) + printf (" %5d", nsig[i]); + putchar ('\n'); + + return result; +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal4.c b/test/nptl/tst-signal4.c new file mode 100644 index 000000000..dcb2893a0 --- /dev/null +++ b/test/nptl/tst-signal4.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + sigset_t ss; + + sigemptyset (&ss); + + int i; + for (i = 0; i < 10000; ++i) + { + long int r = random (); + + if (r != SIG_BLOCK && r != SIG_SETMASK && r != SIG_UNBLOCK) + { + int e = pthread_sigmask (r, &ss, NULL); + + if (e == 0) + { + printf ("pthread_sigmask succeeded for how = %ld\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("pthread_sigmask didn't return EINVAL"); + exit (1); + } + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal5.c b/test/nptl/tst-signal5.c new file mode 100644 index 000000000..cea6ec143 --- /dev/null +++ b/test/nptl/tst-signal5.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static sigset_t ss; + + +static void * +tf (void *arg) +{ + sigset_t ss2; + if (pthread_sigmask (SIG_SETMASK, NULL, &ss2) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + int i; + for (i = 1; i < 32; ++i) + if (sigismember (&ss, i) && ! sigismember (&ss2, i)) + { + printf ("signal %d set in parent mask, but not in child\n", i); + exit (1); + } + else if (! sigismember (&ss, i) && sigismember (&ss2, i)) + { + printf ("signal %d set in child mask, but not in parent\n", i); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st sigmask failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("1st join failed"); + exit (1); + } + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR2); + sigaddset (&ss, SIGFPE); + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("2nd sigmask failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + if (pthread_join (th, &r) != 0) + { + puts ("2nd join failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal6.c b/test/nptl/tst-signal6.c new file mode 100644 index 000000000..85a864002 --- /dev/null +++ b/test/nptl/tst-signal6.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#define N 2 +static pthread_barrier_t bar; +static struct +{ + void *p; + pthread_t s; +} ti[N]; +static int sig1; + + +static void +handler (int sig) +{ + pthread_t self = pthread_self (); + size_t i; + + for (i = 0; i < N; ++i) + if (ti[i].s == self) + { + if ((uintptr_t) ti[i].p <= (uintptr_t) &self + && (uintptr_t) ti[i].p + 2 * MINSIGSTKSZ > (uintptr_t) &self) + { + puts ("alt stack not used"); + exit (1); + } + + printf ("thread %zu used alt stack for signal %d\n", i, sig); + + return; + } + + puts ("handler: thread not found"); + exit (1); +} + + +static void * +tf (void *arg) +{ + size_t nr = (uintptr_t) arg; + if (nr >= N) + { + puts ("wrong nr parameter"); + exit (1); + } + + sigset_t ss; + sigemptyset (&ss); + size_t i; + for (i = 0; i < N; ++i) + if (i != nr) + if (sigaddset (&ss, sig1 + i) != 0) + { + puts ("tf: sigaddset failed"); + exit (1); + } + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("tf: sigmask failed"); + exit (1); + } + + void *p = malloc (2 * MINSIGSTKSZ); + if (p == NULL) + { + puts ("tf: malloc failed"); + exit (1); + } + + stack_t s; + s.ss_sp = p; + s.ss_size = 2 * MINSIGSTKSZ; + s.ss_flags = 0; + if (sigaltstack (&s, NULL) != 0) + { + puts ("tf: sigaltstack failed"); + exit (1); + } + + ti[nr].p = p; + ti[nr].s = pthread_self (); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + return NULL; +} + + +static int +do_test (void) +{ + sig1 = SIGRTMIN; + if (sig1 + N > SIGRTMAX) + { + puts ("too few RT signals"); + return 0; + } + + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + if (sigaction (sig1, &sa, NULL) != 0 + || sigaction (sig1 + 1, &sa, NULL) != 0 + || sigaction (sig1 + 2, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pthread_barrier_init (&bar, NULL, 1 + N) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th[N]; + size_t i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], NULL, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + return 1; + } + + /* Block the three signals. */ + sigset_t ss; + sigemptyset (&ss); + for (i = 0; i <= N; ++i) + sigaddset (&ss, sig1 + i); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("main: sigmask failed"); + return 1; + } + + pthread_barrier_wait (&bar); + + /* Send some signals. */ + pid_t me = getpid (); + kill (me, sig1 + N); + for (i = 0; i < N; ++i) + kill (me, sig1 + i); + kill (me, sig1 + N); + + /* Give the signals a chance to be worked on. */ + sleep (1); + + pthread_barrier_wait (&bar); + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin1.c b/test/nptl/tst-spin1.c new file mode 100644 index 000000000..259b4b4d6 --- /dev/null +++ b/test/nptl/tst-spin1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_spinlock_t s; + + if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (&s) != 0) + { + puts ("spin_lock failed"); + return 1; + } + + if (pthread_spin_unlock (&s) != 0) + { + puts ("spin_unlock failed"); + return 1; + } + + if (pthread_spin_destroy (&s) != 0) + { + puts ("spin_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin2.c b/test/nptl/tst-spin2.c new file mode 100644 index 000000000..5b1df6c4a --- /dev/null +++ b/test/nptl/tst-spin2.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-spin2.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_spinlock_t *s; + pid_t pid; + char *p; + int err; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + s = (pthread_spinlock_t *) (((uintptr_t) mem + + __alignof (pthread_spinlock_t)) + & ~(__alignof (pthread_spinlock_t) - 1)); + p = (char *) (s + 1); + + if (pthread_spin_init (s, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (s) != 0) + { + puts ("spin_lock failed"); + return 1; + } + + err = pthread_spin_trylock (s); + if (err == 0) + { + puts ("1st spin_trylock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("1st spin_trylock didn't return EBUSY"); + return 1; + } + + err = pthread_spin_unlock (s); + if (err != 0) + { + puts ("parent: spin_unlock failed"); + return 1; + } + + err = pthread_spin_trylock (s); + if (err != 0) + { + puts ("2nd spin_trylock failed"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_spin_unlock (s) != 0) + { + puts ("child: 1st spin_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_spin_lock (s) != 0) + { + puts ("parent: 2nd spin_lock failed"); + return 1; + } + + puts ("waiting for child"); + + waitpid (pid, NULL, 0); + + puts ("parent done"); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin3.c b/test/nptl/tst-spin3.c new file mode 100644 index 000000000..443774032 --- /dev/null +++ b/test/nptl/tst-spin3.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + pthread_spinlock_t s; + + if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (&s) != 0) + { + puts ("1st spin_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_spin_lock (&s); + + puts ("2nd spin_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stack-align.h b/test/nptl/tst-stack-align.h new file mode 100644 index 000000000..59b1e656a --- /dev/null +++ b/test/nptl/tst-stack-align.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2003 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdint.h> + +#define TEST_STACK_ALIGN() \ + ({ \ + double _d = 12.0; \ + long double _ld = 15.0; \ + int _ret = 0; \ + printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ + if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ + _ret = 1; \ + \ + printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ + if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ + _ret = 1; \ + _ret; \ + }) diff --git a/test/nptl/tst-stack1.c b/test/nptl/tst-stack1.c new file mode 100644 index 000000000..93405981d --- /dev/null +++ b/test/nptl/tst-stack1.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/param.h> +#include <unistd.h> + + +static void *stack; +static size_t size; + + +static void * +tf (void *a) +{ + int result = 0; + + puts ("child start"); + + pthread_attr_t attr; + if (pthread_getattr_np (pthread_self (), &attr) != 0) + { + puts ("getattr_np failed"); + exit (1); + } + + size_t test_size; + void *test_stack; + if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0) + { + puts ("attr_getstack failed"); + exit (1); + } + + if (test_size != size) + { + printf ("child: reported size differs: is %zu, expected %zu\n", + test_size, size); + result = 1; + } + + if (test_stack != stack) + { + printf ("child: reported stack address differs: is %p, expected %p\n", + test_stack, stack); + result = 1; + } + + puts ("child OK"); + + return result ? (void *) 1l : NULL; +} + + +int +do_test (void) +{ + int result = 0; + + size = MAX (4 * getpagesize (), PTHREAD_STACK_MIN); + if (posix_memalign (&stack, getpagesize (), size) != 0) + { + puts ("out of memory while allocating the stack memory"); + exit (1); + } + + pthread_attr_t attr; + if (pthread_attr_init (&attr) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + puts ("attr_setstack"); + if (pthread_attr_setstack (&attr, stack, size) != 0) + { + puts ("attr_setstack failed"); + exit (1); + } + + size_t test_size; + void *test_stack; + puts ("attr_getstack"); + if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0) + { + puts ("attr_getstack failed"); + exit (1); + } + + if (test_size != size) + { + printf ("reported size differs: is %zu, expected %zu\n", + test_size, size); + result = 1; + } + + if (test_stack != stack) + { + printf ("reported stack address differs: is %p, expected %p\n", + test_stack, stack); + result = 1; + } + + puts ("create"); + + pthread_t th; + if (pthread_create (&th, &attr, tf, NULL) != 0) + { + puts ("failed to create thread"); + exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("join failed"); + exit (1); + } + + result |= status != NULL; + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stack2.c b/test/nptl/tst-stack2.c new file mode 100644 index 000000000..5fcdb18d0 --- /dev/null +++ b/test/nptl/tst-stack2.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Test whether it is possible to create a thread with PTHREAD_STACK_MIN + stack size. */ + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> + +static int seen; + +static void * +tf (void *p) +{ + ++seen; + return NULL; +} + +static int +do_test (void) +{ + pthread_attr_t attr; + pthread_attr_init (&attr); + + int result = 0; + int res = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + if (res) + { + printf ("pthread_attr_setstacksize failed %d\n", res); + result = 1; + } + + /* Create the thread. */ + pthread_t th; + res = pthread_create (&th, &attr, tf, NULL); + if (res) + { + printf ("pthread_create failed %d\n", res); + result = 1; + } + else + { + res = pthread_join (th, NULL); + if (res) + { + printf ("pthread_join failed %d\n", res); + result = 1; + } + } + + if (seen != 1) + { + printf ("seen %d != 1\n", seen); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stdio1.c b/test/nptl/tst-stdio1.c new file mode 100644 index 000000000..ebb3e2f0b --- /dev/null +++ b/test/nptl/tst-stdio1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static void *tf (void *a) +{ + flockfile (stdout); + /* This call should never return. */ + return a; +} + + +int +do_test (void) +{ + pthread_t th; + + flockfile (stdout); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + pthread_join (th, NULL); + + puts ("join returned"); + + return 0; +} + + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stdio2.c b/test/nptl/tst-stdio2.c new file mode 100644 index 000000000..08d6addf4 --- /dev/null +++ b/test/nptl/tst-stdio2.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void *tf (void *a) +{ + puts ("start tf"); + + /* Multiple locking, implicitly or explicitly, must be possible. */ + flockfile (stdout); + + puts ("after first flockfile"); + + flockfile (stdout); + + puts ("foo"); + + funlockfile (stdout); + + puts ("after first funlockfile"); + + funlockfile (stdout); + + puts ("all done"); + + return a; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("join failed"); + exit (1); + } + else if (result != NULL) + { + printf ("wrong return value: %p, expected %p\n", result, NULL); + exit (1); + } + + puts ("join returned succsefully"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sysconf.c b/test/nptl/tst-sysconf.c new file mode 100644 index 000000000..3ad1b6a3c --- /dev/null +++ b/test/nptl/tst-sysconf.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + puts ("We expect no limits"); + /* We have no fixed limit on the number of threads. Make sure the + headers tell the right story. */ +#ifdef PTHREAD_THREADS_MAX + printf ("Header report maximum number of threads = %lu\n", + (unsigned long int) PTHREAD_THREADS_MAX); + return 1; +#else + long int r = sysconf (_SC_THREAD_THREADS_MAX); + if (r != -1) + { + printf ("sysconf(_SC_THREAD_THREADS_MAX) return %ld\n", r); + return 1; + } +#endif + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer2.c b/test/nptl/tst-timer2.c new file mode 100644 index 000000000..60026c1ef --- /dev/null +++ b/test/nptl/tst-timer2.c @@ -0,0 +1,65 @@ +/* Test for crashing bugs when trying to create too many timers. */ + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +void +thread (union sigval arg) +{ + puts ("Timeout"); +} + +int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_notify_function = thread; + sigev.sigev_notify_attributes = 0; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + if (timer_create (CLOCK_REALTIME, &sigev, &timerId) < 0) + { + perror ("timer_create"); + continue; + } + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + perror ("timer_settime"); + + res = timer_delete (timerId); + if (res < 0) + perror ("timer_delete"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer3.c b/test/nptl/tst-timer3.c new file mode 100644 index 000000000..8113f6690 --- /dev/null +++ b/test/nptl/tst-timer3.c @@ -0,0 +1,86 @@ +/* Test for bogus per-thread deletion of timers. */ + +#include <stdio.h> +#include <error.h> +#include <time.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + + +/* Creating timers in another thread should work too. */ +static void * +do_timer_create (void *arg) +{ + struct sigevent *const sigev = arg; + timer_t *const timerId = sigev->sigev_value.sival_ptr; + if (timer_create (CLOCK_REALTIME, sigev, timerId) < 0) + { + printf ("timer_create: %m\n"); + return NULL; + } + return timerId; +} + + +static int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGALRM; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + pthread_t thr; + res = pthread_create (&thr, NULL, &do_timer_create, &sigev); + if (res) + { + printf ("pthread_create: %s\n", strerror (res)); + continue; + } + void *val; + res = pthread_join (thr, &val); + if (res) + { + printf ("pthread_join: %s\n", strerror (res)); + continue; + } + if (val == NULL) + continue; + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + printf ("timer_settime: %m\n"); + + res = timer_delete (timerId); + if (res < 0) + printf ("timer_delete: %m\n"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer4.c b/test/nptl/tst-timer4.c new file mode 100644 index 000000000..5bec01181 --- /dev/null +++ b/test/nptl/tst-timer4.c @@ -0,0 +1,648 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004 + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +# ifndef TEST_CLOCK +# define TEST_CLOCK CLOCK_REALTIME +# endif + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2; + +int thr1_cnt, thr1_err; +union sigval thr1_sigval; +struct timespec thr1_ts; + +static void +thr1 (union sigval sigval) +{ + pthread_mutex_lock (&lock); + thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts); + if (thr1_cnt >= 5) + { + struct itimerspec it = { }; + thr1_err |= timer_settime (timer_thr1, 0, &it, NULL); + } + thr1_sigval = sigval; + ++thr1_cnt; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +int thr2_cnt, thr2_err; +union sigval thr2_sigval; +size_t thr2_guardsize; +struct timespec thr2_ts; + +static void +thr2 (union sigval sigval) +{ + pthread_attr_t nattr; + int err = 0; + size_t guardsize = -1; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("*** pthread_getattr_np failed: %m\n"); + err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &guardsize); + if (ret) + { + errno = ret; + printf ("*** pthread_attr_getguardsize failed: %m\n"); + err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("*** pthread_attr_destroy failed"); + err = 1; + } + } + pthread_mutex_lock (&lock); + thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err; + if (thr2_cnt >= 5) + { + struct itimerspec it = { }; + thr2_err |= timer_settime (timer_thr2, 0, &it, NULL); + } + thr2_sigval = sigval; + ++thr2_cnt; + thr2_guardsize = guardsize; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +volatile int sig1_cnt, sig1_err; +volatile union sigval sig1_sigval; +struct timespec sig1_ts; + +static void +sig1_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN) err |= 1 << 0; + if (info->si_signo != SIGRTMIN) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0) + err |= 1 << 3; + if (sig1_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig1, 0, &it, NULL)) + err |= 1 << 4; + } + sig1_err |= err; + sig1_sigval = info->si_value; + ++sig1_cnt; +} + +volatile int sig2_cnt, sig2_err; +volatile union sigval sig2_sigval; +struct timespec sig2_ts; + +static void +sig2_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN + 1) err |= 1 << 0; + if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0) + err |= 1 << 3; + if (sig2_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig2, 0, &it, NULL)) + err |= 1 << 4; + } + sig2_err |= err; + sig2_sigval = info->si_value; + ++sig2_cnt; +} + +/* Check if end is later or equal to start + nsec. */ +static int +check_ts (const char *name, const struct timespec *start, + const struct timespec *end, long msec) +{ + struct timespec ts = *start; + + ts.tv_sec += msec / 1000000; + ts.tv_nsec += (msec % 1000000) * 1000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + if (end->tv_sec < ts.tv_sec + || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec)) + { + printf ("\ +*** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n", + name, (long) end->tv_sec, end->tv_nsec, + (long) ts.tv_sec, ts.tv_nsec); + return 1; + } + else + return 0; +} + +#define TIMEOUT 15 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + +#ifdef TEST_CLOCK_MISSING + const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK); + if (missing != NULL) + { + printf ("%s missing, skipping test\n", missing); + return 0; + } +#endif + + struct timespec ts; + if (clock_gettime (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + else + printf ("clock_gettime returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + if (clock_getres (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_getres failed: %m\n"); + result = 1; + } + else + printf ("clock_getres returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + struct sigevent ev; + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0) + { + printf ("*** timer_create for timer_none failed: %m\n"); + return 1; + } + + struct sigaction sa = { .sa_sigaction = sig1_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + sa.sa_sigaction = sig2_handler; + sigaction (SIGRTMIN + 1, &sa, NULL); + + memset (&ev, 0x22, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0) + { + printf ("*** timer_create for timer_sig1 failed: %m\n"); + return 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN + 1; + ev.sigev_value.sival_int = 163; + if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0) + { + printf ("*** timer_create for timer_sig2 failed: %m\n"); + return 1; + } + + memset (&ev, 0x44, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr1; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0) + { + printf ("*** timer_create for timer_thr1 failed: %m\n"); + return 1; + } + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("*** pthread_attr_t setup failed"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr2; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_int = 111; + if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0) + { + printf ("*** timer_create for timer_thr2 failed: %m\n"); + return 1; + } + + int ret = timer_getoverrun (timer_thr1); + if (ret != 0) + { + if (ret == -1) + printf ("*** timer_getoverrun failed: %m\n"); + else + printf ("*** timer_getoverrun returned %d != 0\n", ret); + result = 1; + } + + struct itimerspec it; + it.it_value.tv_sec = 0; + it.it_value.tv_nsec = -26; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_sig1, 0, &it, NULL) == 0) + { + puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000; + it.it_interval.tv_nsec = 1000000000; + if (timer_settime (timer_sig2, 0, &it, NULL) == 0) + { + puts ("\ +*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with tv_nsec 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + +#if 0 + it.it_value.tv_nsec = 0; + it.it_interval.tv_nsec = -26; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } + + it.it_interval.tv_nsec = 3000000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } +#endif + + struct timespec startts; + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt == 0 || thr2_cnt == 0) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt == 0 || sig2_cnt == 0) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_cnt != 1) + { + printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt); + result = 1; + } + else if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (thr1_sigval.sival_ptr != &ev) + { + printf ("*** thr1_sigval.sival_ptr %p != %p\n", + thr1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 200000)) + result = 1; + + if (thr2_cnt != 1) + { + printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt); + result = 1; + } + else if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (thr2_sigval.sival_int != 111) + { + printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_cnt != 1) + { + printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt); + result = 1; + } + else if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (sig1_sigval.sival_ptr != &ev) + { + printf ("*** sig1_sigval.sival_ptr %p != %p\n", + sig1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 400000)) + result = 1; + + if (sig2_cnt != 1) + { + printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt); + result = 1; + } + else if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (sig2_sigval.sival_int != 163) + { + printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_value.tv_sec || it.it_value.tv_nsec + || it.it_interval.tv_sec || it.it_interval.tv_nsec) + { + printf ("\ +*** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n", + (long) it.it_value.tv_sec, it.it_value.tv_nsec, + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + result = 1; + } + + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_nsec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 100000000; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + it.it_interval.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + it.it_interval.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + it.it_interval.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt < 6 || thr2_cnt < 6) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt < 6 || sig2_cnt < 6) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000)) + result = 1; + + if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000)) + result = 1; + + if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000) + { + printf ("\ +!!! second timer_gettime timer_none returned it_interval %ld.%09ld\n", + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + /* FIXME: For now disabled. + result = 1; */ + } + + if (timer_delete (timer_none) != 0) + { + printf ("*** timer_delete for timer_none failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig1) != 0) + { + printf ("*** timer_delete for timer_sig1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig2) != 0) + { + printf ("*** timer_delete for timer_sig2 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr1) != 0) + { + printf ("*** timer_delete for timer_thr1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr2) != 0) + { + printf ("*** timer_delete for timer_thr2 failed: %m\n"); + result = 1; + } + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer5.c b/test/nptl/tst-timer5.c new file mode 100644 index 000000000..6466c8efc --- /dev/null +++ b/test/nptl/tst-timer5.c @@ -0,0 +1,38 @@ +/* Timer test using the monotonic clock. */ + +#include <time.h> +#include <unistd.h> + +#if defined CLOCK_MONOTONIC && defined _POSIX_MONOTONIC_CLOCK + +# define TEST_CLOCK CLOCK_MONOTONIC +# define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "CLOCK_MONOTONIC" : NULL) + +# include <stdio.h> + +static int +setup_test (void) +{ + if (sysconf (_SC_MONOTONIC_CLOCK) <= 0) + return 1; + + /* The user-level timers implementation doesn't support CLOCK_MONOTONIC, + even though sysconf claims it will. */ + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +# include "tst-timer4.c" + +#else +# define TEST_FUNCTION 0 +# include "../test-skeleton.c" +#endif diff --git a/test/nptl/tst-tls1.c b/test/nptl/tst-tls1.c new file mode 100644 index 000000000..541035ea7 --- /dev/null +++ b/test/nptl/tst-tls1.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <tls.h> + +#if HAVE___THREAD +struct test_s +{ + int a; + int b; +}; + +#define INIT_A 1 +#define INIT_B 42 +/* Deliberately not static. */ +__thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) = +{ + .a = INIT_A, + .b = INIT_B +}; + + +static void * +tf (void *arg) +{ + if (s.a != INIT_A || s.b != INIT_B) + { + puts ("initial value of s in child thread wrong"); + exit (1); + } + + ++s.a; + + return NULL; +} +#endif + + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if (s.a != INIT_A || s.b != INIT_B) + { + puts ("initial value of s in main thread wrong"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + +#define N 10 + int i; + for (i = 0; i < N; ++i) + { +#define M 10 + pthread_t th[M]; + int j; + for (j = 0; j < M; ++j, ++s.a) + if (pthread_create (&th[j], &a, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + for (j = 0; j < M; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls2.c b/test/nptl/tst-tls2.c new file mode 100644 index 000000000..3615d1b81 --- /dev/null +++ b/test/nptl/tst-tls2.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD + +#define N 10 +static pthread_t th[N]; + + +#define CB(n) \ +static void \ +cb##n (void) \ +{ \ + if (th[n] != pthread_self ()) \ + { \ + write (STDOUT_FILENO, "wrong callback\n", 15); \ + _exit (1); \ + } \ +} +CB (0) +CB (1) +CB (2) +CB (3) +CB (4) +CB (5) +CB (6) +CB (7) +CB (8) +CB (9) +static void (*cbs[]) (void) = +{ + cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9 +}; + + +static __thread void (*fp) (void) __attribute__ ((tls_model ("local-exec"))); + + +static sem_t s; + + +#define THE_SIG SIGUSR1 +static void +handler (int sig) +{ + if (sig != THE_SIG) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + fp (); + + if (sem_post (&s) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + + +static pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +static int nsigs; + + +static void * +tf (void *arg) +{ + fp = arg; + + pthread_barrier_wait (&b); + + pthread_barrier_wait (&b); + + if (nsigs != TOTAL_SIGS) + { + puts ("barrier_wait prematurely returns"); + exit (1); + } + + return NULL; +} +#endif + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (THE_SIG, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, cbs[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + pthread_barrier_wait (&b); + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, THE_SIG); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + /* Start sending signals. */ + for (i = 0; i < TOTAL_SIGS; ++i) + { + if (kill (getpid (), THE_SIG) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + + ++nsigs; + } + + pthread_barrier_wait (&b); + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls3.c b/test/nptl/tst-tls3.c new file mode 100644 index 000000000..411acbdf0 --- /dev/null +++ b/test/nptl/tst-tls3.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <dlfcn.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <semaphore.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthreaddef.h> +#include <tls.h> + +#define THE_SIG SIGUSR1 + + +#define N 10 +static pthread_t th[N]; + + +#define CB(n) \ +static void \ +cb##n (void) \ +{ \ + if (th[n] != pthread_self ()) \ + { \ + write (STDOUT_FILENO, "wrong callback\n", 15); \ + _exit (1); \ + } \ +} +CB (0) +CB (1) +CB (2) +CB (3) +CB (4) +CB (5) +CB (6) +CB (7) +CB (8) +CB (9) +static void (*cbs[]) (void) = +{ + cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9 +}; + + +sem_t s; + + +pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +int nsigs; + + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1)) + { + puts ("initial thread's struct pthread not aligned enough"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + void *h = dlopen ("tst-tls3mod.so", RTLD_LAZY); + if (h == NULL) + { + puts ("dlopen failed"); + exit (1); + } + + void *(*tf) (void *) = dlsym (h, "tf"); + if (tf == NULL) + { + puts ("dlsym for tf failed"); + exit (1); + } + + struct sigaction sa; + sa.sa_handler = dlsym (h, "handler"); + if (sa.sa_handler == NULL) + { + puts ("dlsym for handler failed"); + exit (1); + } + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (THE_SIG, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int r; + for (r = 0; r < 10; ++r) + { + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, cbs[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + nsigs = 0; + + pthread_barrier_wait (&b); + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, THE_SIG); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + /* Start sending signals. */ + for (i = 0; i < TOTAL_SIGS; ++i) + { + if (kill (getpid (), THE_SIG) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + + ++nsigs; + } + + pthread_barrier_wait (&b); + + if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls3mod.c b/test/nptl/tst-tls3mod.c new file mode 100644 index 000000000..25f892405 --- /dev/null +++ b/test/nptl/tst-tls3mod.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthreaddef.h> +#include <tls.h> + +#if HAVE___THREAD + +extern pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +extern int nsigs; + +extern sem_t s; + + +static __thread void (*fp) (void); + + +#define THE_SIG SIGUSR1 +void +handler (int sig) +{ + if (sig != THE_SIG) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + fp (); + + if (sem_post (&s) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + + +void * +tf (void *arg) +{ + if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1)) + { + puts ("thread's struct pthread not aligned enough"); + exit (1); + } + + if (fp != NULL) + { +printf("fp=%p\n", (void *)&fp); + puts ("fp not initially NULL"); + exit (1); + } + + fp = arg; + + pthread_barrier_wait (&b); + + pthread_barrier_wait (&b); + + if (nsigs != TOTAL_SIGS) + { + puts ("barrier_wait prematurely returns"); + exit (1); + } + + return NULL; +} + +#endif diff --git a/test/nptl/tst-tls4.c b/test/nptl/tst-tls4.c new file mode 100644 index 000000000..52775dee8 --- /dev/null +++ b/test/nptl/tst-tls4.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <dlfcn.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +#define N 3 + +void (*test1) (void), (*test2) (void); + +pthread_barrier_t b2, b3; + +static void * +tf (void *arg) +{ + int i; + + for (i = 0; i <= (uintptr_t) arg; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + test1 (); + + for (i = 0; i < 3; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + test2 (); + + for (i = 0; i < 3 - (uintptr_t) arg; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + return NULL; +} + +static void * +tf2 (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf2: barrier_wait failed"); + exit (1); + } + + int i; + for (i = 0; i < N; ++i) + tf (arg); + return NULL; +} + +int +do_test (void) +{ + pthread_t th[2]; + const char *modules[N] + = { "tst-tls4moda.so", "tst-tls4moda.so", "tst-tls4modb.so" }; + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (&b3, NULL, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th[0], NULL, tf2, (void *) (uintptr_t) 1)) + { + puts ("pthread_create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + { + void *h = dlopen (modules[i], RTLD_LAZY); + if (h == NULL) + { + printf ("dlopen failed %s\n", dlerror ()); + return 1; + } + + test1 = dlsym (h, "test1"); + if (test1 == NULL) + { + printf ("dlsym for test1 failed %s\n", dlerror ()); + return 1; + } + + test2 = dlsym (h, "test2"); + if (test2 == NULL) + { + printf ("dlsym for test2 failed %s\n", dlerror ()); + return 1; + } + + if (pthread_create (&th[1], NULL, tf, (void *) (uintptr_t) 2)) + { + puts ("pthread_create failed"); + return 1; + } + + tf ((void *) (uintptr_t) 0); + + if (pthread_join (th[1], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (dlclose (h)) + { + puts ("dlclose failed"); + return 1; + } + + printf ("test %d with %s succeeded\n", i, modules[i]); + } + + if (pthread_join (th[0], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + return 0; +} + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls4moda.c b/test/nptl/tst-tls4moda.c new file mode 100644 index 000000000..ff7ee5604 --- /dev/null +++ b/test/nptl/tst-tls4moda.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +static __thread unsigned char foo [32] + __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *)))); + +void +test1 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo); ++s) + { + if (foo [s]) + abort (); + foo [s] = s; + } +} + +void +test2 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo); ++s) + { + if (foo [s] != s) + abort (); + foo [s] = sizeof (foo) - s; + } +} + +#endif diff --git a/test/nptl/tst-tls4modb.c b/test/nptl/tst-tls4modb.c new file mode 100644 index 000000000..99f3b5405 --- /dev/null +++ b/test/nptl/tst-tls4modb.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +static int i; +int bar; + +static __thread void *foo [32 / sizeof (void *)] + __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *)))) + = { &i, &bar }; + +void +test1 (void) +{ + size_t s; + + if (foo [0] != &i || foo [1] != &bar) + abort (); + + foo [0] = NULL; + foo [1] = NULL; + for (s = 0; s < sizeof (foo) / sizeof (void *); ++s) + { + if (foo [s]) + abort (); + foo [s] = &foo[s]; + } +} + +void +test2 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo) / sizeof (void *); ++s) + { + if (foo [s] != &foo [s]) + abort (); + foo [s] = &foo [s ^ 1]; + } +} + +#endif diff --git a/test/nptl/tst-tls5.c b/test/nptl/tst-tls5.c new file mode 100644 index 000000000..476f09aa1 --- /dev/null +++ b/test/nptl/tst-tls5.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Check alignment, overlapping and layout of TLS variables. */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/param.h> + +#include "tst-tls5.h" + +#ifdef TLS_REGISTER + +struct tls_obj tls_registry[64]; + +static int +tls_addr_cmp (const void *a, const void *b) +{ + if (((struct tls_obj *)a)->addr < ((struct tls_obj *)b)->addr) + return -1; + if (((struct tls_obj *)a)->addr > ((struct tls_obj *)b)->addr) + return 1; + return 0; +} + +static int +do_test (void) +{ + size_t cnt, i; + int res = 0; + uintptr_t min_addr = ~(uintptr_t) 0, max_addr = 0; + + for (cnt = 0; tls_registry[cnt].name; ++cnt); + tls_registry[cnt].name = NULL; + tls_registry[cnt].addr = (uintptr_t) pthread_self (); + tls_registry[cnt].size = sizeof (struct pthread); + tls_registry[cnt++].align = __alignof__ (struct pthread); + + qsort (tls_registry, cnt, sizeof (struct tls_obj), tls_addr_cmp); + + for (i = 0; i < cnt; ++i) + { + printf ("%s%s = %p, size %zd, align %zd", + tls_registry[i].name ? "&" : "", + tls_registry[i].name ?: "pthread_self ()", + (void *) tls_registry[i].addr, + tls_registry[i].size, tls_registry[i].align); + if (tls_registry[i].addr & (tls_registry[i].align - 1)) + { + fputs (", WRONG ALIGNMENT", stdout); + res = 1; + } + if (i > 0 + && (tls_registry[i - 1].addr + tls_registry[i - 1].size + > tls_registry[i].addr)) + { + fputs (", ADDRESS OVERLAP", stdout); + res = 1; + } + puts (""); + if (tls_registry[i].name) + { + min_addr = MIN (tls_registry[i].addr, min_addr); + max_addr = MAX (tls_registry[i].addr + tls_registry[i].size, + max_addr); + } + } + + if (cnt > 1) + { +#if defined(TLS_TCB_AT_TP) + if (tls_registry[cnt - 1].name) + { + puts ("pthread_self () not larger than all TLS addresses"); + res = 1; + } + else + max_addr = MAX (tls_registry[cnt - 1].addr, max_addr); +#elif defined(TLS_DTV_AT_TP) + if (tls_registry[0].name) + { + puts ("pthread_self () not smaller than all TLS addresses"); + res = 1; + } +#else + abort (); +#endif + printf ("Initial TLS used block size %zd\n", + (size_t) (max_addr - min_addr)); + } + return res; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls5.h b/test/nptl/tst-tls5.h new file mode 100644 index 000000000..b7c14eb82 --- /dev/null +++ b/test/nptl/tst-tls5.h @@ -0,0 +1,28 @@ +#include <stdint.h> +#include <stdlib.h> +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +struct tls_obj +{ + const char *name; + uintptr_t addr; + size_t size; + size_t align; +}; +extern struct tls_obj tls_registry[]; + +#define TLS_REGISTER(x) \ +static void __attribute__((constructor)) \ +tls_register_##x (void) \ +{ \ + size_t i; \ + for (i = 0; tls_registry[i].name; ++i); \ + tls_registry[i].name = #x; \ + tls_registry[i].addr = (uintptr_t) &x; \ + tls_registry[i].size = sizeof (x); \ + tls_registry[i].align = __alignof__ (x); \ +} + +#endif diff --git a/test/nptl/tst-tls5mod.c b/test/nptl/tst-tls5mod.c new file mode 100644 index 000000000..4616a20e9 --- /dev/null +++ b/test/nptl/tst-tls5mod.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +/* Ensure tls_registry is exported from the binary. */ +void *tst_tls5mod attribute_hidden = tls_registry; +#endif diff --git a/test/nptl/tst-tls5moda.c b/test/nptl/tst-tls5moda.c new file mode 100644 index 000000000..4644d763a --- /dev/null +++ b/test/nptl/tst-tls5moda.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread char a [32] __attribute__ ((aligned (64))); +TLS_REGISTER (a) +#endif diff --git a/test/nptl/tst-tls5modb.c b/test/nptl/tst-tls5modb.c new file mode 100644 index 000000000..09b439670 --- /dev/null +++ b/test/nptl/tst-tls5modb.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int b; +TLS_REGISTER (b) +#endif diff --git a/test/nptl/tst-tls5modc.c b/test/nptl/tst-tls5modc.c new file mode 100644 index 000000000..bbd89633d --- /dev/null +++ b/test/nptl/tst-tls5modc.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int c; +TLS_REGISTER (c) +#endif diff --git a/test/nptl/tst-tls5modd.c b/test/nptl/tst-tls5modd.c new file mode 100644 index 000000000..8b54d168c --- /dev/null +++ b/test/nptl/tst-tls5modd.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int d; +TLS_REGISTER (d) +#endif diff --git a/test/nptl/tst-tls5mode.c b/test/nptl/tst-tls5mode.c new file mode 100644 index 000000000..d30b06752 --- /dev/null +++ b/test/nptl/tst-tls5mode.c @@ -0,0 +1,8 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int e1 = 24; +static __thread char e2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (e1) +TLS_REGISTER (e2) +#endif diff --git a/test/nptl/tst-tls5modf.c b/test/nptl/tst-tls5modf.c new file mode 100644 index 000000000..52dcb9495 --- /dev/null +++ b/test/nptl/tst-tls5modf.c @@ -0,0 +1,9 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +char tst_tls5modf[60] attribute_hidden = { 26 }; +static __thread int f1 = 24; +static __thread char f2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (f1) +TLS_REGISTER (f2) +#endif diff --git a/test/nptl/tst-tsd1.c b/test/nptl/tst-tsd1.c new file mode 100644 index 000000000..51b2d0cb2 --- /dev/null +++ b/test/nptl/tst-tsd1.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_key_t key1; + pthread_key_t key2; + void *value; + int result = 0; + int err; + + err = pthread_key_create (&key1, NULL); + if (err != 0) + { + printf ("1st key_create failed: %s\n", strerror (err)); + return 1; + } + + /* Initial value must be NULL. */ + value = pthread_getspecific (key1); + if (value != NULL) + { + puts ("1st getspecific != NULL"); + result = 1; + } + + err = pthread_setspecific (key1, (void *) -2l); + if (err != 0) + { + printf ("1st setspecific failed: %s\n", strerror (err)); + return 1; + } + + value = pthread_getspecific (key1); + if (value == NULL) + { + puts ("2nd getspecific == NULL\n"); + result = 1; + } + else if (value != (void *) -2l) + { + puts ("2nd getspecific != -2l\n"); + result = 1; + } + + err = pthread_setspecific (key1, (void *) -3l); + if (err != 0) + { + printf ("2nd setspecific failed: %s\n", strerror (err)); + return 1; + } + + value = pthread_getspecific (key1); + if (value == NULL) + { + puts ("3rd getspecific == NULL\n"); + result = 1; + } + else if (value != (void *) -3l) + { + puts ("3rd getspecific != -2l\n"); + result = 1; + } + + err = pthread_key_delete (key1); + if (err != 0) + { + printf ("key_delete failed: %s\n", strerror (err)); + result = 1; + } + + + err = pthread_key_create (&key2, NULL); + if (err != 0) + { + printf ("2nd key_create failed: %s\n", strerror (err)); + return 1; + } + + if (key1 != key2) + puts ("key1 != key2; no more tests performed"); + else + { + value = pthread_getspecific (key2); + if (value != NULL) + { + puts ("4th getspecific != NULL"); + result = 1; + } + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd2.c b/test/nptl/tst-tsd2.c new file mode 100644 index 000000000..19d8a69f9 --- /dev/null +++ b/test/nptl/tst-tsd2.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int result; + + +static void +destr (void *arg) +{ + if (arg != (void *) -2l) + result = 2; + else + result = 0; +} + + +static void * +tf (void *arg) +{ + pthread_key_t key = (pthread_key_t) (long int) arg; + int err; + + err = pthread_setspecific (key, (void *) -2l); + if (err != 0) + result = 3; + + return NULL; +} + + +static int +do_test (void) +{ + pthread_key_t key; + pthread_t th; + int err; + + err = pthread_key_create (&key, destr); + if (err != 0) + { + printf ("key_create failed: %s\n", strerror (err)); + return 1; + } + + result = 1; + + err = pthread_create (&th, NULL, tf, (void *) (long int) key); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + /* Wait for the thread to terminate. */ + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (result == 1) + puts ("destructor not called"); + else if (result == 2) + puts ("destructor got passed a wrong value"); + else if (result == 3) + puts ("setspecific in child failed"); + else if (result != 0) + puts ("result != 0"); + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd3.c b/test/nptl/tst-tsd3.c new file mode 100644 index 000000000..6cdf74991 --- /dev/null +++ b/test/nptl/tst-tsd3.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_key_t key1; +static pthread_key_t key2; + + +static int left; + + +static void +destr1 (void *arg) +{ + if (--left > 0) + { + puts ("set key2"); + + if (pthread_setspecific (key2, (void *) 1l) != 0) + { + puts ("destr1: setspecific failed"); + exit (1); + } + } +} + + +static void +destr2 (void *arg) +{ + if (--left > 0) + { + puts ("set key1"); + + if (pthread_setspecific (key1, (void *) 1l) != 0) + { + puts ("destr2: setspecific failed"); + exit (1); + } + } +} + + +static void * +tf (void *arg) +{ + /* Let the destructors work. */ + left = 7; + + if (pthread_setspecific (key1, (void *) 1l) != 0 + || pthread_setspecific (key2, (void *) 1l) != 0) + { + puts ("tf: setspecific failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + /* Allocate two keys, both with destructors. */ + if (pthread_key_create (&key1, destr1) != 0 + || pthread_key_create (&key2, destr2) != 0) + { + puts ("key_create failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (left != 0) + { + printf ("left == %d\n", left); + return 1; + } + + if (pthread_getspecific (key1) != NULL) + { + puts ("key1 data != NULL"); + return 1; + } + if (pthread_getspecific (key2) != NULL) + { + puts ("key2 data != NULL"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd4.c b/test/nptl/tst-tsd4.c new file mode 100644 index 000000000..44bbadb42 --- /dev/null +++ b/test/nptl/tst-tsd4.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_key_t key; + + +static int rounds; + + +static void +destr (void *arg) +{ + ++rounds; + + if (pthread_setspecific (key, (void *) 1l) != 0) + { + puts ("destr: setspecific failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + if (pthread_setspecific (key, (void *) 1l) != 0) + { + puts ("tf: setspecific failed"); + exit (1); + } + + return NULL; +} + + +/* This test check non-standard behavior. The standard does not + require that the implementation has to stop calling TSD destructors + when they are set over and over again. But NPTL does. */ +static int +do_test (void) +{ + /* Allocate two keys, both with destructors. */ + if (pthread_key_create (&key, destr) != 0) + { + puts ("key_create failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (rounds < PTHREAD_DESTRUCTOR_ITERATIONS) + { + printf ("rounds == %d, PTHREAD_DESTRUCTOR_ITERATIONS = %d\n", + rounds, PTHREAD_DESTRUCTOR_ITERATIONS); + return 1; + } + + if (pthread_getspecific (key) != NULL) + { + puts ("key data != NULL"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd5.c b/test/nptl/tst-tsd5.c new file mode 100644 index 000000000..8793e339a --- /dev/null +++ b/test/nptl/tst-tsd5.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + + +static void +cl (void *p) +{ + pthread_mutex_unlock (&m); +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + pthread_key_t k; + if (pthread_key_create (&k, cl) != 0) + { + puts ("key_create failed"); + return 1; + } + if (pthread_setspecific (k, (void *) 1) != 0) + { + puts ("setspecific failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + pthread_exit (NULL); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-umask1.c b/test/nptl/tst-umask1.c new file mode 100644 index 000000000..d64a8be3d --- /dev/null +++ b/test/nptl/tst-umask1.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + + +static struct +{ + int (*fp) (const char *, mode_t); + const char *name; + bool is_fd; +} fcts[] = +{ + { creat, "creat", true }, + { mkdir, "mkdir", false }, + { mkfifo, "mkfifo", false }, +}; +#define nfcts (sizeof (fcts) / sizeof (fcts[0])) + + +static int +work (const char *fname, int mask) +{ + int result = 0; + size_t i; + for (i = 0; i < nfcts; ++i) + { + remove (fname); + int fd = fcts[i].fp (fname, 0777); + if (fd == -1) + { + printf ("cannot %s %s: %m\n", fcts[i].name, fname); + exit (1); + } + if (fcts[i].is_fd) + close (fd); + struct stat64 st; + if (stat64 (fname, &st) == -1) + { + printf ("cannot stat %s after %s: %m\n", fname, fcts[i].name); + exit (1); + } + + if ((st.st_mode & mask) != 0) + { + printf ("mask not successful after %s: %x still set\n", + fcts[i].name, (unsigned int) (st.st_mode & mask)); + result = 1; + } + } + + return result; +} + + +static pthread_barrier_t bar; + + +static void * +tf (void *arg) +{ + pthread_barrier_wait (&bar); + + int result = work (arg, 022); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + return (work (arg, 0) | result) ? (void *) -1l : NULL; +} + + +static int +do_test (const char *fname) +{ + int result = 0; + + umask (0); + result |= work (fname, 0); + + pthread_barrier_init (&bar, NULL, 2); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) fname) != 0) + { + puts ("cannot create thread"); + exit (1); + } + + umask (022); + result |= work (fname, 022); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + umask (0); + + pthread_barrier_wait (&bar); + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + exit (1); + } + + remove (fname); + + return result || res != NULL; +} + +#define TEST_FUNCTION do_test (argc < 2 ? "/tmp/tst-umask.tmp" : argv[1]) +#include "../test-skeleton.c" diff --git a/test/pthread/Makefile b/test/pthread/Makefile index d6f00d643..5f2033d42 100644 --- a/test/pthread/Makefile +++ b/test/pthread/Makefile @@ -1,6 +1,7 @@ # uClibc pthread tests # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +TESTS_DISABLED += cancellation-points top_builddir=../../ include ../Rules.mak -include Makefile.in diff --git a/test/tls/Makefile b/test/tls/Makefile new file mode 100644 index 000000000..a99c5d16f --- /dev/null +++ b/test/tls/Makefile @@ -0,0 +1,7 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +top_builddir=../../ +include ../Rules.mak +-include Makefile.in +include ../Test.mak diff --git a/test/tls/Makefile.in b/test/tls/Makefile.in new file mode 100644 index 000000000..10c674100 --- /dev/null +++ b/test/tls/Makefile.in @@ -0,0 +1,104 @@ +# uClibc TLS tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 \ + tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13 \ + tst-tls14 tst-tls15 tst-tls16 tst-tls1-static tst-tls2-static \ + tst-tls9-static +TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static + +PTDIR := $(top_builddir)libpthread/nptl + +EXTRA_CFLAGS := -DNOT_IN_libc=1 \ + -std=gnu99 -I. -I$(PTDIR) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux \ + -I$(PTDIR)/sysdeps/pthread \ + -I$(PTDIR)/sysdeps/pthread/bits \ + -I$(PTDIR)/sysdeps/generic \ + -I$(top_builddir)ldso/include \ + -I$(top_builddir)ldso/ldso/$(TARGET_ARCH) \ + -include $(top_builddir)include/libc-symbols.h + +CFLAGS_tst-tlsmod1.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod2.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod3.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod4.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod5.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod6.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod7.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod8.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod9.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod10.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod11.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod12.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod16.so := -fPIC -DSHARED -shared + +LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod2.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod3.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod2.so +LDFLAGS_tst-tlsmod4.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod5.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod6.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod7.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod8.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod7.so +LDFLAGS_tst-tlsmod9.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod10.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod9.so +LDFLAGS_tst-tlsmod11.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod12.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod11.so +LDFLAGS_tst-tlsmod13.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod13a.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod13.so +LDFLAGS_tst-tlsmod14a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod14b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod16.so := -shared -static-libgcc -L$(top_builddir)lib + +LDFLAGS_tst-tls3 := tst-tlsmod1.so +LDFLAGS_tst-tls4 := -ldl +LDFLAGS_tst-tls5 := -ldl +LDFLAGS_tst-tls6 := -ldl +LDFLAGS_tst-tls7 := -ldl +LDFLAGS_tst-tls8 := -ldl +LDFLAGS_tst-tls9 := -ldl +LDFLAGS_tst-tls10 := -Wl,-rpath-link=. tst-tlsmod8.so +LDFLAGS_tst-tls11 := -Wl,-rpath-link=. tst-tlsmod10.so +LDFLAGS_tst-tls12 := -Wl,-rpath-link=. tst-tlsmod12.so +LDFLAGS_tst-tls13 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so +LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls16 := tst-tlsmod16.so + +tst-tls3: tst-tlsmod1.so +tst-tls4: tst-tlsmod2.so +tst-tls5: tst-tlsmod2.so +tst-tls6: tst-tlsmod2.so +tst-tls7: tst-tlsmod2.so tst-tlsmod3.so +tst-tls8: tst-tlsmod2.so tst-tlsmod3.so tst-tlsmod4.so +tst-tls9: tst-tlsmod5.so tst-tlsmod6.so +tst-tls10: tst-tlsmod7.so tst-tlsmod8.so +tst-tls11: tst-tlsmod9.so tst-tlsmod10.so +tst-tls12: tst-tlsmod11.so tst-tlsmod12.so +tst-tls13: tst-tlsmod13.so tst-tlsmod13a.so +tst-tls14: tst-tlsmod14a.so tst-tlsmod14b.so +tst-tls15: tst-tlsmod15a.so tst-tlsmod15b.so +tst-tls16: tst-tlsmod16.so + +RET_tst-tls13 := 1 +ifeq ($(TARGET_ARCH),mips) +RET_tst-tls15 := 1 +endif + +WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" diff --git a/test/tls/README b/test/tls/README new file mode 100644 index 000000000..06c9eb743 --- /dev/null +++ b/test/tls/README @@ -0,0 +1,8 @@ +These tests were imported from 'glibc/elf' and are responsible for testing +the TLS functionality of the dynamic loader. The file 'tls-macros-mips.h' +is a copy of 'glibc/sysdeps/mips/tls-macros.h'. Dependency and link orders +are critical and should NOT be changed. Even if you think you know what +you are doing, do not touch the Makefile without posting to the uClibc +development mailing list. + +-Steve <sjhill@uclibc.org> diff --git a/test/tls/tls-macros-arm.h b/test/tls/tls-macros-arm.h new file mode 100644 index 000000000..13d0f9752 --- /dev/null +++ b/test/tls/tls-macros-arm.h @@ -0,0 +1,51 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "3: ldr %0, [pc, %0];" \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(gottpoff) + (. - 3b - 8); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros-mips.h b/test/tls/tls-macros-mips.h new file mode 100644 index 000000000..0db383032 --- /dev/null +++ b/test/tls/tls-macros-mips.h @@ -0,0 +1,88 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#if _MIPS_SIM != _ABI64 + +/* These versions are for o32 and n32. */ + +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#else +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#endif + +#if _MIPS_SIM != _ABI64 +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lw $3,%%gottprel(" #x ")($28)\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) + +#else + +/* These versions are for n64. */ + +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("ld $3,%%gottprel(" #x ")($28)\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +#endif diff --git a/test/tls/tls-macros-thumb.h b/test/tls/tls-macros-thumb.h new file mode 100644 index 000000000..dfa6582a5 --- /dev/null +++ b/test/tls/tls-macros-thumb.h @@ -0,0 +1,57 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + int tmp; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "adr %1, 1f; " \ + "ldr %0, [%1, %0]; " \ + "add %0, %2, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(gottpoff); " \ + "2: " \ + : "=&r" (__result), "=&r"(tmp) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros.h b/test/tls/tls-macros.h new file mode 100644 index 000000000..29a75df95 --- /dev/null +++ b/test/tls/tls-macros.h @@ -0,0 +1,861 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#define COMMON_INT_DEF(x) \ + __asm__ (".tls_common " #x ",4,4") +/* XXX Until we get compiler support we don't need declarations. */ +#define COMMON_INT_DECL(x) + +/* XXX This definition will probably be machine specific, too. */ +#define VAR_INT_DEF(x) \ + __asm__ (".section .tdata\n\t" \ + ".globl " #x "\n" \ + ".balign 4\n" \ + #x ":\t.long 0\n\t" \ + ".size " #x ",4\n\t" \ + ".previous") +/* XXX Until we get compiler support we don't need declarations. */ +#define VAR_INT_DECL(x) + +#ifdef __mips__ +#include <tls-macros-mips.h> +#endif + +#ifdef __arm__ +#ifdef __thumb__ +#include <tls-macros-thumb.h> +#else +#include <tls-macros-arm.h> +#endif +#endif + + /* XXX Each architecture must have its own asm for now. */ +#ifdef __i386__ +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl $" #x "@tpoff,%0" \ + : "=r" (__l)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l)); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l, __b; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l), "=&b" (__b)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l, __b, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l, __b, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +#elif defined __x86_64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "leaq " #x "@tpoff(%0), %0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "addq " #x "@gottpoff(%%rip),%0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leaq " #x "@tlsld(%%rip),%%rdi\n\t" \ + "call __tls_get_addr@plt\n\t" \ + "leaq " #x "@dtpoff(%%rax), %%rax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ (".byte 0x66\n\t" \ + "leaq " #x "@tlsgd(%%rip),%%rdi\n\t" \ + ".word 0x6666\n\t" \ + "rex64\n\t" \ + "call __tls_get_addr@plt" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +#elif defined __sh__ + +# define TLS_LE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("stc gbr,%1\n\t" \ + "mov.l 1f,%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp) : "r" (__gp) : "r0"); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "2: mov.l @r15+,r12" \ + : "=r" (__l), "=r" (__tp) : : "r0"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "3:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "3: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +#elif defined __alpha__ + +register void *__gp __asm__("$29"); + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("call_pal 158\n\tlda $0," #x "($0)\t\t!tprel" : "=v"(__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ char *__tp; unsigned long __o; \ + __asm__ ("call_pal 158\n\tldq %1," #x "($gp)\t\t!gottprel" \ + : "=v"(__tp), "=r"(__o) : "r"(__gp)); \ + (int *)(__tp + __o); }) + +# define TLS_LD(x) \ + ({ extern void *__tls_get_addr(void *); int *__l; void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsldm" : "=r" (__i) : "r"(__gp)); \ + __i = __tls_get_addr(__i); \ + __asm__ ("lda %0, " #x "(%1)\t\t!dtprel" : "=r"(__l) : "r"(__i)); \ + __l; }) + +# define TLS_GD(x) \ + ({ extern void *__tls_get_addr(void *); void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsgd" : "=r" (__i) : "r"(__gp)); \ + (int *) __tls_get_addr(__i); }) + + +#elif defined __ia64__ + +# define TLS_LE(x) \ + ({ void *__l; \ + __asm__ ("mov r2=r13\n\t" \ + ";;\n\t" \ + "addl %0=@tprel(" #x "),r2\n\t" \ + : "=r" (__l) : : "r2" ); __l; }) + +# define TLS_IE(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 r17=[r16]\n\t" \ + ";;\n\t" \ + "add %0=r13,r17\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "r16", "r17" ); __l; }) + +# define __TLS_CALL_CLOBBERS \ + "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17", \ + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", \ + "r27", "r28", "r29", "r30", "r31", \ + "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \ + "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "b6", "b7", \ + "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" + +# define TLS_LD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl out1=@dtprel(" #x "),r0\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +# define TLS_GD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "ld8 out1=[r17]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +#elif defined __sparc__ && !defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ register long pc __asm__ ("%o7"); \ + long got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "call .+8\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ld [%1 + %2], %0, %%tie_ld(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __sparc__ && defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ long pc, got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "rd %%pc, %0\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ldx [%1 + %2], %0, %%tie_ldx(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __s390x__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@ntpoff\n" \ + "1:\tlg %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@gotntpoff\n" \ + "1:\tlg %0,0(%0)\n\t" \ + "lg %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@indntpoff\n" \ + "1:\t lg %0,0(%0)\n\t" \ + "lg %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __s390__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@ntpoff\n" \ + "1:\tl %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@gotntpoff\n" \ + "1:\tl %0,0(%0)\n\t" \ + "l %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@indntpoff\n" \ + "1:\t l %0,0(%0)\n\t" \ + "l %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __powerpc__ && !defined __powerpc64__ + +#include "config.h" + +# define __TLS_CALL_CLOBBERS \ + "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", \ + "lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7" + +/* PowerPC32 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int *__result; \ + __asm__ ("addi %0,2," #x "@tprel" \ + : "=r" (__result)); \ + __result; }) + +/* PowerPC32 Initial Exec TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr %0\n\t" \ + "addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# else +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr %0\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# endif + +/* PowerPC32 Local Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +/* PowerPC32 General Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +#elif defined __powerpc__ && defined __powerpc64__ + +/* PowerPC64 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int * __result; \ + __asm__ ( \ + " addis %0,13," #x "@tprel@ha\n" \ + " addi %0,%0," #x "@tprel@l\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Initial Exec TLS access. */ +# define TLS_IE(x) \ + ({ int * __result; \ + __asm__ ( \ + " ld %0," #x "@got@tprel(2)\n" \ + " add %0,%0," #x "@tls\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Local Dynamic TLS access. */ +# define TLS_LD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsld\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " addis %0,3," #x "@dtprel@ha\n" \ + " addi %0,%0," #x "@dtprel@l\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) +/* PowerPC64 General Dynamic TLS access. */ +# define TLS_GD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsgd\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " mr %0,3\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) + +#elif !defined TLS_LE || !defined TLS_IE \ + || !defined TLS_LD || !defined TLS_GD +# error "No support for this architecture so far." +#endif diff --git a/test/tls/tst-tls1-static.c b/test/tls/tst-tls1-static.c new file mode 100644 index 000000000..a01008073 --- /dev/null +++ b/test/tls/tst-tls1-static.c @@ -0,0 +1 @@ +#include "tst-tls1.c" diff --git a/test/tls/tst-tls1.c b/test/tls/tst-tls1.c new file mode 100644 index 000000000..f5ac6d2bc --- /dev/null +++ b/test/tls/tst-tls1.c @@ -0,0 +1,92 @@ +/* glibc test for TLS in ld.so. */ +#undef _LIBC +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two common 'int' variables in TLS. */ +COMMON_INT_DEF(foo); +COMMON_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls10.c b/test/tls/tst-tls10.c new file mode 100644 index 000000000..fc0677072 --- /dev/null +++ b/test/tls/tst-tls10.c @@ -0,0 +1,40 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A local = { 1, 2, 3 }; +#endif + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ + struct A *p; + if (local.a != 1 || local.b != 2 || local.c != 3) + abort (); +#ifdef USE_TLS__THREAD + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + check1 (); + check2 (); + if (f1a () != &a1 || f2a () != &a2 || f3a () != &a3 || f4a () != &a4) + abort (); + CHECK (5, 16); + CHECK (6, 19); + if (f7a () != &a2 || f8a () != &a4) + abort (); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls10.h b/test/tls/tst-tls10.h new file mode 100644 index 000000000..1be6adc29 --- /dev/null +++ b/test/tls/tst-tls10.h @@ -0,0 +1,38 @@ +#include <tls.h> +#include <stdlib.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +# define USE_TLS__THREAD + +struct A +{ + char a; + int b; + long long c; +}; + +extern __thread struct A a1, a2, a3, a4; +extern struct A *f1a (void); +extern struct A *f2a (void); +extern struct A *f3a (void); +extern struct A *f4a (void); +extern struct A *f5a (void); +extern struct A *f6a (void); +extern struct A *f7a (void); +extern struct A *f8a (void); +extern struct A *f9a (void); +extern struct A *f10a (void); +extern int f1b (void); +extern int f2b (void); +extern int f3b (void); +extern int f4b (void); +extern int f5b (void); +extern int f6b (void); +extern int f7b (void); +extern int f8b (void); +extern int f9b (void); +extern int f10b (void); +extern void check1 (void); +extern void check2 (void); +#endif diff --git a/test/tls/tst-tls11.c b/test/tls/tst-tls11.c new file mode 100644 index 000000000..816cf5cc2 --- /dev/null +++ b/test/tls/tst-tls11.c @@ -0,0 +1,27 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + check2 (); + CHECK (1, 4); + CHECK (2, 22); + CHECK (3, 10); + CHECK (4, 25); + CHECK (5, 16); + CHECK (6, 19); + CHECK (7, 22); + CHECK (8, 25); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls12.c b/test/tls/tst-tls12.c new file mode 100644 index 000000000..84aa7d35c --- /dev/null +++ b/test/tls/tst-tls12.c @@ -0,0 +1,18 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = &a##N; \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + CHECK (1, 4); + CHECK (2, 7); +#endif + exit (0); +} diff --git a/test/tls/tst-tls13.c b/test/tls/tst-tls13.c new file mode 100644 index 000000000..55fb62e54 --- /dev/null +++ b/test/tls/tst-tls13.c @@ -0,0 +1,30 @@ +/* Check unloading modules with data in static TLS block. */ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + + +static int +do_test (void) +{ + int i; + for (i = 0; i < 1000;) + { + printf ("round %d\n",++i); + + void *h = dlopen ("tst-tlsmod13a.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot load: %s\n", dlerror ()); + exit (1); + } + + dlclose (h); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls14.c b/test/tls/tst-tls14.c new file mode 100644 index 000000000..428fd5293 --- /dev/null +++ b/test/tls/tst-tls14.c @@ -0,0 +1,66 @@ +/* Check alignment of TLS variable. */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +extern int in_dso1 (void); + + +static int +do_test (void) +{ + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + result |= in_dso1 (); + + void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open tst-tlsmod14b.so: %m\n"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2"); + if (fp == NULL) + { + puts ("cannot find in_dso2"); + exit (1); + } + + result |= fp (); + + return result; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls15.c b/test/tls/tst-tls15.c new file mode 100644 index 000000000..2c2df251b --- /dev/null +++ b/test/tls/tst-tls15.c @@ -0,0 +1,33 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW); + if (h != NULL) + { + puts ("unexpectedly succeeded to open tst-tlsmod15a.so"); + exit (1); + } + + h = dlopen ("tst-tlsmod15b.so", RTLD_NOW); + if (h == NULL) + { + puts ("failed to open tst-tlsmod15b.so"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso"); + if (fp == NULL) + { + puts ("cannot find in_dso"); + exit (1); + } + + return fp (); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls16.c b/test/tls/tst-tls16.c new file mode 100644 index 000000000..53aece181 --- /dev/null +++ b/test/tls/tst-tls16.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <stdlib.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +extern __thread int tls_var; +#endif + +int main(void) +{ + int ret = EXIT_SUCCESS; +#ifdef USE_TLS + if (tls_var != TLS_VAR_INIT_VALUE) { + printf("tls_var = %d - Expected value = %d\n", tls_var, TLS_VAR_INIT_VALUE); + ret = EXIT_FAILURE; + } +#endif + return ret; +} diff --git a/test/tls/tst-tls2-static.c b/test/tls/tst-tls2-static.c new file mode 100644 index 000000000..55ffa5744 --- /dev/null +++ b/test/tls/tst-tls2-static.c @@ -0,0 +1 @@ +#include "tst-tls2.c" diff --git a/test/tls/tst-tls2.c b/test/tls/tst-tls2.c new file mode 100644 index 000000000..417489968 --- /dev/null +++ b/test/tls/tst-tls2.c @@ -0,0 +1,91 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two 'int' variables in TLS. */ +VAR_INT_DEF(foo); +VAR_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls3.c b/test/tls/tst-tls3.c new file mode 100644 index 000000000..84be43575 --- /dev/null +++ b/test/tls/tst-tls3.c @@ -0,0 +1,76 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DECL(foo); +VAR_INT_DECL(bar); +VAR_INT_DEF(baz); +#endif + + +extern int in_dso (void); + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp, *cp; + + + /* Set the variable using the local exec model. */ + puts ("set baz to 3 (LE)"); + ap = TLS_LE (baz); + *ap = 3; + + + /* Get variables using initial exec model. */ + puts ("set variables foo and bar (IE)"); + ap = TLS_IE (foo); + *ap = 1; + bp = TLS_IE (bar); + *bp = 2; + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo, bar (GD) and baz (LD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_LD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } + + + result |= in_dso (); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls4.c b/test/tls/tst-tls4.c new file mode 100644 index 000000000..f92ee53ce --- /dev/null +++ b/test/tls/tst-tls4.c @@ -0,0 +1,56 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (0, NULL); + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls5.c b/test/tls/tst-tls5.c new file mode 100644 index 000000000..a571d2cd3 --- /dev/null +++ b/test/tls/tst-tls5.c @@ -0,0 +1,72 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls6.c b/test/tls/tst-tls6.c new file mode 100644 index 000000000..e692aca6b --- /dev/null +++ b/test/tls/tst-tls6.c @@ -0,0 +1,108 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != modid) + { + printf ("round %d: modid now %zd, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42 + i; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42 + i, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls7.c b/test/tls/tst-tls7.c new file mode 100644 index 000000000..41da2708d --- /dev/null +++ b/test/tls/tst-tls7.c @@ -0,0 +1,79 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod3.so"; + int result = 0; + int (*fp) (void); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + fp = dlsym (h, "in_dso2"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso2': %s\n", dlerror ()); + exit (1); + } + + result |= fp (); + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls8.c b/test/tls/tst-tls8.c new file mode 100644 index 000000000..2541609f1 --- /dev/null +++ b/test/tls/tst-tls8.c @@ -0,0 +1,230 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod3.so"; + static const char modname2[] = "tst-tlsmod4.so"; + int result = 0; + int (*fp1) (void); + int (*fp2) (int, int *); + void *h1; + void *h2; + int i; + size_t modid1 = (size_t) -1; + size_t modid2 = (size_t) -1; + int *bazp; + + for (i = 0; i < 10; ++i) + { + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 42 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (42 + i, bazp); + + dlclose (h1); + dlclose (h2); + + + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 62 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (62 + i, bazp); + + /* This time the dlclose calls are in reverse order. */ + dlclose (h2); + dlclose (h1); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls9-static.c b/test/tls/tst-tls9-static.c new file mode 100644 index 000000000..51812ccc7 --- /dev/null +++ b/test/tls/tst-tls9-static.c @@ -0,0 +1 @@ +#include "tst-tls9.c" diff --git a/test/tls/tst-tls9.c b/test/tls/tst-tls9.c new file mode 100644 index 000000000..e317696df --- /dev/null +++ b/test/tls/tst-tls9.c @@ -0,0 +1,42 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <link.h> +#include <tls.h> + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod5.so"; + static const char modname2[] = "tst-tlsmod6.so"; + int result = 0; + + void *h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + result = 1; + } + void *h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + result = 1; + } + + if (h1 != NULL) + dlclose (h1); + if (h2 != NULL) + dlclose (h2); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tlsmod1.c b/test/tls/tst-tlsmod1.c new file mode 100644 index 000000000..b4954ca3e --- /dev/null +++ b/test/tls/tst-tlsmod1.c @@ -0,0 +1,68 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DEF(foo); +VAR_INT_DEF(bar); +VAR_INT_DECL(baz); +#endif + +extern int in_dso (void); + +int +in_dso (void) +{ + int result = 0; +#ifdef USE_TLS + int *ap, *bp, *cp; + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + __asm__ ("" ::: "memory"); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 3; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar and baz (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_GD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } +#endif + + return result; +} diff --git a/test/tls/tst-tlsmod10.c b/test/tls/tst-tlsmod10.c new file mode 100644 index 000000000..32e54f3c0 --- /dev/null +++ b/test/tls/tst-tlsmod10.c @@ -0,0 +1 @@ +#include "tst-tlsmod8.c" diff --git a/test/tls/tst-tlsmod11.c b/test/tls/tst-tlsmod11.c new file mode 100644 index 000000000..9938b5753 --- /dev/null +++ b/test/tls/tst-tlsmod11.c @@ -0,0 +1,6 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +#endif diff --git a/test/tls/tst-tlsmod12.c b/test/tls/tst-tlsmod12.c new file mode 100644 index 000000000..4602709a1 --- /dev/null +++ b/test/tls/tst-tlsmod12.c @@ -0,0 +1,14 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +extern __thread struct A a2 __attribute__((tls_model("initial-exec"))); + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 7 || a2.b != 8 || a2.c != 9) + abort (); +} +#endif diff --git a/test/tls/tst-tlsmod13.c b/test/tls/tst-tlsmod13.c new file mode 100644 index 000000000..beca89f6f --- /dev/null +++ b/test/tls/tst-tlsmod13.c @@ -0,0 +1,14 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int a[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int a[2]; +#endif + +int +foo (void) +{ + return a[0]; +} diff --git a/test/tls/tst-tlsmod13a.c b/test/tls/tst-tlsmod13a.c new file mode 100644 index 000000000..14b12b032 --- /dev/null +++ b/test/tls/tst-tlsmod13a.c @@ -0,0 +1,16 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int b[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int b[2]; +#endif + +extern int foo (void); + +int +bar (void) +{ + return foo () + b[0]; +} diff --git a/test/tls/tst-tlsmod14a.c b/test/tls/tst-tlsmod14a.c new file mode 100644 index 000000000..0bb393d9c --- /dev/null +++ b/test/tls/tst-tlsmod14a.c @@ -0,0 +1,41 @@ +#include <stdint.h> +#include <stdio.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +#ifndef FCT +# define FCT in_dso1 +#endif + + +int +FCT (void) +{ + puts (__func__); + + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + return result; +} + +#endif diff --git a/test/tls/tst-tlsmod14b.c b/test/tls/tst-tlsmod14b.c new file mode 100644 index 000000000..24d9ceaf7 --- /dev/null +++ b/test/tls/tst-tlsmod14b.c @@ -0,0 +1,2 @@ +#define FCT in_dso2 +#include "tst-tlsmod14a.c" diff --git a/test/tls/tst-tlsmod15a.c b/test/tls/tst-tlsmod15a.c new file mode 100644 index 000000000..66c707129 --- /dev/null +++ b/test/tls/tst-tlsmod15a.c @@ -0,0 +1,6 @@ +extern int nonexistent_dummy_var; +int * +foo (void) +{ + return &nonexistent_dummy_var; +} diff --git a/test/tls/tst-tlsmod15b.c b/test/tls/tst-tlsmod15b.c new file mode 100644 index 000000000..4f63eab14 --- /dev/null +++ b/test/tls/tst-tlsmod15b.c @@ -0,0 +1,17 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int mod15b_var __attribute__((tls_model("initial-exec"))); + +int +in_dso (void) +{ + return mod15b_var; +} +#else +int +in_dso (void) +{ + return 0; +} +#endif diff --git a/test/tls/tst-tlsmod16.c b/test/tls/tst-tlsmod16.c new file mode 100644 index 000000000..bd04b5081 --- /dev/null +++ b/test/tls/tst-tlsmod16.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +__thread int tls_var __attribute__((tls_model("global-dynamic"))); +static __thread int local_tls_var __attribute__((tls_model("local-dynamic"))); +#endif + +void __attribute__((constructor)) libtls_ctor(void); +void libtls_ctor(void) +{ + printf("libtls: constructor!\n"); +#ifdef USE_TLS + local_tls_var = TLS_VAR_INIT_VALUE; + tls_var = local_tls_var; +#endif +} + +void __attribute__((destructor)) libtls_dtor(void); +void libtls_dtor(void) +{ + printf("libtls: destructor!\n"); +} diff --git a/test/tls/tst-tlsmod2.c b/test/tls/tst-tlsmod2.c new file mode 100644 index 000000000..4547c9716 --- /dev/null +++ b/test/tls/tst-tlsmod2.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +COMMON_INT_DEF(foo); + + +int +in_dso (int n, int *caller_foop) +{ + int *foop; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + + if (caller_foop != NULL && foop != caller_foop) + { + printf ("callers address of foo differs: %p vs %p\n", caller_foop, foop); + result = 1; + } + else if (*foop != n) + { + printf ("foo != %d\n", n); + result = 1; + } + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod3.c b/test/tls/tst-tlsmod3.c new file mode 100644 index 000000000..12505f623 --- /dev/null +++ b/test/tls/tst-tlsmod3.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + +extern int in_dso (int n, int *caller_foop); + +COMMON_INT_DEF(comm_n); + + + + +int +in_dso2 (void) +{ + int *foop; + int result = 0; + static int n; + int *np; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + np = TLS_GD (comm_n); + + if (n != *np) + { + printf ("n = %d != comm_n = %d\n", n, *np); + result = 1; + } + + result |= in_dso (*foop = 42 + n++, foop); + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod4.c b/test/tls/tst-tlsmod4.c new file mode 100644 index 000000000..4893cdae7 --- /dev/null +++ b/test/tls/tst-tlsmod4.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +COMMON_INT_DEF(baz); + + +int +in_dso (int n, int *caller_bazp) +{ + int *bazp; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + bazp = TLS_GD (baz); + + if (caller_bazp != NULL && bazp != caller_bazp) + { + printf ("callers address of baz differs: %p vs %p\n", caller_bazp, bazp); + result = 1; + } + else if (*bazp != n) + { + printf ("baz != %d\n", n); + result = 1; + } + + *bazp = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod5.c b/test/tls/tst-tlsmod5.c new file mode 100644 index 000000000..2ec69e13b --- /dev/null +++ b/test/tls/tst-tlsmod5.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(foo); +#endif diff --git a/test/tls/tst-tlsmod6.c b/test/tls/tst-tlsmod6.c new file mode 100644 index 000000000..0fda51b22 --- /dev/null +++ b/test/tls/tst-tlsmod6.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(bar); +#endif diff --git a/test/tls/tst-tlsmod7.c b/test/tls/tst-tlsmod7.c new file mode 100644 index 000000000..944b97f9c --- /dev/null +++ b/test/tls/tst-tlsmod7.c @@ -0,0 +1,103 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 13, 14, 15 }; +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod8.c b/test/tls/tst-tlsmod8.c new file mode 100644 index 000000000..c1822fc0c --- /dev/null +++ b/test/tls/tst-tlsmod8.c @@ -0,0 +1,72 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread long long dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a2 = { 22, 23, 24 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 25, 26, 27 }; +static __thread struct A local1 = { 28, 29, 30 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 31, 32, 33 }; + +void +check2 (void) +{ + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 28 || local1.b != 29 || local1.c != 30) + abort (); + if (local2.a != 31 || local2.b != 32 || local2.c != 33) + abort (); +} + +struct A * +f7a (void) +{ + return &a2; +} + +struct A * +f8a (void) +{ + return &a4; +} + +struct A * +f9a (void) +{ + return &local1; +} + +struct A * +f10a (void) +{ + return &local2; +} + +int +f7b (void) +{ + return a2.b; +} + +int +f8b (void) +{ + return a4.a; +} + +int +f9b (void) +{ + return local1.b; +} + +int +f10b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod9.c b/test/tls/tst-tlsmod9.c new file mode 100644 index 000000000..e124144e4 --- /dev/null +++ b/test/tls/tst-tlsmod9.c @@ -0,0 +1,101 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +extern __thread struct A a4 __attribute__((tls_model("initial-exec"))); +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif |