mirror of
git://sourceware.org/git/glibc.git
synced 2025-04-06 14:10:30 +08:00
Updated to fedora-glibc-20050708T0811
This commit is contained in:
parent
03d65262fd
commit
48f006fc65
124
ChangeLog
124
ChangeLog
@ -1,3 +1,127 @@
|
||||
2005-07-07 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* resolv/res_send.c (send_dg): Recognize referral results and
|
||||
treat them as server errors.
|
||||
Based on a patch by Jason Vas Dias <jvdias@redhat.com>.
|
||||
|
||||
2005-07-08 Carlos O'Donell <carlos@systemhalted.org>
|
||||
|
||||
* sysdeps/hppa/setjmp.S (__sigsetjmp): Use %r1 not %r19.
|
||||
|
||||
* sysdeps/hppa/add_n.s (__mpn_add_n): Use sr0 or r0, not 0.
|
||||
* sysdeps/hppa/lshift.s (__mpn_lshift): Likewise.
|
||||
* sysdeps/hppa/rshift.s (__mpn_rshift): Likewise.
|
||||
* sysdeps/hppa/sub_n.s (__mpn_sub_n): Likewise.
|
||||
* sysdeps/hppa/udiv_qrnnd.s (__udiv_qrnnd): Likewise.
|
||||
* sysdeps/hppa/hppa1.1/udiv_qrnnd.s (__udiv_qrnnd): Likewise.
|
||||
|
||||
2005-07-07 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/generic/s_ctanh.c (__ctanh): Handle case of zero den better.
|
||||
* sysdeps/generic/s_ctanhf.c (__ctanhf): Likewise.
|
||||
* sysdeps/generic/s_ctanhl.c (__ctanhl): Likewise.
|
||||
* sysdeps/generic/s_ctan.c (__ctan): Likewise.
|
||||
* sysdeps/generic/s_ctanf.c (__ctanf): Likewise.
|
||||
* sysdeps/generic/s_ctanl.c (__ctanl): Likewise.
|
||||
|
||||
2005-04-13 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #974]
|
||||
* csu/elf-init.c (__preinit_array_start): Take int, char **, char **.
|
||||
(__preinit_array_end): Likewise.
|
||||
(__init_array_start): Likewise.
|
||||
(__init_array_end): Likewise.
|
||||
(__libc_csu_init): Take int argc, char **argv, char **envp.
|
||||
Call preinit_array and init_array with argc, argv, envp.
|
||||
* sysdeps/generic/libc-start.c (LIBC_START_MAIN): Remove
|
||||
INIT_MAIN_ARGS.
|
||||
* sysdeps/powerpc/elf/libc-start.c (INIT_MAIN_ARGS): Removed.
|
||||
* elf/Makefile (distribute): Add tst-array5.c, tst-array5-static.c,
|
||||
tst-array5dep.c, and tst-array5.exp.
|
||||
(tests): Add tst-array5.
|
||||
(tests-static): Add tst-array5-static.
|
||||
($(objpfx)tst-array5): New target.
|
||||
($(objpfx)tst-array5.out): Likewise.
|
||||
($(objpfx)tst-array5-static.out): Likewise.
|
||||
* elf/tst-array5-static.c: New file.
|
||||
* elf/tst-array5-static.exp: Likewise.
|
||||
* elf/tst-array5.c: Likewise.
|
||||
* elf/tst-array5.exp: Likewise.
|
||||
* elf/tst-array5dep.c: Likewise.
|
||||
|
||||
2005-07-07 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/bits/sched.h: Adjust clone prototype.
|
||||
|
||||
2005-07-05 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* elf/stackguard-macros.h (STACK_CHK_GUARD): Fix s390/s390x definition.
|
||||
Reported by Ulrich Weigand <uweigand@de.ibm.com>.
|
||||
|
||||
* elf/stackguard-macros.h (STACK_CHK_GUARD): Add ia64 definition.
|
||||
|
||||
2005-07-06 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/dl-error.c (_dl_signal_error): When testing for executable
|
||||
being relocated, take into account that nothing might even be loaded.
|
||||
|
||||
* elf/dl-reloc.c [PROF] (_dl_relocate_object): Define
|
||||
consider_profiling always to zero. Don't count of compiler to
|
||||
remove unreached if block.
|
||||
* sysdeps/x86_64/dl-trampoline.S [PROF] (_dl_runtime_profile):
|
||||
Don't compile.
|
||||
* sysdeps/i386/dl-trampoline.S [PROF] (_dl_runtime_profile): Likewise.
|
||||
* sysdeps/ia64/dl-trampoline.S [PROF] (_dl_runtime_profile): Likewise.
|
||||
* sysdeps/s390/s390-64/dl-trampoline.S [PROF] (_dl_runtime_profile):
|
||||
Likewise.
|
||||
* sysdeps/s390/s390-32/dl-trampoline.S [PROF] (_dl_runtime_profile):
|
||||
Likewise.
|
||||
* sysdeps/powerpc/powerpc64/dl-trampoline.S [PROF]
|
||||
(_dl_profile_resolve): Likewise.
|
||||
* sysdeps/powerpc/powerpc32/dl-trampoline.S [PROF]
|
||||
(_dl_profile_resolve): Likewise.
|
||||
* gmon/Makefile: Add rules to build and run tst-profile-static.
|
||||
* gmon/tst-profile-static.c: New file.
|
||||
* Makeconfig (+link-static): Allow passing program-specific flags.
|
||||
|
||||
2005-07-05 Thorsten Kukuk <kukuk@suse.de>
|
||||
|
||||
* nis/nss_compat/compat-grp.c (internal_getgrgid_r): Check if NSS
|
||||
module provides getgrgid_r.
|
||||
(getgrnam_plusgroup): Preserve original return value.
|
||||
* nis/nss_compat/compat-pwd.c (getpwnam_plususer): Preserve
|
||||
original return value.
|
||||
* nis/nss_compat/compat-spwd.c (getspnam_plususer): Likewise.
|
||||
|
||||
2005-07-05 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* posix/regex_internal.c (build_wcs_buffer): Use MB_LEN_MAX not
|
||||
MB_CUR_MAX.
|
||||
(build_wcs_upper_buffer): Likewise.
|
||||
|
||||
* csu/elf-init.c (__libc_csu_fini): Pretty printing.
|
||||
|
||||
2005-07-02 Roland McGrath <roland@redhat.com>
|
||||
|
||||
* NEWS: Note LinuxThreads removal.
|
||||
* manual/install.texi (Installation): Don't mention linuxthreads.
|
||||
(Configuring and compiling): Don't use linuxthreads as example.
|
||||
|
||||
* sysdeps/unix/sysv/linux/configure.in: Check for nptl add-on only,
|
||||
not linuxthreads.
|
||||
* sysdeps/unix/sysv/linux/configure: Regenerated.
|
||||
* resolv/Depend: Add nptl.
|
||||
* rt/Depend: Likewise.
|
||||
|
||||
* linuxthreads, linuxthreads_db: Directories removed (preserved in
|
||||
ports repository).
|
||||
|
||||
2005-06-27 Jakub Jelinek <jj@ultra.linux.cz>
|
||||
|
||||
[BZ #1037]
|
||||
* sysdeps/unix/sysv/linux/sparc/sparc32/Makefile: -mv8 is deprecated,
|
||||
use -mcpu=v8.
|
||||
|
||||
2005-06-16 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
[BZ #1016]
|
||||
|
@ -415,7 +415,7 @@ endif
|
||||
# Command for statically linking programs with the C library.
|
||||
ifndef +link-static
|
||||
+link-static = $(CC) -nostdlib -nostartfiles -static -o $@ \
|
||||
$(sysdep-LDFLAGS) $(LDFLAGS) \
|
||||
$(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
|
||||
$(addprefix $(csu-objpfx),$(static-start-installed-name)) \
|
||||
$(+preinit) $(+prector) \
|
||||
$(filter-out $(addprefix $(csu-objpfx),start.o \
|
||||
|
5
NEWS
5
NEWS
@ -14,6 +14,11 @@ Version 2.4
|
||||
|
||||
* It is now possible to install audit libraries for the dynamic linker using
|
||||
LD_AUDIT. Implemented by Ulrich Drepper.
|
||||
|
||||
* The LinuxThreads add-on, providing pthreads on Linux 2.4 kernels, is no
|
||||
longer supported. The new NPTL implementation requires Linux 2.6 kernels.
|
||||
For a libc and libpthread that works well on Linux 2.4 kernels, we
|
||||
recommend using the stable 2.3 branch.
|
||||
|
||||
Version 2.3.5
|
||||
|
||||
|
@ -38,10 +38,14 @@
|
||||
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
/* These magic symbols are provided by the linker. */
|
||||
extern void (*__preinit_array_start []) (void) attribute_hidden;
|
||||
extern void (*__preinit_array_end []) (void) attribute_hidden;
|
||||
extern void (*__init_array_start []) (void) attribute_hidden;
|
||||
extern void (*__init_array_end []) (void) attribute_hidden;
|
||||
extern void (*__preinit_array_start []) (int, char **, char **)
|
||||
attribute_hidden;
|
||||
extern void (*__preinit_array_end []) (int, char **, char **)
|
||||
attribute_hidden;
|
||||
extern void (*__init_array_start []) (int, char **, char **)
|
||||
attribute_hidden;
|
||||
extern void (*__init_array_end []) (int, char **, char **)
|
||||
attribute_hidden;
|
||||
extern void (*__fini_array_start []) (void) attribute_hidden;
|
||||
extern void (*__fini_array_end []) (void) attribute_hidden;
|
||||
|
||||
@ -75,7 +79,7 @@ extern void _fini (void);
|
||||
the libc.a module in that it doesn't call the preinit array. */
|
||||
|
||||
void
|
||||
__libc_csu_init (void)
|
||||
__libc_csu_init (int argc, char **argv, char **envp)
|
||||
{
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
/* For dynamically linked executables the preinit array is executed by
|
||||
@ -87,7 +91,7 @@ __libc_csu_init (void)
|
||||
const size_t size = __preinit_array_end - __preinit_array_start;
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++)
|
||||
(*__preinit_array_start [i]) ();
|
||||
(*__preinit_array_start [i]) (argc, argv, envp);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
@ -99,7 +103,7 @@ __libc_csu_init (void)
|
||||
const size_t size = __init_array_end - __init_array_start;
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++)
|
||||
(*__init_array_start [i]) ();
|
||||
(*__init_array_start [i]) (argc, argv, envp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -111,11 +115,11 @@ void
|
||||
__libc_csu_fini (void)
|
||||
{
|
||||
#ifndef LIBC_NONSHARED
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
# ifdef HAVE_INITFINI_ARRAY
|
||||
size_t i = __fini_array_end - __fini_array_start;
|
||||
while (i-- > 0)
|
||||
(*__fini_array_start [i]) ();
|
||||
#endif
|
||||
# endif
|
||||
|
||||
_fini ();
|
||||
#endif
|
||||
|
21
elf/Makefile
21
elf/Makefile
@ -88,7 +88,9 @@ distribute := rtld-Rules \
|
||||
unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
|
||||
unload6mod1.c unload6mod2.c unload6mod3.c tst-auditmod1.c \
|
||||
order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
|
||||
tst-stackguard1.c tst-stackguard1-static.c
|
||||
tst-stackguard1.c tst-stackguard1-static.c \
|
||||
tst-array5.c tst-array5-static.c tst-array5dep.c \
|
||||
tst-array5.exp
|
||||
|
||||
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
|
||||
@ -138,7 +140,7 @@ endif
|
||||
|
||||
tests = tst-tls1 tst-tls2 tst-tls9
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
tests += tst-array1 tst-array2 tst-array3 tst-array4
|
||||
tests += tst-array1 tst-array2 tst-array3 tst-array4 tst-array5
|
||||
endif
|
||||
ifeq (yes,$(build-static))
|
||||
tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static
|
||||
@ -148,7 +150,7 @@ tst-tls9-static-ENV = \
|
||||
LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn
|
||||
endif
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
tests-static += tst-array1-static
|
||||
tests-static += tst-array1-static tst-array5-static
|
||||
endif
|
||||
tests += $(tests-static)
|
||||
endif
|
||||
@ -206,7 +208,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
unload6mod1 unload6mod2 unload6mod3 \
|
||||
order2mod1 order2mod2 order2mod3 order2mod4
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
modules-names += tst-array2dep
|
||||
modules-names += tst-array2dep tst-array5dep
|
||||
endif
|
||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||
modules-names += tst-piemod1
|
||||
@ -767,6 +769,17 @@ $(objpfx)tst-array4.out: $(objpfx)tst-array4 $(objpfx)tst-array2dep.so
|
||||
$< > $@
|
||||
cmp $@ tst-array4.exp > /dev/null
|
||||
|
||||
$(objpfx)tst-array5: $(objpfx)tst-array5dep.so
|
||||
$(objpfx)tst-array5.out: $(objpfx)tst-array5
|
||||
$(elf-objpfx)$(rtld-installed-name) \
|
||||
--library-path $(rpath-link)$(patsubst %,:%,$(sysdep-library-path)) \
|
||||
$(objpfx)tst-array5 > $@
|
||||
cmp $@ tst-array5.exp > /dev/null
|
||||
|
||||
$(objpfx)tst-array5-static.out: $(objpfx)tst-array5-static
|
||||
$(objpfx)tst-array5-static > $@
|
||||
cmp $@ tst-array5-static.exp > /dev/null
|
||||
|
||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||
CFLAGS-tst-pie1.c += -fpie
|
||||
|
||||
|
@ -98,8 +98,9 @@ _dl_signal_error (int errcode, const char *objname, const char *occation,
|
||||
/* If the main executable is relocated it means the libc's malloc
|
||||
is used. */
|
||||
#ifdef SHARED
|
||||
lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated
|
||||
!= 0);
|
||||
lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
|
||||
&& (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated
|
||||
!= 0));
|
||||
#else
|
||||
lcatch->malloced = true;
|
||||
#endif
|
||||
|
@ -153,6 +153,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
#ifdef SHARED
|
||||
/* If we are auditing, install the same handlers we need for profiling. */
|
||||
consider_profiling |= GLRO(dl_audit) != NULL;
|
||||
#elif defined PROF
|
||||
/* Never use dynamic linker profiling for gprof profiling code. */
|
||||
# define consider_profiling 0
|
||||
#endif
|
||||
|
||||
if (l->l_relocated)
|
||||
@ -264,6 +267,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
|
||||
ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);
|
||||
|
||||
#ifndef PROF
|
||||
if (__builtin_expect (consider_profiling, 0))
|
||||
{
|
||||
/* Allocate the array which will contain the already found
|
||||
@ -288,6 +292,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
goto fatal;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Mark the object so we know this work has been done. */
|
||||
|
@ -20,10 +20,13 @@
|
||||
({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; })
|
||||
#elif defined __s390x__
|
||||
# define STACK_CHK_GUARD \
|
||||
({ uintptr_t x; asm ("ear %0,%a0; sllg %0,%0,32; ear %0,%a1; lg %0,0x28(%0)" : "=r" (x)); x; })
|
||||
({ uintptr_t x; asm ("ear %0,%%a0; sllg %0,%0,32; ear %0,%%a1; lg %0,0x28(%0)" : "=a" (x)); x; })
|
||||
#elif defined __s390__
|
||||
# define STACK_CHK_GUARD \
|
||||
({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=r" (x)); x; })
|
||||
({ uintptr_t x; asm ("ear %0,%%a0; l %0,0x14(%0)" : "=a" (x)); x; })
|
||||
#elif defined __ia64__
|
||||
# define STACK_CHK_GUARD \
|
||||
({ uintptr_t x; asm ("adds %0 = -8, r13;; ld8 %0 = [%0]" : "=r" (x)); x; })
|
||||
#else
|
||||
extern uintptr_t __stack_chk_guard;
|
||||
# define STACK_CHK_GUARD __stack_chk_guard
|
||||
|
1
elf/tst-array5-static.c
Normal file
1
elf/tst-array5-static.c
Normal file
@ -0,0 +1 @@
|
||||
#include "tst-array5.c"
|
2
elf/tst-array5-static.exp
Normal file
2
elf/tst-array5-static.exp
Normal file
@ -0,0 +1,2 @@
|
||||
preinit array in executable: tst-array5-static
|
||||
init array in executable: tst-array5-static
|
50
elf/tst-array5.c
Normal file
50
elf/tst-array5.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void
|
||||
preinit_0 (int argc __attribute__ ((unused)), char **argv)
|
||||
{
|
||||
char *p = strrchr (argv [0], '/');
|
||||
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
p++;
|
||||
size_t len = strlen (p);
|
||||
write (STDOUT_FILENO, "preinit array in executable: ", 29);
|
||||
write (STDOUT_FILENO, p, len);
|
||||
write (STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
void (*const preinit_array []) (int, char **)
|
||||
__attribute__ ((section (".preinit_array"), aligned (sizeof (void *)))) =
|
||||
{
|
||||
&preinit_0,
|
||||
};
|
||||
|
||||
static void
|
||||
init_0 (int argc __attribute__ ((unused)), char **argv)
|
||||
{
|
||||
char *p = strrchr (argv [0], '/');
|
||||
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
p++;
|
||||
size_t len = strlen (p);
|
||||
write (STDOUT_FILENO, "init array in executable: ", 26);
|
||||
write (STDOUT_FILENO, p, len);
|
||||
write (STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
void (*const init_array []) (int, char **)
|
||||
__attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
|
||||
{
|
||||
&init_0,
|
||||
};
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
3
elf/tst-array5.exp
Normal file
3
elf/tst-array5.exp
Normal file
@ -0,0 +1,3 @@
|
||||
preinit array in executable: tst-array5
|
||||
init array in DSO: tst-array5
|
||||
init array in executable: tst-array5
|
23
elf/tst-array5dep.c
Normal file
23
elf/tst-array5dep.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void
|
||||
init_0 (int argc __attribute__ ((unused)), char **argv)
|
||||
{
|
||||
char *p = strrchr (argv [0], '/');
|
||||
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
p++;
|
||||
size_t len = strlen (p);
|
||||
write (STDOUT_FILENO, "init array in DSO: ", 19);
|
||||
write (STDOUT_FILENO, p, len);
|
||||
write (STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
void (*const init_array []) (int, char **)
|
||||
__attribute__ ((section (".init_array"), aligned (sizeof (void *)))) =
|
||||
{
|
||||
&init_0,
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
# This file is updated automatically by Makefile.
|
||||
glibc-branch := fedora
|
||||
glibc-base := HEAD
|
||||
fedora-sync-date := 2005-06-27 08:50 UTC
|
||||
fedora-sync-tag := fedora-glibc-20050627T0850
|
||||
fedora-sync-date := 2005-07-08 08:11 UTC
|
||||
fedora-sync-tag := fedora-glibc-20050708T0811
|
||||
|
@ -1,4 +1,4 @@
|
||||
%define glibcrelease 1
|
||||
%define glibcrelease 2
|
||||
%define auxarches i586 i686 athlon sparcv9 alphaev6
|
||||
%define prelinkarches noarch
|
||||
%define xenarches i686 athlon
|
||||
@ -1072,6 +1072,10 @@ rm -f *.filelist*
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Jul 8 2005 Jakub Jelinek <jakub@redhat.com> 2.3.90-2
|
||||
- update from CVS
|
||||
- ia64 stack protector support
|
||||
|
||||
* Mon Jun 27 2005 Jakub Jelinek <jakub@redhat.com> 2.3.90-1
|
||||
- update from CVS
|
||||
- stack protector support
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (C) 1995, 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1995,1996,1997,2001,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
|
||||
@ -27,7 +27,15 @@ routines := gmon mcount profil sprofil bb_init_func bb_exit_func prof-freq
|
||||
|
||||
elide-routines.os = bb_init_func bb_exit_func
|
||||
|
||||
tests := tst-sprofil
|
||||
include ../Makeconfig
|
||||
|
||||
tests = tst-sprofil
|
||||
ifeq ($(build-profile),yes)
|
||||
tests += tst-profile-static
|
||||
tests-static += tst-profile-static
|
||||
|
||||
LDFLAGS-tst-profile-static = -profile
|
||||
endif
|
||||
|
||||
# The mcount code won't work without a frame pointer.
|
||||
CFLAGS-mcount.c := -fno-omit-frame-pointer
|
||||
|
10
gmon/tst-profile-static.c
Normal file
10
gmon/tst-profile-static.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdio.h>
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
puts ("Hello world");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
@ -1 +0,0 @@
|
||||
linuxthreads-0.10 by Xavier Leroy
|
File diff suppressed because it is too large
Load Diff
@ -1,85 +0,0 @@
|
||||
Release 0.9:
|
||||
- more ports (SH, IA-64, s390)
|
||||
- many bug fixes
|
||||
- timed sync object wait functions
|
||||
- barrier implementation
|
||||
- spinlocks implementation
|
||||
- thread register on x86
|
||||
- variable stack size and position on some platforms
|
||||
|
||||
Release 0.8:
|
||||
(ehmm, forgot to update, don't know anymore)
|
||||
|
||||
Release 0.7:
|
||||
- Destructors for thread-specific data now conform to the POSIX semantics
|
||||
(call destructors again if non-NULL TSD remains after a round of
|
||||
destruction).
|
||||
- Implemented thread-specific data as a sparse array, allows more TSD keys
|
||||
and smaller thread descriptors (Ulrich Drepper).
|
||||
- Added "error checking" mutexes.
|
||||
- Protect against multiple sigwait() on the same signals.
|
||||
- Simplified implementation of semaphores when compare_and_swap is
|
||||
not available.
|
||||
- Fixed bug in fork() where stdin was closed if fork() was called before
|
||||
the first pthread_create().
|
||||
- Fixed bug in the gethostby*_r functions (bad result if null bytes
|
||||
in addresses).
|
||||
- Typos in manual pages corrected.
|
||||
- First cut at a PowerPC port (not working yet, runs into problems
|
||||
with gcc and with the C library).
|
||||
|
||||
Release 0.6:
|
||||
- Validation of thread identifiers: no more crashes when operating on
|
||||
a thread that has exited (based on Pavel Krauz's ideas).
|
||||
- Added fallback implementation of semaphores for the 386 and the
|
||||
Sparc.
|
||||
- Fixed a bug in signal handling causing false restarts of suspended
|
||||
threads.
|
||||
- Fixed a bug in realtime scheduling causing all threads to have
|
||||
default scheduling on Ix86 with libc5.
|
||||
- With realtime scheduling, unlocking a mutex now restarts the
|
||||
highest priority thread waiting on the mutex, not the
|
||||
first-suspended thread (Richard Neitzel).
|
||||
- Timing a process now returns cumulative times for all threads, not
|
||||
just times for the initial thread (suggested by Wolfram Gloger).
|
||||
- Cleaned up name space (internal defs prefixed by __, weak aliases
|
||||
for non-portable extensions).
|
||||
- MIPS port (contributed by Ralf Baechle).
|
||||
|
||||
Release 0.5:
|
||||
- Signal-safe semaphores a la POSIX 1003.1b added.
|
||||
- Locking bug in pthread_mutex_trylock over recursive mutexes fixed.
|
||||
- Race conditions in thread cancellation fixed.
|
||||
- Sparc port (contributed by Miguel de Icaza).
|
||||
- Support for getpwnam_r and getpwuid_r.
|
||||
- Added pthread_kill_other_threads_np to be used in conjunction with
|
||||
exec*().
|
||||
|
||||
Release 0.4:
|
||||
- Manual pages for all functions.
|
||||
- Synchronization bug causing accumulation of zombie processes fixed.
|
||||
- Race condition in pthread_cond_timedwait fixed.
|
||||
- Recursive mutexes are back by popular demand.
|
||||
- Partial support for realtime scheduling (initiated by Richard Neitzel).
|
||||
- pthread.h cleaned up a lot: now C++ compatible, added missing "const"
|
||||
qualifiers, added short documentation, put to GNU libc standards
|
||||
for name space pollution (Ulrich Drepper).
|
||||
- Motorola 68k port (contributed by Andreas Schwab).
|
||||
- Interaction with fork(2) cleaned up a lot.
|
||||
|
||||
Release 0.3:
|
||||
- Thread creation and reclaimation now performed by a centralized
|
||||
"thread manager" thread.
|
||||
- Removed recursive mutexes to make regular mutexes more efficient.
|
||||
- Now available as a shared library (contributed by Richard Henderson).
|
||||
- Alpha port (contributed by Richard Henderson).
|
||||
- Fixed many small discrepancies with Posix 1003.1c.
|
||||
- Put under the LGPL instead of the GPL.
|
||||
|
||||
Release 0.2:
|
||||
- Reentrant libc functions (adapted from libc 5.3.9 by Peeter Joot)
|
||||
- pthread_cond_wait did not reacquire the mutex correctly on return
|
||||
- More efficient pthread_cond_broadcast
|
||||
|
||||
Release 0.1:
|
||||
- First public release
|
@ -1,15 +0,0 @@
|
||||
CC=gcc
|
||||
CFLAGS=-g -O -Wall -I.. -D_REENTRANT
|
||||
LIBPTHREAD=../libpthread.a
|
||||
|
||||
PROGS=ex1 ex2 ex3 ex4 ex5 proxy
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
.c:
|
||||
$(CC) $(CFLAGS) -o $* $*.c $(LIBPTHREAD)
|
||||
|
||||
$(PROGS):
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS)
|
@ -1,42 +0,0 @@
|
||||
/* Creates two threads, one printing 10000 "a"s, the other printing
|
||||
10000 "b"s.
|
||||
Illustrates: thread creation, thread joining. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "pthread.h"
|
||||
|
||||
static void *
|
||||
process (void *arg)
|
||||
{
|
||||
int i;
|
||||
fprintf (stderr, "Starting process %s\n", (char *) arg);
|
||||
for (i = 0; i < 10000; i++)
|
||||
{
|
||||
write (1, (char *) arg, 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int retcode;
|
||||
pthread_t th_a, th_b;
|
||||
void *retval;
|
||||
|
||||
retcode = pthread_create (&th_a, NULL, process, (void *) "a");
|
||||
if (retcode != 0)
|
||||
fprintf (stderr, "create a failed %d\n", retcode);
|
||||
retcode = pthread_create (&th_b, NULL, process, (void *) "b");
|
||||
if (retcode != 0)
|
||||
fprintf (stderr, "create b failed %d\n", retcode);
|
||||
retcode = pthread_join (th_a, &retval);
|
||||
if (retcode != 0)
|
||||
fprintf (stderr, "join a failed %d\n", retcode);
|
||||
retcode = pthread_join (th_b, &retval);
|
||||
if (retcode != 0)
|
||||
fprintf (stderr, "join b failed %d\n", retcode);
|
||||
return 0;
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/* Tests for pthread_mutex_timedlock function.
|
||||
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#define NUM_THREADS 10
|
||||
#define NUM_ITERS 50
|
||||
#define TIMEOUT_NS 100000000L
|
||||
|
||||
static void *thread (void *) __attribute__ ((__noreturn__));
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t th;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
if (pthread_create (&th, NULL, thread, NULL) != 0)
|
||||
error (EXIT_FAILURE, 0, "cannot create thread");
|
||||
}
|
||||
|
||||
(void) thread (NULL);
|
||||
/* notreached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
thread (void *arg)
|
||||
{
|
||||
int i;
|
||||
pthread_t self = pthread_self ();
|
||||
static int linecount; /* protected by flockfile(stdout) */
|
||||
|
||||
for (i = 0; i < NUM_ITERS; i++)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int err;
|
||||
|
||||
clock_gettime (CLOCK_REALTIME, &ts);
|
||||
|
||||
ts.tv_nsec += TIMEOUT_NS;
|
||||
|
||||
if (ts.tv_nsec >= 1000000000L) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= 1000000000L;
|
||||
}
|
||||
|
||||
switch ((err = pthread_mutex_timedlock (&mutex, &ts)))
|
||||
{
|
||||
case 0:
|
||||
flockfile (stdout);
|
||||
printf ("%04d: thread %lu got mutex\n", ++linecount,
|
||||
(unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
break;
|
||||
case ETIMEDOUT:
|
||||
flockfile (stdout);
|
||||
printf ("%04d: thread %lu timed out on mutex\n", ++linecount,
|
||||
(unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
continue;
|
||||
default:
|
||||
error (EXIT_FAILURE, err, "pthread_mutex_timedlock failure");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = TIMEOUT_NS;
|
||||
nanosleep (&ts, NULL);
|
||||
|
||||
flockfile (stdout);
|
||||
printf ("%04d: thread %lu releasing mutex\n", ++linecount,
|
||||
(unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
pthread_exit (NULL);
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/* Test program for timedout read/write lock functions.
|
||||
Copyright (C) 2000 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 TIMEOUT 1000000
|
||||
#define DELAY 1000000
|
||||
|
||||
static pthread_rwlock_t lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
|
||||
|
||||
|
||||
static void *
|
||||
writer_thread (void *nr)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timespec delay;
|
||||
int n;
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = TIMEOUT;
|
||||
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = DELAY;
|
||||
|
||||
for (n = 0; n < WRITETRIES; ++n)
|
||||
{
|
||||
do
|
||||
{
|
||||
clock_gettime (CLOCK_REALTIME, &ts);
|
||||
|
||||
ts.tv_nsec += 2 * TIMEOUT;
|
||||
|
||||
printf ("writer thread %ld tries again\n", (long int) nr);
|
||||
}
|
||||
//while (pthread_rwlock_wrlock (&lock), 0);
|
||||
while (pthread_rwlock_timedwrlock (&lock, &ts) == ETIMEDOUT);
|
||||
|
||||
printf ("writer thread %ld succeeded\n", (long int) nr);
|
||||
|
||||
nanosleep (&delay, NULL);
|
||||
|
||||
pthread_rwlock_unlock (&lock);
|
||||
|
||||
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)
|
||||
{
|
||||
do
|
||||
{
|
||||
clock_gettime (CLOCK_REALTIME, &ts);
|
||||
|
||||
ts.tv_nsec += TIMEOUT;
|
||||
|
||||
printf ("reader thread %ld tries again\n", (long int) nr);
|
||||
}
|
||||
//while (pthread_rwlock_rdlock (&lock), 0);
|
||||
while (pthread_rwlock_timedrdlock (&lock, &ts) == ETIMEDOUT);
|
||||
|
||||
printf ("reader thread %ld succeeded\n", (long int) nr);
|
||||
|
||||
nanosleep (&delay, NULL);
|
||||
|
||||
pthread_rwlock_unlock (&lock);
|
||||
|
||||
printf ("reader thread %ld released\n", (long int) nr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (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)
|
||||
{
|
||||
int err = pthread_create (&thwr[n], NULL, writer_thread,
|
||||
(void *) (long int) n);
|
||||
|
||||
if (err != 0)
|
||||
error (EXIT_FAILURE, err, "cannot create writer thread");
|
||||
}
|
||||
|
||||
for (n = 0; n < NREADERS; ++n)
|
||||
{
|
||||
int err = pthread_create (&thrd[n], NULL, reader_thread,
|
||||
(void *) (long int) n);
|
||||
|
||||
if (err != 0)
|
||||
error (EXIT_FAILURE, err, "cannot create reader thread");
|
||||
}
|
||||
|
||||
/* Wait for all the threads. */
|
||||
for (n = 0; n < NWRITERS; ++n)
|
||||
pthread_join (thwr[n], &res);
|
||||
for (n = 0; n < NREADERS; ++n)
|
||||
pthread_join (thrd[n], &res);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/* Variant of ex6, but this time we use pthread_exit (). */
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *
|
||||
__attribute__ ((noreturn))
|
||||
test_thread (void *v_param)
|
||||
{
|
||||
pthread_exit (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
setvbuf (stdout, NULL, _IONBF, 0);
|
||||
|
||||
for (count = 0; count < 2000; ++count)
|
||||
{
|
||||
pthread_t thread;
|
||||
int status;
|
||||
|
||||
status = pthread_create (&thread, NULL, test_thread, NULL);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("status = %d, count = %lu: %s\n", status, count,
|
||||
strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("count = %lu\n", count);
|
||||
}
|
||||
/* pthread_detach (thread); */
|
||||
if (pthread_join (thread, NULL) != 0)
|
||||
{
|
||||
printf ("join failed, count %lu\n", count);
|
||||
return 2;
|
||||
}
|
||||
usleep (10);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
/* Test for Pthreads/mutexes.
|
||||
Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kurt Garloff <garloff@suse.de>, 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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *thread_start (void *ptr) __attribute__ ((__noreturn__));
|
||||
|
||||
|
||||
struct thr_ctrl
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int retval;
|
||||
};
|
||||
|
||||
static void
|
||||
dump_mut (pthread_mutex_t * mut)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof (*mut); i++)
|
||||
printf (" %02x", *((unsigned char *) mut + i));
|
||||
printf ("\n");
|
||||
};
|
||||
|
||||
/* Helper, the opposite of pthread_cond_wait (cond, mut). */
|
||||
static void
|
||||
pthr_cond_signal_mutex (pthread_cond_t * cond, pthread_mutex_t * mut)
|
||||
{
|
||||
int err;
|
||||
err = pthread_mutex_lock (mut);
|
||||
if (err)
|
||||
printf ("mutex_lock : %s\n", strerror (err));
|
||||
err = pthread_cond_signal (cond);
|
||||
if (err)
|
||||
printf ("cond_signal : %s\n", strerror (err));
|
||||
err = pthread_mutex_unlock (mut);
|
||||
if (err)
|
||||
printf ("mutex_unlock: %s\n", strerror (err));
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_start (void *ptr)
|
||||
{
|
||||
struct thr_ctrl *tc = ptr;
|
||||
/* Do initialization. */
|
||||
/* ... */
|
||||
/* Signal that we are ready. */
|
||||
pthr_cond_signal_mutex (&tc->cond, &tc->mutex);
|
||||
sleep (2);
|
||||
pthr_cond_signal_mutex (&tc->cond, &tc->mutex);
|
||||
tc->retval = 0;
|
||||
pthread_exit (&tc->retval);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct thr_ctrl threadctrl;
|
||||
pthread_t thread;
|
||||
int err;
|
||||
void *res = &threadctrl.retval;
|
||||
pthread_mutexattr_t mutattr;
|
||||
pthread_mutexattr_init (&mutattr);
|
||||
pthread_mutex_init (&threadctrl.mutex, &mutattr);
|
||||
pthread_cond_init (&threadctrl.cond, NULL);
|
||||
err = pthread_mutex_lock (&threadctrl.mutex);
|
||||
if (err)
|
||||
printf ("mutex_lock : %s\n", strerror (err));
|
||||
dump_mut (&threadctrl.mutex);
|
||||
pthread_create (&thread, NULL, thread_start, &threadctrl);
|
||||
/* Wait until it's ready. */
|
||||
err = pthread_cond_wait (&threadctrl.cond, &threadctrl.mutex);
|
||||
if (err)
|
||||
printf ("cond_wait : %s\n", strerror (err));
|
||||
/* Now, we should have acquired the mutex again! */
|
||||
dump_mut (&threadctrl.mutex);
|
||||
sleep (1);
|
||||
dump_mut (&threadctrl.mutex);
|
||||
err = pthread_cond_wait (&threadctrl.cond, &threadctrl.mutex);
|
||||
if (err)
|
||||
{
|
||||
printf ("cond_wait : %s\n", strerror (err));
|
||||
printf ("ERROR\n");
|
||||
abort ();
|
||||
};
|
||||
dump_mut (&threadctrl.mutex);
|
||||
pthread_join (thread, &res);
|
||||
printf ("OK\n");
|
||||
return 0;
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
puts ("all OK");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include "../test-skeleton.c"
|
@ -1,58 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *worker (void *dummy) __attribute__ ((__noreturn__));
|
||||
|
||||
static void *
|
||||
worker (void *dummy)
|
||||
{
|
||||
exit (26);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#define TIMEOUT 10
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
pthread_t th;
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
switch ((pid = fork ()))
|
||||
{
|
||||
case -1:
|
||||
puts ("Could not fork");
|
||||
exit (1);
|
||||
case 0:
|
||||
if (pthread_create(&th, NULL, worker, NULL) != 0)
|
||||
{
|
||||
puts ("Failed to start thread");
|
||||
exit (1);
|
||||
}
|
||||
for (;;);
|
||||
exit (1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (waitpid (pid, &status, 0) != pid)
|
||||
{
|
||||
puts ("waitpid failed");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != 26)
|
||||
{
|
||||
printf ("Wrong exit code %d\n", status);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
puts ("All OK");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "../../test-skeleton.c"
|
@ -1,26 +0,0 @@
|
||||
/* Tst case by Jakub Jelinek <jakub@redhat.com>. */
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static void *
|
||||
task (void *p)
|
||||
{
|
||||
sleep (30);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t t;
|
||||
int status;
|
||||
|
||||
status = pthread_create (&t, NULL, task, NULL);
|
||||
if (status)
|
||||
exit (status);
|
||||
|
||||
status = pthread_detach (t);
|
||||
pthread_kill_other_threads_np ();
|
||||
return status;
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static pthread_mutex_t synch = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void *
|
||||
test_thread (void *v_param)
|
||||
{
|
||||
pthread_mutex_lock (&synch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STACKSIZE 0x100000
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t thread;
|
||||
pthread_attr_t attr;
|
||||
int status;
|
||||
void *stack, *stack2;
|
||||
size_t stacksize;
|
||||
|
||||
pthread_attr_init (&attr);
|
||||
stack = mmap (NULL, STACKSIZE,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (stack == MAP_FAILED)
|
||||
{
|
||||
perror ("mmap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = pthread_attr_setstack (&attr, stack, STACKSIZE);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("pthread_attr_setstack failed: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = pthread_attr_getstack (&attr, &stack2, &stacksize);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("pthread_attr_getstack failed: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stack2 != stack || stacksize != STACKSIZE)
|
||||
{
|
||||
printf ("first pthread_attr_getstack returned different stack (%p,%zx)\n"
|
||||
"than was set by setstack (%p,%x)\n",
|
||||
stack2, stacksize, stack, STACKSIZE);
|
||||
return 2;
|
||||
}
|
||||
|
||||
status = pthread_mutex_lock (&synch);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("cannot get lock: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = pthread_create (&thread, &attr, test_thread, NULL);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("pthread_create failed: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = pthread_getattr_np (thread, &attr);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("pthread_getattr_np failed: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = pthread_attr_getstack (&attr, &stack2, &stacksize);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("pthread_attr_getstack failed: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stack2 != stack || stacksize != STACKSIZE)
|
||||
{
|
||||
printf ("second pthread_attr_getstack returned different stack (%p,%zx)\n"
|
||||
"than was set by setstack (%p,%x)\n",
|
||||
stack2, stacksize, stack, STACKSIZE);
|
||||
return 3;
|
||||
}
|
||||
|
||||
status = pthread_mutex_unlock (&synch);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("cannot release lock: %s\n", strerror (status));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* pthread_detach (thread); */
|
||||
if (pthread_join (thread, NULL) != 0)
|
||||
{
|
||||
printf ("join failed\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Beat up the pthread_key_create and pthread_key_delete
|
||||
* functions.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define CHATTY
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const int beatup_iterations = 10000;
|
||||
const int num_threads = 30;
|
||||
const int max_keys = 500;
|
||||
|
||||
struct key_list {
|
||||
struct key_list *next;
|
||||
pthread_key_t key;
|
||||
};
|
||||
|
||||
struct key_list *key_list;
|
||||
pthread_mutex_t key_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Create a new key and put it at the tail of a linked list.
|
||||
* If the linked list grows to a certain length, delete a key from the
|
||||
* head of * the list.
|
||||
*/
|
||||
|
||||
static void
|
||||
beat_up(void)
|
||||
{
|
||||
struct key_list *new = malloc(sizeof *new);
|
||||
struct key_list **iter, *old_key = 0;
|
||||
int key_count = 0;
|
||||
|
||||
if (new == 0) {
|
||||
fprintf(stderr, "malloc failed\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
new->next = 0;
|
||||
|
||||
if (pthread_key_create(&new->key, 0) != 0) {
|
||||
fprintf(stderr, "pthread_key_create failed\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (pthread_getspecific(new->key) != 0) {
|
||||
fprintf(stderr, "new pthread_key_t resolves to non-null value\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_setspecific(new->key, (void *) 1);
|
||||
|
||||
#ifdef CHATTY
|
||||
printf("created key\n");
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&key_lock);
|
||||
|
||||
for (iter = &key_list; *iter != 0; iter = &(*iter)->next)
|
||||
key_count++;
|
||||
|
||||
*iter = new;
|
||||
|
||||
if (key_count > max_keys) {
|
||||
old_key = key_list;
|
||||
key_list = key_list->next;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&key_lock);
|
||||
|
||||
if (old_key != 0) {
|
||||
#ifdef CHATTY
|
||||
printf("deleting key\n");
|
||||
#endif
|
||||
pthread_key_delete(old_key->key);
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
thread(void *arg)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < beatup_iterations; i++)
|
||||
beat_up();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
pthread_attr_t detached_thread;
|
||||
|
||||
pthread_attr_init(&detached_thread);
|
||||
pthread_attr_setdetachstate(&detached_thread, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
for (i = 0; i < num_threads; i++) {
|
||||
pthread_t thread_id;
|
||||
while (pthread_create(&thread_id, &detached_thread, thread, 0) == EAGAIN) {
|
||||
/* let some threads die, so system can breathe. :) */
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
/* The classic producer-consumer example.
|
||||
Illustrates mutexes and conditions.
|
||||
All integers between 0 and 9999 should be printed exactly twice,
|
||||
once to the right of the arrow and once to the left. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pthread.h"
|
||||
|
||||
#define BUFFER_SIZE 16
|
||||
|
||||
/* Circular buffer of integers. */
|
||||
|
||||
struct prodcons
|
||||
{
|
||||
int buffer[BUFFER_SIZE]; /* the actual data */
|
||||
pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
|
||||
int readpos, writepos; /* positions for reading and writing */
|
||||
pthread_cond_t notempty; /* signaled when buffer is not empty */
|
||||
pthread_cond_t notfull; /* signaled when buffer is not full */
|
||||
};
|
||||
|
||||
/* Initialize a buffer */
|
||||
static void
|
||||
init (struct prodcons *b)
|
||||
{
|
||||
pthread_mutex_init (&b->lock, NULL);
|
||||
pthread_cond_init (&b->notempty, NULL);
|
||||
pthread_cond_init (&b->notfull, NULL);
|
||||
b->readpos = 0;
|
||||
b->writepos = 0;
|
||||
}
|
||||
|
||||
/* Store an integer in the buffer */
|
||||
static void
|
||||
put (struct prodcons *b, int data)
|
||||
{
|
||||
pthread_mutex_lock (&b->lock);
|
||||
/* Wait until buffer is not full */
|
||||
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
|
||||
{
|
||||
pthread_cond_wait (&b->notfull, &b->lock);
|
||||
/* pthread_cond_wait reacquired b->lock before returning */
|
||||
}
|
||||
/* Write the data and advance write pointer */
|
||||
b->buffer[b->writepos] = data;
|
||||
b->writepos++;
|
||||
if (b->writepos >= BUFFER_SIZE)
|
||||
b->writepos = 0;
|
||||
/* Signal that the buffer is now not empty */
|
||||
pthread_cond_signal (&b->notempty);
|
||||
pthread_mutex_unlock (&b->lock);
|
||||
}
|
||||
|
||||
/* Read and remove an integer from the buffer */
|
||||
static int
|
||||
get (struct prodcons *b)
|
||||
{
|
||||
int data;
|
||||
pthread_mutex_lock (&b->lock);
|
||||
/* Wait until buffer is not empty */
|
||||
while (b->writepos == b->readpos)
|
||||
{
|
||||
pthread_cond_wait (&b->notempty, &b->lock);
|
||||
}
|
||||
/* Read the data and advance read pointer */
|
||||
data = b->buffer[b->readpos];
|
||||
b->readpos++;
|
||||
if (b->readpos >= BUFFER_SIZE)
|
||||
b->readpos = 0;
|
||||
/* Signal that the buffer is now not full */
|
||||
pthread_cond_signal (&b->notfull);
|
||||
pthread_mutex_unlock (&b->lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* A test program: one thread inserts integers from 1 to 10000,
|
||||
the other reads them and prints them. */
|
||||
|
||||
#define OVER (-1)
|
||||
|
||||
struct prodcons buffer;
|
||||
|
||||
static void *
|
||||
producer (void *data)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < 10000; n++)
|
||||
{
|
||||
printf ("%d --->\n", n);
|
||||
put (&buffer, n);
|
||||
}
|
||||
put (&buffer, OVER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
consumer (void *data)
|
||||
{
|
||||
int d;
|
||||
while (1)
|
||||
{
|
||||
d = get (&buffer);
|
||||
if (d == OVER)
|
||||
break;
|
||||
printf ("---> %d\n", d);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t th_a, th_b;
|
||||
void *retval;
|
||||
|
||||
init (&buffer);
|
||||
/* Create the threads */
|
||||
pthread_create (&th_a, NULL, producer, 0);
|
||||
pthread_create (&th_b, NULL, consumer, 0);
|
||||
/* Wait until producer and consumer finish. */
|
||||
pthread_join (th_a, &retval);
|
||||
pthread_join (th_b, &retval);
|
||||
return 0;
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/* Multi-thread searching.
|
||||
Illustrates: thread cancellation, cleanup handlers. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Defines the number of searching threads */
|
||||
#define NUM_THREADS 5
|
||||
|
||||
/* Function prototypes */
|
||||
void *search(void *);
|
||||
void print_it(void *);
|
||||
|
||||
/* Global variables */
|
||||
pthread_t threads[NUM_THREADS];
|
||||
pthread_mutex_t lock;
|
||||
int tries;
|
||||
volatile int started;
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
int i;
|
||||
int pid;
|
||||
|
||||
/* create a number to search for */
|
||||
pid = getpid();
|
||||
printf("Searching for the number = %d...\n", pid);
|
||||
|
||||
/* Initialize the mutex lock */
|
||||
pthread_mutex_init(&lock, NULL);
|
||||
|
||||
/* Create the searching threads */
|
||||
for (started=0; started<NUM_THREADS; started++)
|
||||
pthread_create(&threads[started], NULL, search, (void *) (long int) pid);
|
||||
|
||||
/* Wait for (join) all the searching threads */
|
||||
for (i=0; i<NUM_THREADS; i++)
|
||||
pthread_join(threads[i], NULL);
|
||||
|
||||
printf("It took %d tries to find the number.\n", tries);
|
||||
|
||||
/* Exit the program */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the cleanup function that is called
|
||||
when the threads are cancelled */
|
||||
|
||||
void print_it(void *arg)
|
||||
{
|
||||
int *try = (int *) arg;
|
||||
pthread_t tid;
|
||||
|
||||
/* Get the calling thread's ID */
|
||||
tid = pthread_self();
|
||||
|
||||
/* Print where the thread was in its search when it was cancelled */
|
||||
printf("Thread %lx was canceled on its %d try.\n", tid, *try);
|
||||
}
|
||||
|
||||
/* This is the search routine that is executed in each thread */
|
||||
|
||||
void *search(void *arg)
|
||||
{
|
||||
int num = (long int) arg;
|
||||
int i, j, ntries;
|
||||
pthread_t tid;
|
||||
|
||||
/* get the calling thread ID */
|
||||
tid = pthread_self();
|
||||
|
||||
/* use the thread ID to set the seed for the random number generator */
|
||||
/* Since srand and rand are not thread-safe, serialize with lock */
|
||||
|
||||
/* Try to lock the mutex lock --
|
||||
if locked, check to see if the thread has been cancelled
|
||||
if not locked then continue */
|
||||
while (pthread_mutex_trylock(&lock) == EBUSY)
|
||||
pthread_testcancel();
|
||||
|
||||
srand((int)tid);
|
||||
i = rand() & 0xFFFFFF;
|
||||
pthread_mutex_unlock(&lock);
|
||||
ntries = 0;
|
||||
|
||||
/* Set the cancellation parameters --
|
||||
- Enable thread cancellation
|
||||
- Defer the action of the cancellation */
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||
|
||||
while (started < NUM_THREADS)
|
||||
sched_yield ();
|
||||
|
||||
/* Push the cleanup routine (print_it) onto the thread
|
||||
cleanup stack. This routine will be called when the
|
||||
thread is cancelled. Also note that the pthread_cleanup_push
|
||||
call must have a matching pthread_cleanup_pop call. The
|
||||
push and pop calls MUST be at the same lexical level
|
||||
within the code */
|
||||
|
||||
/* Pass address of `ntries' since the current value of `ntries' is not
|
||||
the one we want to use in the cleanup function */
|
||||
|
||||
pthread_cleanup_push(print_it, (void *)&ntries);
|
||||
|
||||
/* Loop forever */
|
||||
while (1) {
|
||||
i = (i + 1) & 0xFFFFFF;
|
||||
ntries++;
|
||||
|
||||
/* Does the random number match the target number? */
|
||||
if (num == i) {
|
||||
/* Try to lock the mutex lock --
|
||||
if locked, check to see if the thread has been cancelled
|
||||
if not locked then continue */
|
||||
while (pthread_mutex_trylock(&lock) == EBUSY)
|
||||
pthread_testcancel();
|
||||
|
||||
/* Set the global variable for the number of tries */
|
||||
tries = ntries;
|
||||
printf("Thread %lx found the number!\n", tid);
|
||||
|
||||
/* Cancel all the other threads */
|
||||
for (j=0; j<NUM_THREADS; j++)
|
||||
if (threads[j] != tid) pthread_cancel(threads[j]);
|
||||
|
||||
/* Break out of the while loop */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Every 100 tries check to see if the thread has been cancelled. */
|
||||
if (ntries % 100 == 0) {
|
||||
pthread_testcancel();
|
||||
}
|
||||
}
|
||||
|
||||
/* The only way we can get here is when the thread breaks out
|
||||
of the while loop. In this case the thread that makes it here
|
||||
has found the number we are looking for and does not need to run
|
||||
the thread cleanup function. This is why the pthread_cleanup_pop
|
||||
function is called with a 0 argument; this will pop the cleanup
|
||||
function off the stack without executing it */
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
return((void *)0);
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/* Making a library function that uses static variables thread-safe.
|
||||
Illustrates: thread-specific data, pthread_once(). */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* This is a typical example of a library function that uses
|
||||
static variables to accumulate results between calls.
|
||||
Here, it just returns the concatenation of all string arguments
|
||||
that were given to it. */
|
||||
|
||||
#if 0
|
||||
|
||||
char *
|
||||
str_accumulate (char *s)
|
||||
{
|
||||
static char accu[1024] = { 0 };
|
||||
strcat (accu, s);
|
||||
return accu;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Of course, this cannot be used in a multi-threaded program
|
||||
because all threads store "accu" at the same location.
|
||||
So, we'll use thread-specific data to have a different "accu"
|
||||
for each thread. */
|
||||
|
||||
/* Key identifying the thread-specific data */
|
||||
static pthread_key_t str_key;
|
||||
/* "Once" variable ensuring that the key for str_alloc will be allocated
|
||||
exactly once. */
|
||||
static pthread_once_t str_alloc_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Forward functions */
|
||||
static void str_alloc_key (void);
|
||||
static void str_alloc_destroy_accu (void *accu);
|
||||
|
||||
/* Thread-safe version of str_accumulate */
|
||||
|
||||
static char *
|
||||
str_accumulate (const char *s)
|
||||
{
|
||||
char *accu;
|
||||
|
||||
/* Make sure the key is allocated */
|
||||
pthread_once (&str_alloc_key_once, str_alloc_key);
|
||||
/* Get the thread-specific data associated with the key */
|
||||
accu = (char *) pthread_getspecific (str_key);
|
||||
/* It's initially NULL, meaning that we must allocate the buffer first. */
|
||||
if (accu == NULL)
|
||||
{
|
||||
accu = malloc (1024);
|
||||
if (accu == NULL)
|
||||
return NULL;
|
||||
accu[0] = 0;
|
||||
/* Store the buffer pointer in the thread-specific data. */
|
||||
pthread_setspecific (str_key, (void *) accu);
|
||||
printf ("Thread %lx: allocating buffer at %p\n", pthread_self (), accu);
|
||||
}
|
||||
/* Now we can use accu just as in the non thread-safe code. */
|
||||
strcat (accu, s);
|
||||
return accu;
|
||||
}
|
||||
|
||||
/* Function to allocate the key for str_alloc thread-specific data. */
|
||||
|
||||
static void
|
||||
str_alloc_key (void)
|
||||
{
|
||||
pthread_key_create (&str_key, str_alloc_destroy_accu);
|
||||
printf ("Thread %lx: allocated key %d\n", pthread_self (), str_key);
|
||||
}
|
||||
|
||||
/* Function to free the buffer when the thread exits. */
|
||||
/* Called only when the thread-specific data is not NULL. */
|
||||
|
||||
static void
|
||||
str_alloc_destroy_accu (void *accu)
|
||||
{
|
||||
printf ("Thread %lx: freeing buffer at %p\n", pthread_self (), accu);
|
||||
free (accu);
|
||||
}
|
||||
|
||||
/* Test program */
|
||||
|
||||
static void *
|
||||
process (void *arg)
|
||||
{
|
||||
char *res;
|
||||
res = str_accumulate ("Result of ");
|
||||
res = str_accumulate ((char *) arg);
|
||||
res = str_accumulate (" thread");
|
||||
printf ("Thread %lx: \"%s\"\n", pthread_self (), res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *res;
|
||||
pthread_t th1, th2;
|
||||
|
||||
res = str_accumulate ("Result of ");
|
||||
pthread_create (&th1, NULL, process, (void *) "first");
|
||||
pthread_create (&th2, NULL, process, (void *) "second");
|
||||
res = str_accumulate ("initial thread");
|
||||
printf ("Thread %lx: \"%s\"\n", pthread_self (), res);
|
||||
pthread_join (th1, NULL);
|
||||
pthread_join (th2, NULL);
|
||||
return 0;
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/* The classic producer-consumer example, implemented with semaphores.
|
||||
All integers between 0 and 9999 should be printed exactly twice,
|
||||
once to the right of the arrow and once to the left. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pthread.h"
|
||||
#include "semaphore.h"
|
||||
|
||||
#define BUFFER_SIZE 16
|
||||
|
||||
/* Circular buffer of integers. */
|
||||
|
||||
struct prodcons
|
||||
{
|
||||
int buffer[BUFFER_SIZE]; /* the actual data */
|
||||
int readpos, writepos; /* positions for reading and writing */
|
||||
sem_t sem_read; /* number of elements available for reading */
|
||||
sem_t sem_write; /* number of locations available for writing */
|
||||
};
|
||||
|
||||
/* Initialize a buffer */
|
||||
|
||||
static void
|
||||
init (struct prodcons *b)
|
||||
{
|
||||
sem_init (&b->sem_write, 0, BUFFER_SIZE - 1);
|
||||
sem_init (&b->sem_read, 0, 0);
|
||||
b->readpos = 0;
|
||||
b->writepos = 0;
|
||||
}
|
||||
|
||||
/* Store an integer in the buffer */
|
||||
|
||||
static void
|
||||
put (struct prodcons *b, int data)
|
||||
{
|
||||
/* Wait until buffer is not full */
|
||||
sem_wait (&b->sem_write);
|
||||
/* Write the data and advance write pointer */
|
||||
b->buffer[b->writepos] = data;
|
||||
b->writepos++;
|
||||
if (b->writepos >= BUFFER_SIZE)
|
||||
b->writepos = 0;
|
||||
/* Signal that the buffer contains one more element for reading */
|
||||
sem_post (&b->sem_read);
|
||||
}
|
||||
|
||||
/* Read and remove an integer from the buffer */
|
||||
|
||||
static int
|
||||
get (struct prodcons *b)
|
||||
{
|
||||
int data;
|
||||
/* Wait until buffer is not empty */
|
||||
sem_wait (&b->sem_read);
|
||||
/* Read the data and advance read pointer */
|
||||
data = b->buffer[b->readpos];
|
||||
b->readpos++;
|
||||
if (b->readpos >= BUFFER_SIZE)
|
||||
b->readpos = 0;
|
||||
/* Signal that the buffer has now one more location for writing */
|
||||
sem_post (&b->sem_write);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* A test program: one thread inserts integers from 1 to 10000,
|
||||
the other reads them and prints them. */
|
||||
|
||||
#define OVER (-1)
|
||||
|
||||
struct prodcons buffer;
|
||||
|
||||
static void *
|
||||
producer (void *data)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < 10000; n++)
|
||||
{
|
||||
printf ("%d --->\n", n);
|
||||
put (&buffer, n);
|
||||
}
|
||||
put (&buffer, OVER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
consumer (void *data)
|
||||
{
|
||||
int d;
|
||||
while (1)
|
||||
{
|
||||
d = get (&buffer);
|
||||
if (d == OVER)
|
||||
break;
|
||||
printf ("---> %d\n", d);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t th_a, th_b;
|
||||
void *retval;
|
||||
|
||||
init (&buffer);
|
||||
/* Create the threads */
|
||||
pthread_create (&th_a, NULL, producer, 0);
|
||||
pthread_create (&th_b, NULL, consumer, 0);
|
||||
/* Wait until producer and consumer finish. */
|
||||
pthread_join (th_a, &retval);
|
||||
pthread_join (th_b, &retval);
|
||||
return 0;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void *
|
||||
test_thread (void *v_param)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
setvbuf (stdout, NULL, _IONBF, 0);
|
||||
|
||||
for (count = 0; count < 2000; ++count)
|
||||
{
|
||||
pthread_t thread;
|
||||
int status;
|
||||
|
||||
status = pthread_create (&thread, NULL, test_thread, NULL);
|
||||
if (status != 0)
|
||||
{
|
||||
printf ("status = %d, count = %lu: %s\n", status, count,
|
||||
strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("count = %lu\n", count);
|
||||
}
|
||||
/* pthread_detach (thread); */
|
||||
int err = pthread_join (thread, NULL);
|
||||
if (err != 0)
|
||||
{
|
||||
printf ("join failed (%s), count %lu\n", strerror (err), count);
|
||||
return 2;
|
||||
}
|
||||
usleep (10);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/* This is a test of the special shutdown that occurs
|
||||
when all threads, including the main one, call
|
||||
pthread_exit(). It demonstrates that atexit
|
||||
handlers are properly called, and that the
|
||||
output is properly flushed even when stdout is
|
||||
redirected to a file, and therefore fully buffered. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define NTHREADS 20 /* number of threads */
|
||||
|
||||
static void *
|
||||
thread (void *arg)
|
||||
{
|
||||
printf ("thread terminating\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup (void)
|
||||
{
|
||||
printf ("atexit handler called\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
atexit (cleanup);
|
||||
|
||||
for (i = 0; i < NTHREADS; i++)
|
||||
{
|
||||
pthread_t id;
|
||||
if (pthread_create (&id, 0, thread, 0) != 0)
|
||||
{
|
||||
fprintf (stderr, "pthread_create failed\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit (0);
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
/* Tests for fork in multi-threaded environment.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
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; 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 <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
enum
|
||||
{
|
||||
PREPARE_BIT = 1,
|
||||
PARENT_BIT = 2,
|
||||
CHILD_BIT = 4
|
||||
};
|
||||
|
||||
static int var;
|
||||
|
||||
static void
|
||||
prepare (void)
|
||||
{
|
||||
var |= PREPARE_BIT;
|
||||
}
|
||||
|
||||
static void
|
||||
parent (void)
|
||||
{
|
||||
var |= PARENT_BIT;
|
||||
}
|
||||
|
||||
static void
|
||||
child (void)
|
||||
{
|
||||
var |= CHILD_BIT;
|
||||
}
|
||||
|
||||
|
||||
static void *thread (void *arg);
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t th;
|
||||
void *res;
|
||||
|
||||
pthread_atfork (prepare, parent, child);
|
||||
|
||||
if (pthread_create (&th, NULL, thread, NULL) != 0)
|
||||
error (EXIT_FAILURE, 0, "cannot create thread");
|
||||
|
||||
pthread_join (th, &res);
|
||||
|
||||
return (int) (long int) res;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
thread (void *arg)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork ();
|
||||
if (pid == 0)
|
||||
{
|
||||
/* We check whether the `prepare' and `child' function ran. */
|
||||
exit (var != (PREPARE_BIT | CHILD_BIT));
|
||||
}
|
||||
else if (pid == (pid_t) -1)
|
||||
error (EXIT_FAILURE, errno, "cannot fork");
|
||||
|
||||
if (waitpid (pid, &status, 0) != pid)
|
||||
error (EXIT_FAILURE, errno, "wrong child");
|
||||
|
||||
if (WTERMSIG (status) != 0)
|
||||
error (EXIT_FAILURE, 0, "Child terminated incorrectly");
|
||||
status = WEXITSTATUS (status);
|
||||
|
||||
if (status == 0)
|
||||
status = var != (PREPARE_BIT | PARENT_BIT);
|
||||
|
||||
return (void *) (long int) status;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/* Tests for pthread_barrier_* functions.
|
||||
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define NUM_THREADS 10
|
||||
#define NUM_ITERS 500
|
||||
|
||||
static void *thread (void *) __attribute__ ((__noreturn__));
|
||||
static pthread_barrier_t barrier;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t thread_list[NUM_THREADS];
|
||||
int i;
|
||||
|
||||
if (pthread_barrier_init (&barrier, NULL, NUM_THREADS + 1) != 0)
|
||||
error (EXIT_FAILURE, 0, "cannot initialize barrier");
|
||||
|
||||
for (i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
if (pthread_create (&thread_list[i], NULL, thread, NULL) != 0)
|
||||
error (EXIT_FAILURE, 0, "cannot create thread");
|
||||
}
|
||||
|
||||
(void) thread (NULL);
|
||||
|
||||
for (i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
pthread_join(thread_list[i], NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
thread (void *arg)
|
||||
{
|
||||
int i;
|
||||
pthread_t self = pthread_self ();
|
||||
static pthread_t last_serial_thread;
|
||||
static int linecount; /* protected by flockfile(stdout) */
|
||||
|
||||
for (i = 0; i < NUM_ITERS; i++)
|
||||
{
|
||||
switch (pthread_barrier_wait (&barrier))
|
||||
{
|
||||
case 0:
|
||||
flockfile (stdout);
|
||||
printf ("%04d: non-serial thread %lu\n", ++linecount,
|
||||
(unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
break;
|
||||
case PTHREAD_BARRIER_SERIAL_THREAD:
|
||||
flockfile (stdout);
|
||||
printf ("%04d: serial thread %lu\n", ++linecount,
|
||||
(unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
last_serial_thread = self;
|
||||
break;
|
||||
default:
|
||||
/* Huh? */
|
||||
error (EXIT_FAILURE, 0, "unexpected return value from barrier wait");
|
||||
}
|
||||
}
|
||||
|
||||
if (pthread_equal (self, last_serial_thread))
|
||||
{
|
||||
flockfile (stdout);
|
||||
printf ("%04d: last serial thread %lu terminating process\n",
|
||||
++linecount, (unsigned long) self);
|
||||
funlockfile (stdout);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include "ex1.c"
|
File diff suppressed because it is too large
Load Diff
@ -1,501 +0,0 @@
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
**********************************
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
========
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it in
|
||||
new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License, which was designed for utility
|
||||
programs. This license, the GNU Library General Public License,
|
||||
applies to certain designated libraries. This license is quite
|
||||
different from the ordinary one; be sure to read it in full, and don't
|
||||
assume that anything in it is the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is
|
||||
that they blur the distinction we usually make between modifying or
|
||||
adding to a program and simply using it. Linking a program with a
|
||||
library, without changing the library, is in some sense simply using
|
||||
the library, and is analogous to running a utility program or
|
||||
application program. However, in a textual and legal sense, the linked
|
||||
executable is a combined work, a derivative of the original library,
|
||||
and the ordinary General Public License treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended
|
||||
to permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to
|
||||
achieve this as regards changes in header files, but we have achieved
|
||||
it as regards changes in the actual functions of the Library.) The
|
||||
hope is that this will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other
|
||||
authorized party saying it may be distributed under the terms of
|
||||
this Library General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or
|
||||
translated straightforwardly into another language. (Hereinafter,
|
||||
translation is included without limitation in the term
|
||||
"modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code
|
||||
means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are
|
||||
not covered by this License; they are outside its scope. The act
|
||||
of running a program using the Library is not restricted, and
|
||||
output from such a program is covered only if its contents
|
||||
constitute a work based on the Library (independent of the use of
|
||||
the Library in a tool for writing it). Whether that is true
|
||||
depends on what the Library does and what the program that uses
|
||||
the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided
|
||||
that you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep
|
||||
intact all the notices that refer to this License and to the
|
||||
absence of any warranty; and distribute a copy of this License
|
||||
along with the Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange
|
||||
for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a. The modified work must itself be a software library.
|
||||
|
||||
b. You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c. You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d. If a facility in the modified Library refers to a function or
|
||||
a table of data to be supplied by an application program that
|
||||
uses the facility, other than as an argument passed when the
|
||||
facility is invoked, then you must make a good faith effort
|
||||
to ensure that, in the event an application does not supply
|
||||
such function or table, the facility still operates, and
|
||||
performs whatever part of its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots
|
||||
has a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function
|
||||
must be optional: if the application does not supply it, the
|
||||
square root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the
|
||||
Library, and can be reasonably considered independent and separate
|
||||
works in themselves, then this License, and its terms, do not
|
||||
apply to those sections when you distribute them as separate
|
||||
works. But when you distribute the same sections as part of a
|
||||
whole which is a work based on the Library, the distribution of
|
||||
the whole must be on the terms of this License, whose permissions
|
||||
for other licensees extend to the entire whole, and thus to each
|
||||
and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or
|
||||
contest your rights to work written entirely by you; rather, the
|
||||
intent is to exercise the right to control the distribution of
|
||||
derivative or collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the
|
||||
Library with the Library (or with a work based on the Library) on
|
||||
a volume of a storage or distribution medium does not bring the
|
||||
other work under the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library.
|
||||
To do this, you must alter all the notices that refer to this
|
||||
License, so that they refer to the ordinary GNU General Public
|
||||
License, version 2, instead of to this License. (If a newer
|
||||
version than version 2 of the ordinary GNU General Public License
|
||||
has appeared, then you can specify that version instead if you
|
||||
wish.) Do not make any other change in these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to
|
||||
all subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable
|
||||
form under the terms of Sections 1 and 2 above provided that you
|
||||
accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software
|
||||
interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy
|
||||
the source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being
|
||||
compiled or linked with it, is called a "work that uses the
|
||||
Library". Such a work, in isolation, is not a derivative work of
|
||||
the Library, and therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because
|
||||
it contains portions of the Library), rather than a "work that
|
||||
uses the library". The executable is therefore covered by this
|
||||
License. Section 6 states terms for distribution of such
|
||||
executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header
|
||||
file that is part of the Library, the object code for the work may
|
||||
be a derivative work of the Library even though the source code is
|
||||
not. Whether this is true is especially significant if the work
|
||||
can be linked without the Library, or if the work is itself a
|
||||
library. The threshold for this to be true is not precisely
|
||||
defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a
|
||||
derivative work. (Executables containing this object code plus
|
||||
portions of the Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section
|
||||
6. Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered
|
||||
by this License. You must supply a copy of this License. If the
|
||||
work during execution displays copyright notices, you must include
|
||||
the copyright notice for the Library among them, as well as a
|
||||
reference directing the user to the copy of this License. Also,
|
||||
you must do one of these things:
|
||||
|
||||
a. Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including
|
||||
whatever changes were used in the work (which must be
|
||||
distributed under Sections 1 and 2 above); and, if the work
|
||||
is an executable linked with the Library, with the complete
|
||||
machine-readable "work that uses the Library", as object code
|
||||
and/or source code, so that the user can modify the Library
|
||||
and then relink to produce a modified executable containing
|
||||
the modified Library. (It is understood that the user who
|
||||
changes the contents of definitions files in the Library will
|
||||
not necessarily be able to recompile the application to use
|
||||
the modified definitions.)
|
||||
|
||||
b. Accompany the work with a written offer, valid for at least
|
||||
three years, to give the same user the materials specified in
|
||||
Subsection 6a, above, for a charge no more than the cost of
|
||||
performing this distribution.
|
||||
|
||||
c. If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the
|
||||
above specified materials from the same place.
|
||||
|
||||
d. Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special
|
||||
exception, the source code distributed need not include anything
|
||||
that is normally distributed (in either source or binary form)
|
||||
with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that
|
||||
component itself accompanies the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you
|
||||
cannot use both them and the Library together in an executable
|
||||
that you distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other
|
||||
library facilities not covered by this License, and distribute
|
||||
such a combined library, provided that the separate distribution
|
||||
of the work based on the Library and of the other library
|
||||
facilities is otherwise permitted, and provided that you do these
|
||||
two things:
|
||||
|
||||
a. Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b. Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same
|
||||
work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute the
|
||||
Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate
|
||||
your rights under this License. However, parties who have
|
||||
received copies, or rights, from you under this License will not
|
||||
have their licenses terminated so long as such parties remain in
|
||||
full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify
|
||||
or distribute the Library or its derivative works. These actions
|
||||
are prohibited by law if you do not accept this License.
|
||||
Therefore, by modifying or distributing the Library (or any work
|
||||
based on the Library), you indicate your acceptance of this
|
||||
License to do so, and all its terms and conditions for copying,
|
||||
distributing or modifying the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the
|
||||
Library subject to these terms and conditions. You may not impose
|
||||
any further restrictions on the recipients' exercise of the rights
|
||||
granted herein. You are not responsible for enforcing compliance
|
||||
by third parties to this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent
|
||||
issues), conditions are imposed on you (whether by court order,
|
||||
agreement or otherwise) that contradict the conditions of this
|
||||
License, they do not excuse you from the conditions of this
|
||||
License. If you cannot distribute so as to satisfy simultaneously
|
||||
your obligations under this License and any other pertinent
|
||||
obligations, then as a consequence you may not distribute the
|
||||
Library at all. For example, if a patent license would not permit
|
||||
royalty-free redistribution of the Library by all those who
|
||||
receive copies directly or indirectly through you, then the only
|
||||
way you could satisfy both it and this License would be to refrain
|
||||
entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable
|
||||
under any particular circumstance, the balance of the section is
|
||||
intended to apply, and the section as a whole is intended to apply
|
||||
in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of
|
||||
any such claims; this section has the sole purpose of protecting
|
||||
the integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is
|
||||
willing to distribute software through any other system and a
|
||||
licensee cannot impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed
|
||||
to be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces,
|
||||
the original copyright holder who places the Library under this
|
||||
License may add an explicit geographical distribution limitation
|
||||
excluding those countries, so that distribution is permitted only
|
||||
in or among countries not thus excluded. In such case, this
|
||||
License incorporates the limitation as if written in the body of
|
||||
this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library specifies a version number of this License which applies
|
||||
to it and "any later version", you have the option of following
|
||||
the terms and conditions either of that version or of any later
|
||||
version published by the Free Software Foundation. If the Library
|
||||
does not specify a license version number, you may choose any
|
||||
version ever published by the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free
|
||||
status of all derivatives of our free software and of promoting
|
||||
the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE
|
||||
LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT
|
||||
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
|
||||
QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE
|
||||
LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
|
||||
SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
|
||||
MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
|
||||
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
|
||||
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
|
||||
INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU
|
||||
OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY
|
||||
OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
==============================================
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of
|
||||
the ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library.
|
||||
It is safest to attach them to the start of each source file to most
|
||||
effectively convey the exclusion of warranty; and each file should have
|
||||
at least the "copyright" line and a pointer to where the full notice is
|
||||
found.
|
||||
|
||||
ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES.
|
||||
Copyright (C) YEAR NAME OF AUTHOR
|
||||
|
||||
This 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.
|
||||
|
||||
This library is distributed in the hope that 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 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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper
|
||||
mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the library,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the library
|
||||
`Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
SIGNATURE OF TY COON, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
@ -1,11 +0,0 @@
|
||||
# Makeconfig fragment for linuxthreads add-on.
|
||||
# This gets included at the end of the main glibc Makeconfig.
|
||||
|
||||
have-thread-library = yes
|
||||
|
||||
shared-thread-library = $(common-objpfx)linuxthreads/libpthread_nonshared.a \
|
||||
$(common-objpfx)linuxthreads/libpthread.so
|
||||
static-thread-library = $(common-objpfx)linuxthreads/libpthread.a
|
||||
bounded-thread-library = $(common-objpfx)linuxthreads/libpthread_b.a
|
||||
|
||||
rpath-dirs += linuxthreads
|
@ -1,348 +0,0 @@
|
||||
# Copyright (C) 1996-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.
|
||||
|
||||
#
|
||||
# Sub-makefile for linuxthreads portion of the library.
|
||||
#
|
||||
subdir := linuxthreads
|
||||
|
||||
all: # Make this the default target; it will be defined in Rules.
|
||||
|
||||
linuxthreads-version := $(shell sed -n 's/^.*$(subdir)-\([0-9.]*\).*$$/\1/p' \
|
||||
Banner)
|
||||
libpthread-abi-frozen := GLIBC_2.3.2
|
||||
|
||||
headers := pthread.h semaphore.h
|
||||
distribute := internals.h queue.h restart.h spinlock.h smp.h tst-signal.sh \
|
||||
tst-cancel-wrappers.sh libc-tsd.c
|
||||
|
||||
routines := forward alloca_cutoff libc-cancellation libc_pthread_init
|
||||
shared-only-routines = forward
|
||||
|
||||
extra-libs := libpthread
|
||||
extra-libs-others := $(extra-libs)
|
||||
install-lib-ldscripts := libpthread.so
|
||||
|
||||
libpthread-routines := attr cancel condvar join manager mutex ptfork \
|
||||
ptlongjmp pthread pt-sigsuspend signals specific errno \
|
||||
lockfile semaphore spinlock rwlock pt-machine \
|
||||
oldsemaphore events getcpuclockid pspinlock barrier \
|
||||
ptclock_gettime ptclock_settime sighandler \
|
||||
pthandles libc-tls-loc pt-allocrtsig \
|
||||
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-lseek64 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 pt-system old_pthread_atfork pthread_atfork \
|
||||
ptcleanup
|
||||
# pthread_setuid pthread_seteuid pthread_setreuid \
|
||||
# pthread_setresuid \
|
||||
# pthread_setgid pthread_setegid pthread_setregid \
|
||||
# pthread_setresgid
|
||||
|
||||
# Don't generate deps for calls with no sources. See sysdeps/unix/Makefile.
|
||||
omit-deps = $(unix-syscalls:%=ptw-%)
|
||||
|
||||
libpthread-shared-only-routines = pt-allocrtsig
|
||||
libpthread-static-only-routines = pthread_atfork
|
||||
|
||||
linuxthreads-CPPFLAGS = -DIS_IN_linuxthreads=1
|
||||
|
||||
CFLAGS-pthread_atfork.c = -DNOT_IN_libc
|
||||
|
||||
nodelete-yes = -Wl,--enable-new-dtags,-z,nodelete
|
||||
initfirst-yes = -Wl,--enable-new-dtags,-z,initfirst
|
||||
LDFLAGS-pthread.so = $(nodelete-$(have-z-nodelete)) \
|
||||
$(initfirst-$(have-z-initfirst))
|
||||
|
||||
vpath %.c Examples
|
||||
|
||||
tst-cancel-ARGS = "$(objpfx)"
|
||||
CFLAGS-tst-cancel.c = -fno-inline -fno-inline-functions
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
|
||||
# Set the `multidir' variable by grabbing the variable from the compiler.
|
||||
# We do it once and save the result in a generated makefile.
|
||||
-include $(objpfx)multidir.mk
|
||||
$(objpfx)multidir.mk: $(common-objpfx)config.make
|
||||
$(make-target-directory)
|
||||
dir=`$(CC) $(CFLAGS) $(CPPFLAGS) -print-multi-directory`; \
|
||||
echo "multidir := $$dir" > $@T
|
||||
mv -f $@T $@
|
||||
generated += multidir.mk
|
||||
|
||||
crti-objs := crti.o
|
||||
crtn-objs := crtn.o
|
||||
ifneq (,$(patsubst .,,$(multidir)))
|
||||
generated-dirs := $(firstword $(subst /, , $(multidir)))
|
||||
crti-objs += $(multidir)/crti.o
|
||||
crtn-objs += $(multidir)/crtn.o
|
||||
omit-deps += $(multidir)/crti $(multidir)/crtn
|
||||
endif
|
||||
extra-objs += $(crti-objs) $(crtn-objs)
|
||||
omit-deps += crti crtn
|
||||
|
||||
CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time)
|
||||
endif
|
||||
|
||||
librt-tests = ex10 ex11 tst-clock1
|
||||
tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \
|
||||
tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
|
||||
ex17 ex18 tst-cancel tst-context bug-sleep \
|
||||
tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
|
||||
tst-cancel6 tst-cancel7 tst-cancel8 tst-popen tst-popen2 tst-attr1 \
|
||||
tst-stack1 tst-align tst-tsd1
|
||||
test-srcs = tst-signal
|
||||
# These tests are linked with libc before libpthread
|
||||
tests-reverse += tst-cancel5
|
||||
|
||||
ifeq ($(build-static),yes)
|
||||
tests += tststatic tst-static-locale tst-cancel-static
|
||||
tests-static += tststatic tst-static-locale tst-cancel-static
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
tests-nodelete-yes = unload
|
||||
tests += tst-tls1 tst-_res1
|
||||
endif
|
||||
|
||||
modules-names = tst-_res1mod1 tst-_res1mod2 \
|
||||
tst-tls1mod tst-tls1moda tst-tls1modb tst-tls1modc \
|
||||
tst-tls1modd tst-tls1mode tst-tls1modf
|
||||
extra-objs += $(addsuffix .os,$(strip $(modules-names)))
|
||||
generated += $(addsuffix .so,$(strip $(modules-names)))
|
||||
test-extras += $(modules-names)
|
||||
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
||||
|
||||
tst-tls1mod.so-no-z-defs = yes
|
||||
tst-tls1moda.so-no-z-defs = yes
|
||||
tst-tls1modb.so-no-z-defs = yes
|
||||
tst-tls1modc.so-no-z-defs = yes
|
||||
tst-tls1modd.so-no-z-defs = yes
|
||||
tst-tls1mode.so-no-z-defs = yes
|
||||
tst-tls1modf.so-no-z-defs = yes
|
||||
|
||||
$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds
|
||||
$(build-module)
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
# Build all the modules even when not actually running test programs.
|
||||
tests: $(test-modules)
|
||||
endif
|
||||
|
||||
# What we install as libpthread.so for programs to link against is in fact a
|
||||
# link script. It contains references for the various libraries we need.
|
||||
# The libpthread.so object is not complete since some functions are only defined
|
||||
# in libpthread_nonshared.a.
|
||||
# We need to use absolute paths since otherwise local copies (if they exist)
|
||||
# of the files are taken by the linker.
|
||||
install: $(inst_libdir)/libpthread.so
|
||||
$(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \
|
||||
$(objpfx)libpthread.so$(libpthread.so-version) \
|
||||
$(inst_libdir)/$(patsubst %,$(libtype.oS),\
|
||||
$(libprefix)pthread) \
|
||||
$(+force)
|
||||
(echo '/* GNU ld script';\
|
||||
echo ' Use the shared library, but some functions are only in';\
|
||||
echo ' the static library, so try that secondarily. */';\
|
||||
cat $<; \
|
||||
echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \
|
||||
'$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\
|
||||
')' \
|
||||
) > $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
|
||||
extra-B-pthread.so = -B$(common-objpfx)linuxthreads/
|
||||
$(objpfx)libpthread.so: $(addprefix $(objpfx),$(crti-objs) $(crtn-objs))
|
||||
$(objpfx)libpthread.so: +preinit += $(addprefix $(objpfx),$(crti-objs))
|
||||
$(objpfx)libpthread.so: +postinit += $(addprefix $(objpfx),$(crtn-objs))
|
||||
|
||||
znodelete-yes = -DHAVE_Z_NODELETE
|
||||
CFLAGS-mutex.c += -D__NO_WEAK_PTHREAD_ALIASES
|
||||
CFLAGS-specific.c += -D__NO_WEAK_PTHREAD_ALIASES
|
||||
CFLAGS-pthread.c += -D__NO_WEAK_PTHREAD_ALIASES $(znodelete-$(have-z-nodelete))
|
||||
CFLAGS-ptfork.c += -D__NO_WEAK_PTHREAD_ALIASES
|
||||
CFLAGS-cancel.c += -D__NO_WEAK_PTHREAD_ALIASES -D_RPC_THREAD_SAFE_
|
||||
CFLAGS-unload.c += -DPREFIX=\"$(objpfx)\"
|
||||
CFLAGS-mutex.c += $(uses-callbacks)
|
||||
CFLAGS-sighandler.c += $(uses-callbacks)
|
||||
|
||||
ifeq (yes,$(versioning))
|
||||
-include $(common-objpfx)tls.make
|
||||
libc-ok-for-link = $(use-thread)
|
||||
else
|
||||
libc-ok-for-link = yes
|
||||
endif
|
||||
|
||||
ifeq (no,$(libc-ok-for-link))
|
||||
# These hacks are necessary to let us link against a libc.so that exports
|
||||
# the symbols _errno, _h_errno, and _res. Those symbols are accessible
|
||||
# in libc at runtime (dynamic linkable), but are not exported at link time
|
||||
# so that applications cannot link against them. However, libpthread.so
|
||||
# needs to link against them for its __errno_location et al functions to
|
||||
# find the locations that libc's symbols resolve to. We cannot do this
|
||||
# with aliases in libc.so(GLIBC_PRIVATE), because we need to refer to an
|
||||
# executable's symbols when it defines them with copy relocs.
|
||||
libc-link.so = $(objpfx)libc.so
|
||||
|
||||
$(objpfx)libc_pic_lite.a: $(common-objpfx)libc_pic.a
|
||||
cp $< $@T
|
||||
$(AR) d $@T errno.os herrno.os res_libc.os
|
||||
mv -f $@T $@
|
||||
|
||||
extra-objs += libc-tsd.os
|
||||
$(objpfx)libc_pic_lite.os: $(objpfx)libc_pic_lite.a $(objpfx)libc-tsd.os
|
||||
$(LINK.o) -nostdlib -nostartfiles -r -o $@ \
|
||||
$(LDFLAGS-c_pic.os) -Wl,-d -Wl,--whole-archive $^
|
||||
|
||||
# This trick leaves errno and h_errno undefined.
|
||||
libc.so-no-z-defs = yes
|
||||
|
||||
$(objpfx)libc.so: $(elfobjdir)/soinit.os \
|
||||
$(objpfx)libc_pic_lite.os \
|
||||
$(elfobjdir)/sofini.os \
|
||||
$(elfobjdir)/interp.os $(elfobjdir)/ld.so
|
||||
$(build-shlib)
|
||||
|
||||
generated += libc_pic_lite.a libc_pic_lite.os libc.so libc-tsd.os
|
||||
else
|
||||
libc-link.so = $(common-objpfx)libc.so
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
|
||||
# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
|
||||
# This ensures they will load libc.so for needed symbols if loaded by
|
||||
# a statically-linked program that hasn't already loaded it.
|
||||
# Depend on ld.so too to get proper versions of ld.so symbols.
|
||||
$(objpfx)libpthread.so: $(libc-link.so) $(common-objpfx)libc_nonshared.a \
|
||||
$(if $(filter yes,$(elf)), $(elfobjdir)/ld.so)
|
||||
|
||||
# Make sure we link with the thread library.
|
||||
ifeq ($(build-shared),yes)
|
||||
$(addprefix $(objpfx), \
|
||||
$(filter-out $(tests-static) $(tests-reverse) unload, \
|
||||
$(tests) $(test-srcs))): $(objpfx)libpthread.so \
|
||||
$(objpfx)libpthread_nonshared.a
|
||||
# $(objpfx)linklibc.so is used instead of $(common-objpfx)libc.so,
|
||||
# since otherwise libpthread.so comes before libc.so when linking.
|
||||
$(addprefix $(objpfx), $(tests-reverse)): \
|
||||
$(objpfx)linklibc.so $(objpfx)libpthread.so \
|
||||
$(objpfx)libpthread_nonshared.a
|
||||
$(objpfx)../libc.so: $(common-objpfx)libc.so ;
|
||||
$(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so
|
||||
$(objpfx)unload: $(common-objpfx)dlfcn/libdl.so
|
||||
$(objpfx)unload.out: $(objpfx)libpthread.so $(objpfx)libpthread_nonshared.a
|
||||
$(objpfx)linklibc.so: $(common-objpfx)libc.so
|
||||
ln -s ../libc.so $@
|
||||
generated += libclink.so
|
||||
else
|
||||
$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
|
||||
$(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a
|
||||
endif
|
||||
ifeq ($(build-bounded),yes)
|
||||
$(tests:%=$(objpfx)%-bp): $(objpfx)libpthread_b.a
|
||||
$(librt-tests:%=$(objpfx)%-bp): $(common-objpfx)rt/librt_b.a
|
||||
endif
|
||||
|
||||
ifeq ($(build-static),yes)
|
||||
$(addprefix $(objpfx), $(tests-static)): $(objpfx)libpthread.a
|
||||
endif
|
||||
|
||||
ifeq ($(build-shared),yes)
|
||||
vpath pt-initfini.c $(full_config_sysdirs)
|
||||
|
||||
$(objpfx)pt-initfini.s: pt-initfini.c
|
||||
$(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \
|
||||
$(patsubst -f%,-fno-%,$(exceptions)) -o $@
|
||||
|
||||
# We only have one kind of startup code files. Static binaries and
|
||||
# shared libraries are build using the PIC version.
|
||||
$(objpfx)crti.S: $(objpfx)pt-initfini.s
|
||||
sed -n -e '1,/@HEADER_ENDS/p' \
|
||||
-e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \
|
||||
-e '/@TRAILER_BEGINS/,$$p' $< > $@
|
||||
$(objpfx)crtn.S: $(objpfx)pt-initfini.s
|
||||
sed -n -e '1,/@HEADER_ENDS/p' \
|
||||
-e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \
|
||||
-e '/@TRAILER_BEGINS/,$$p' $< > $@
|
||||
|
||||
$(objpfx)defs.h: $(objpfx)pt-initfini.s
|
||||
sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \
|
||||
$(AWK) -f ../csu/defs.awk > $@
|
||||
|
||||
$(objpfx)crti.o: $(objpfx)crti.S $(objpfx)defs.h
|
||||
$(compile.S) -g0 $(ASFLAGS-.os) -o $@
|
||||
|
||||
$(objpfx)crtn.o: $(objpfx)crtn.S $(objpfx)defs.h
|
||||
$(compile.S) -g0 $(ASFLAGS-.os) -o $@
|
||||
|
||||
ifneq ($(multidir),.)
|
||||
$(objpfx)$(multidir):
|
||||
@mkdir -p $(objpfx)$(multidir)
|
||||
|
||||
$(objpfx)$(multidir)/crti.o: $(objpfx)crti.o $(objpfx)$(multidir)
|
||||
ln -f $< $@
|
||||
|
||||
$(objpfx)$(multidir)/crtn.o: $(objpfx)crtn.o $(objpfx)$(multidir)
|
||||
ln -f $< $@
|
||||
endif
|
||||
|
||||
generated += crti.S crtn.S defs.h pt-initfini.s libpthread_nonshared.a
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-static-nss))
|
||||
otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \
|
||||
$(resolvobjdir)/libresolv.a
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
$(objpfx)tst-_res1mod2.so: $(objpfx)tst-_res1mod1.so
|
||||
$(objpfx)tst-_res1: $(objpfx)tst-_res1mod2.so $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-tls1: $(objpfx)tst-tls1mod.so $(shared-thread-library)
|
||||
|
||||
tests: $(objpfx)tst-tls2.out
|
||||
$(objpfx)tst-tls2.out: tst-tls2.sh $(objpfx)tst-tls1 \
|
||||
$(objpfx)tst-tls1moda.so $(objpfx)tst-tls1modb.so \
|
||||
$(objpfx)tst-tls1modc.so $(objpfx)tst-tls1modd.so \
|
||||
$(objpfx)tst-tls1mode.so $(objpfx)tst-tls1modf.so
|
||||
$(SHELL) -e tst-tls2.sh $(common-objpfx) $(elf-objpfx) \
|
||||
$(rtld-installed-name)
|
||||
generated += tst-tls2.out
|
||||
endif
|
||||
|
||||
ifeq (no,$(cross-compiling))
|
||||
ifeq (yes,$(build-shared))
|
||||
tests: $(objpfx)tst-signal.out $(objpfx)tst-cancel-wrappers.out
|
||||
$(objpfx)tst-signal.out: tst-signal.sh $(objpfx)tst-signal
|
||||
$(SHELL) -e $< $(common-objpfx) > $@
|
||||
$(objpfx)tst-cancel-wrappers.out: tst-cancel-wrappers.sh
|
||||
$(SHELL) $< $(common-objpfx)/libc_pic.a \
|
||||
$(common-objpfx)/libc.a \
|
||||
$(objpfx)/libpthread_pic.a \
|
||||
$(objpfx)/libpthread.a > $@
|
||||
generated += tst-signal.out tst-cancel-wrappers.out
|
||||
endif
|
||||
endif
|
@ -1,166 +0,0 @@
|
||||
Linuxthreads - POSIX 1003.1c kernel threads for Linux
|
||||
|
||||
Copyright 1996, 1997 Xavier Leroy (Xavier.Leroy@inria.fr)
|
||||
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
This is release 0.7 (late beta) of LinuxThreads, a BiCapitalized
|
||||
implementation of the Posix 1003.1c "pthread" interface for Linux.
|
||||
|
||||
LinuxThreads provides kernel-level threads: each thread is a separate
|
||||
Unix process, sharing its address space with the other threads through
|
||||
the new system call clone(). Scheduling between threads is handled by
|
||||
the kernel scheduler, just like scheduling between Unix processes.
|
||||
|
||||
|
||||
REQUIREMENTS:
|
||||
|
||||
- Linux version 2.0 and up (requires the new clone() system call
|
||||
and the new realtime scheduler).
|
||||
|
||||
- For Intel platforms: libc 5.2.18 or later is required.
|
||||
5.2.18 or 5.4.12 or later are recommended;
|
||||
5.3.12 and 5.4.7 have problems (see the FAQ.html file for more info).
|
||||
|
||||
- Also supports glibc 2 (a.k.a. libc 6), which actually comes with
|
||||
a specially-adapted version of this library.
|
||||
|
||||
- Currently supports Intel, Alpha, Sparc, Motorola 68k, ARM and MIPS
|
||||
platforms.
|
||||
|
||||
- Multiprocessors are supported.
|
||||
|
||||
|
||||
INSTALLATION:
|
||||
|
||||
- Edit the Makefile, set the variables in the "Configuration" section.
|
||||
|
||||
- Do "make".
|
||||
|
||||
- Do "make install".
|
||||
|
||||
|
||||
USING LINUXTHREADS:
|
||||
|
||||
gcc -D_REENTRANT ... -lpthread
|
||||
|
||||
A complete set of manual pages is included. Also see the subdirectory
|
||||
Examples/ for some sample programs.
|
||||
|
||||
|
||||
STATUS:
|
||||
|
||||
- All functions in the Posix 1003.1c base interface implemented.
|
||||
Also supports priority scheduling.
|
||||
|
||||
- For users of libc 5 (H.J.Lu's libc), a number of C library functions
|
||||
are reimplemented or wrapped to make them thread-safe, including:
|
||||
* malloc functions
|
||||
* stdio functions (define _REENTRANT before including <stdio.h>)
|
||||
* per-thread errno variable (define _REENTRANT before including <errno.h>)
|
||||
* directory reading functions (opendir(), etc)
|
||||
* sleep()
|
||||
* gmtime(), localtime()
|
||||
|
||||
New library functions provided:
|
||||
* flockfile(), funlockfile(), ftrylockfile()
|
||||
* reentrant versions of network database functions (gethostbyname_r(), etc)
|
||||
and password functions (getpwnam_r(), etc).
|
||||
|
||||
- libc 6 (glibc 2) provides much better thread support than libc 5,
|
||||
and comes with a specially-adapted version of LinuxThreads.
|
||||
For serious multithreaded programming, you should consider switching
|
||||
to glibc 2. It is available from ftp.gnu.org:/pub/gnu and its mirrors.
|
||||
|
||||
|
||||
WARNING:
|
||||
|
||||
Many existing libraries are not compatible with LinuxThreads,
|
||||
either because they are not inherently thread-safe, or because they
|
||||
have not been compiled with the -D_REENTRANT. For more info, see the
|
||||
FAQ.html file in this directory.
|
||||
|
||||
A prime example of the latter is Xlib. If you link it with
|
||||
LinuxThreads, you'll probably get an "unknown 0 error" very
|
||||
early. This is just a consequence of the Xlib binaries using the
|
||||
global variable "errno" to fetch error codes, while LinuxThreads and
|
||||
the C library use the per-thread "errno" location.
|
||||
|
||||
See the file README.Xfree3.3 for info on how to compile the Xfree 3.3
|
||||
libraries to make them compatible with LinuxThreads.
|
||||
|
||||
|
||||
KNOWN BUGS AND LIMITATIONS:
|
||||
|
||||
- Threads share pretty much everything they should share according
|
||||
to the standard: memory space, file descriptors, signal handlers,
|
||||
current working directory, etc. One thing that they do not share
|
||||
is their pid's and parent pid's. According to the standard, they
|
||||
should have the same, but that's one thing we cannot achieve
|
||||
in this implementation (until the CLONE_PID flag to clone() becomes
|
||||
usable).
|
||||
|
||||
- The current implementation uses the two signals SIGUSR1 and SIGUSR2,
|
||||
so user-level code cannot employ them. Ideally, there should be two
|
||||
signals reserved for this library. One signal is used for restarting
|
||||
threads blocked on mutexes or conditions; the other is for thread
|
||||
cancellation.
|
||||
|
||||
*** This is not anymore true when the application runs on a kernel
|
||||
newer than approximately 2.1.60.
|
||||
|
||||
- The stacks for the threads are allocated high in the memory space,
|
||||
below the stack of the initial process, and spaced 2M apart.
|
||||
Stacks are allocated with the "grow on demand" flag, so they don't
|
||||
use much virtual space initially (4k, currently), but can grow
|
||||
up to 2M if needed.
|
||||
|
||||
Reserving such a large address space for each thread means that,
|
||||
on a 32-bit architecture, no more than about 1000 threads can
|
||||
coexist (assuming a 2Gb address space for user processes),
|
||||
but this is reasonable, since each thread uses up one entry in the
|
||||
kernel's process table, which is usually limited to 512 processes.
|
||||
|
||||
Another potential problem of the "grow on demand" scheme is that
|
||||
nothing prevents the user from mmap'ing something in the 2M address
|
||||
window reserved for a thread stack, possibly causing later extensions of
|
||||
that stack to fail. Mapping at fixed addresses should be avoided
|
||||
when using this library.
|
||||
|
||||
- Signal handling does not fully conform to the Posix standard,
|
||||
due to the fact that threads are here distinct processes that can be
|
||||
sent signals individually, so there's no notion of sending a signal
|
||||
to "the" process (the collection of all threads).
|
||||
More precisely, here is a summary of the standard requirements
|
||||
and how they are met by the implementation:
|
||||
|
||||
1- Synchronous signals (generated by the thread execution, e.g. SIGFPE)
|
||||
are delivered to the thread that raised them.
|
||||
(OK.)
|
||||
|
||||
2- A fatal asynchronous signal terminates all threads in the process.
|
||||
(OK. The thread manager notices when a thread dies on a signal
|
||||
and kills all other threads with the same signal.)
|
||||
|
||||
3- An asynchronous signal will be delivered to one of the threads
|
||||
of the program which does not block the signal (it is unspecified
|
||||
which).
|
||||
(No, the signal is delivered to the thread it's been sent to,
|
||||
based on the pid of the thread. If that thread is currently
|
||||
blocking the signal, the signal remains pending.)
|
||||
|
||||
4- The signal will be delivered to at most one thread.
|
||||
(OK, except for signals generated from the terminal or sent to
|
||||
the process group, which will be delivered to all threads.)
|
||||
|
||||
- The current implementation of the MIPS support assumes a MIPS ISA II
|
||||
processor or better. These processors support atomic operations by
|
||||
ll/sc instructions. Older R2000/R3000 series processors are not
|
||||
supported yet; support for these will have higher overhead.
|
||||
|
||||
- The current implementation of the ARM support assumes that the SWP
|
||||
(atomic swap register with memory) instruction is available. This is
|
||||
the case for all processors except for the ARM1 and ARM2. On StrongARM,
|
||||
the SWP instruction does not bypass the cache, so multi-processor support
|
||||
will be more troublesome.
|
@ -1,352 +0,0 @@
|
||||
This file describes how to make a threaded X11R6.
|
||||
|
||||
You need the source-code of XFree-3.2. I used the sources of X11R6.1
|
||||
(files: xc-1.tar.gz xc-2.tar.gz xc-3.tar.gz) and the patches to
|
||||
XFree-3.2 (files: README.X11.patch R6.1pl1-3.2.diff.gz cfont32.tgz).
|
||||
|
||||
Untar the xc-?.tar.gz files in a directory called XF3.2 and apply
|
||||
the XFree-3.2 patches as described in README.X11.patch or use the
|
||||
whole XFree86 source.
|
||||
|
||||
Now apply the thread patch with
|
||||
|
||||
patch -p0 < XF3.2.xc.diff
|
||||
|
||||
Go to the XF3.2/xc directory and make the whole thing:
|
||||
nice make World >& world.log &
|
||||
tail -f world.log
|
||||
|
||||
Wait a few hours or interrupt the process after the shared libs
|
||||
are made. The shared libs are:
|
||||
|
||||
XF3.2/xc/lib/ICE/libICE.so.6.0*
|
||||
XF3.2/xc/lib/PEX5/libPEX5.so.6.0*
|
||||
XF3.2/xc/lib/SM/libSM.so.6.0*
|
||||
XF3.2/xc/lib/X11/libX11.so.6.1*
|
||||
XF3.2/xc/lib/XIE/libXIE.so.6.0*
|
||||
XF3.2/xc/lib/XThrStub/libXThrStub.so.6.0*
|
||||
XF3.2/xc/lib/Xaw/libXaw.so.6.1*
|
||||
XF3.2/xc/lib/Xext/libXext.so.6.1*
|
||||
XF3.2/xc/lib/Xi/libXi.so.6.0*
|
||||
XF3.2/xc/lib/Xmu/libXmu.so.6.0*
|
||||
XF3.2/xc/lib/Xt/libXt.so.6.0*
|
||||
XF3.2/xc/lib/Xtst/libXtst.so.6.1*
|
||||
|
||||
(The Program dga didn't compile, but I have not check out why.)
|
||||
|
||||
Now you can copy the resulting libs
|
||||
|
||||
cp XF3.2/xc/lib/*/*.so.?.? /usr/X11R6/lib/
|
||||
|
||||
and create some links
|
||||
|
||||
cd /usr/X11R6/lib/
|
||||
ln -s libXThrStub.so.6.0 libXThrStub.so.6
|
||||
ln -s libXThrStub.so.6 libXThrStub.so
|
||||
|
||||
or use make install (not tested, and needs new configuration).
|
||||
|
||||
It is possible with the libXThrSub to compile X11 programs without linking
|
||||
libpthread to them and not necessary to recompile already installed
|
||||
unthreaded X11 programs, because libXThrSub keeps the dynamic linker quit.
|
||||
On the other hand you can link libpthread to a X11 program to use threads.
|
||||
|
||||
I used linux 2.0.23 and libc 5.4.7 .
|
||||
|
||||
Hans-Helmut Bühmann hans@expmech.ing.tu-bs.de
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
XF3.2.xc.diff:
|
||||
-----------------------------------------------------------------------------
|
||||
diff -u --recursive XF3.2.orig/xc/config/cf/linux.cf XF3.2/xc/config/cf/linux.cf
|
||||
--- XF3.2.orig/xc/config/cf/linux.cf Sun Nov 10 17:05:30 1996
|
||||
+++ XF3.2/xc/config/cf/linux.cf Sun Nov 10 16:30:55 1996
|
||||
@@ -61,6 +61,14 @@
|
||||
#define HasSnprintf YES
|
||||
#endif
|
||||
|
||||
+#define HasPosixThreads YES
|
||||
+#define ThreadedX YES
|
||||
+#define BuildThreadStubLibrary YES
|
||||
+#define NeedUIThrStubs YES
|
||||
+#define HasThreadSafeAPI NO
|
||||
+#define SystemMTDefines -D_REENTRANT
|
||||
+#define ThreadsLibraries -lpthread
|
||||
+
|
||||
#define AvoidNullMakeCommand YES
|
||||
#define StripInstalledPrograms YES
|
||||
#define CompressAllFonts YES
|
||||
@@ -158,7 +166,7 @@
|
||||
#define LdPostLib /* Never needed */
|
||||
|
||||
#ifdef i386Architecture
|
||||
-#define OptimizedCDebugFlags DefaultGcc2i386Opt -m486
|
||||
+#define OptimizedCDebugFlags DefaultGcc2i386Opt -m486 -pipe
|
||||
#define StandardDefines -Dlinux -D__i386__ -D_POSIX_SOURCE \
|
||||
-D_BSD_SOURCE -D_SVID_SOURCE -DX_LOCALE
|
||||
#define XawI18nDefines -DUSE_XWCHAR_STRING -DUSE_XMBTOWC
|
||||
diff -u --recursive XF3.2.orig/xc/config/cf/lnxLib.tmpl XF3.2/xc/config/cf/lnxLib.tmpl
|
||||
--- XF3.2.orig/xc/config/cf/lnxLib.tmpl Sun Nov 10 17:05:30 1996
|
||||
+++ XF3.2/xc/config/cf/lnxLib.tmpl Sat Nov 9 14:52:39 1996
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#define CplusplusLibC
|
||||
|
||||
-#define SharedX11Reqs
|
||||
+#define SharedX11Reqs -L$(BUILDLIBDIR) -lXThrStub
|
||||
#define SharedOldXReqs $(LDPRELIB) $(XLIBONLY)
|
||||
#define SharedXtReqs $(LDPRELIB) $(XLIBONLY) $(SMLIB) $(ICELIB)
|
||||
#define SharedXawReqs $(LDPRELIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
|
||||
diff -u --recursive XF3.2.orig/xc/include/Xthreads.h XF3.2/xc/include/Xthreads.h
|
||||
--- XF3.2.orig/xc/include/Xthreads.h Thu Dec 7 02:19:09 1995
|
||||
+++ XF3.2/xc/include/Xthreads.h Sat Nov 9 01:04:55 1996
|
||||
@@ -229,12 +229,12 @@
|
||||
#define xcondition_wait(c,m) pthread_cond_wait(c,m)
|
||||
#define xcondition_signal(c) pthread_cond_signal(c)
|
||||
#define xcondition_broadcast(c) pthread_cond_broadcast(c)
|
||||
-#ifdef _DECTHREADS_
|
||||
+#if defined(_DECTHREADS_) || defined(linux)
|
||||
static xthread_t _X_no_thread_id;
|
||||
#define xthread_have_id(id) !pthread_equal(id, _X_no_thread_id)
|
||||
#define xthread_clear_id(id) id = _X_no_thread_id
|
||||
#define xthread_equal(id1,id2) pthread_equal(id1, id2)
|
||||
-#endif /* _DECTHREADS_ */
|
||||
+#endif /* _DECTHREADS_ || linux */
|
||||
#if _CMA_VENDOR_ == _CMA__IBM
|
||||
#ifdef DEBUG /* too much of a hack to enable normally */
|
||||
/* see also cma__obj_set_name() */
|
||||
diff -u --recursive XF3.2.orig/xc/lib/X11/util/makekeys.c XF3.2/xc/lib/X11/util/makekeys.c
|
||||
--- XF3.2.orig/xc/lib/X11/util/makekeys.c Mon Apr 18 02:22:22 1994
|
||||
+++ XF3.2/xc/lib/X11/util/makekeys.c Sat Nov 9 00:44:14 1996
|
||||
@@ -73,7 +73,7 @@
|
||||
register char c;
|
||||
int first;
|
||||
int best_max_rehash;
|
||||
- int best_z;
|
||||
+ int best_z = 0;
|
||||
int num_found;
|
||||
KeySym val;
|
||||
|
||||
diff -u --recursive XF3.2.orig/xc/lib/XThrStub/Imakefile XF3.2/xc/lib/XThrStub/Imakefile
|
||||
--- XF3.2.orig/xc/lib/XThrStub/Imakefile Sun Nov 10 17:08:12 1996
|
||||
+++ XF3.2/xc/lib/XThrStub/Imakefile Sat Nov 9 19:04:51 1996
|
||||
@@ -25,7 +25,7 @@
|
||||
DEFINES = $(ALLOC_DEFINES)
|
||||
INCLUDES =
|
||||
SRCS = $(STUBSRCS)
|
||||
- OBJS = $(STUBOBJS
|
||||
+ OBJS = $(STUBOBJS)
|
||||
LINTLIBS = $(LINTXLIB)
|
||||
|
||||
#include <Library.tmpl>
|
||||
diff -u --recursive XF3.2.orig/xc/lib/XThrStub/UIThrStubs.c XF3.2/xc/lib/XThrStub/UIThrStubs.c
|
||||
--- XF3.2.orig/xc/lib/XThrStub/UIThrStubs.c Sun Nov 10 17:08:12 1996
|
||||
+++ XF3.2/xc/lib/XThrStub/UIThrStubs.c Sun Nov 10 15:14:55 1996
|
||||
@@ -37,16 +37,43 @@
|
||||
* specificies the thread library on the link line.
|
||||
*/
|
||||
|
||||
+#if defined(linux)
|
||||
+#include <pthread.h>
|
||||
+#else
|
||||
#include <thread.h>
|
||||
#include <synch.h>
|
||||
+#endif
|
||||
|
||||
+#if defined(linux)
|
||||
+static pthread_t no_thread_id;
|
||||
+#endif /* defined(linux) */
|
||||
+
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_self = _Xthr_self_stub_
|
||||
+pthread_t
|
||||
+_Xthr_self_stub_()
|
||||
+{
|
||||
+ return(no_thread_id);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak thr_self = _Xthr_self_stub_
|
||||
thread_t
|
||||
_Xthr_self_stub_()
|
||||
{
|
||||
return((thread_t)0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_mutex_init = _Xmutex_init_stub_
|
||||
+int
|
||||
+_Xmutex_init_stub_(m, a)
|
||||
+ pthread_mutex_t *m;
|
||||
+ __const pthread_mutexattr_t *a;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak mutex_init = _Xmutex_init_stub_
|
||||
int
|
||||
_Xmutex_init_stub_(m, t, a)
|
||||
@@ -56,7 +83,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_mutex_destroy = _Xmutex_destroy_stub_
|
||||
+int
|
||||
+_Xmutex_destroy_stub_(m)
|
||||
+ pthread_mutex_t *m;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak mutex_destroy = _Xmutex_destroy_stub_
|
||||
int
|
||||
_Xmutex_destroy_stub_(m)
|
||||
@@ -64,7 +101,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_mutex_lock = _Xmutex_lock_stub_
|
||||
+int
|
||||
+_Xmutex_lock_stub_(m)
|
||||
+ pthread_mutex_t *m;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak mutex_lock = _Xmutex_lock_stub_
|
||||
int
|
||||
_Xmutex_lock_stub_(m)
|
||||
@@ -72,7 +119,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_mutex_unlock = _Xmutex_unlock_stub_
|
||||
+int
|
||||
+_Xmutex_unlock_stub_(m)
|
||||
+ pthread_mutex_t *m;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak mutex_unlock = _Xmutex_unlock_stub_
|
||||
int
|
||||
_Xmutex_unlock_stub_(m)
|
||||
@@ -80,7 +137,18 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_cond_init = _Xcond_init_stub_
|
||||
+int
|
||||
+_Xcond_init_stub_(c, a)
|
||||
+ pthread_cond_t *c;
|
||||
+ __const pthread_condattr_t *a;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak cond_init = _Xcond_init_stub_
|
||||
int
|
||||
_Xcond_init_stub_(c, t, a)
|
||||
@@ -90,7 +158,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_cond_destroy = _Xcond_destroy_stub_
|
||||
+int
|
||||
+_Xcond_destroy_stub_(c)
|
||||
+ pthread_cond_t *c;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak cond_destroy = _Xcond_destroy_stub_
|
||||
int
|
||||
_Xcond_destroy_stub_(c)
|
||||
@@ -98,7 +176,18 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_cond_wait = _Xcond_wait_stub_
|
||||
+int
|
||||
+_Xcond_wait_stub_(c,m)
|
||||
+ pthread_cond_t *c;
|
||||
+ pthread_mutex_t *m;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak cond_wait = _Xcond_wait_stub_
|
||||
int
|
||||
_Xcond_wait_stub_(c,m)
|
||||
@@ -107,7 +196,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_cond_signal = _Xcond_signal_stub_
|
||||
+int
|
||||
+_Xcond_signal_stub_(c)
|
||||
+ pthread_cond_t *c;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak cond_signal = _Xcond_signal_stub_
|
||||
int
|
||||
_Xcond_signal_stub_(c)
|
||||
@@ -115,7 +214,17 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_cond_broadcast = _Xcond_broadcast_stub_
|
||||
+int
|
||||
+_Xcond_broadcast_stub_(c)
|
||||
+ pthread_cond_t *c;
|
||||
+{
|
||||
+ return(0);
|
||||
+}
|
||||
+#else /* defined(linux) */
|
||||
#pragma weak cond_broadcast = _Xcond_broadcast_stub_
|
||||
int
|
||||
_Xcond_broadcast_stub_(c)
|
||||
@@ -123,3 +232,15 @@
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
+#endif /* defined(linux) */
|
||||
+
|
||||
+#if defined(linux)
|
||||
+#pragma weak pthread_equal = _Xthr_equal_stub_
|
||||
+int
|
||||
+_Xthr_equal_stub_(t1, t2)
|
||||
+ pthread_t t1;
|
||||
+ pthread_t t2;
|
||||
+{
|
||||
+ return(1);
|
||||
+}
|
||||
+#endif /* defined(linux) */
|
||||
-------------------------------------------------------------------------
|
@ -1,188 +0,0 @@
|
||||
libc {
|
||||
GLIBC_2.0 {
|
||||
pthread_attr_destroy; pthread_attr_getdetachstate;
|
||||
pthread_attr_getinheritsched; pthread_attr_getschedparam;
|
||||
pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init;
|
||||
pthread_attr_setdetachstate; pthread_attr_setinheritsched;
|
||||
pthread_attr_setschedparam; pthread_attr_setschedpolicy;
|
||||
pthread_attr_setscope; pthread_cond_broadcast; pthread_cond_destroy;
|
||||
pthread_cond_init; pthread_cond_signal; pthread_cond_wait;
|
||||
pthread_cond_timedwait;
|
||||
pthread_condattr_destroy; pthread_condattr_init; pthread_equal;
|
||||
pthread_exit; pthread_getschedparam; pthread_mutex_destroy;
|
||||
pthread_mutex_init; pthread_mutex_lock; pthread_mutex_unlock;
|
||||
pthread_self; pthread_setcancelstate; pthread_setcanceltype;
|
||||
pthread_setschedparam;
|
||||
}
|
||||
GLIBC_2.1 {
|
||||
pthread_attr_init;
|
||||
}
|
||||
GLIBC_2.3.2 {
|
||||
# Changed pthread_cond_t.
|
||||
pthread_cond_init; pthread_cond_destroy;
|
||||
pthread_cond_wait; pthread_cond_signal;
|
||||
pthread_cond_broadcast; pthread_cond_timedwait;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
# Internal libc interface to libpthread
|
||||
__libc_dl_error_tsd;
|
||||
|
||||
__libc_pthread_init; __libc_current_sigrtmin_private;
|
||||
__libc_current_sigrtmax_private; __libc_allocate_rtsig_private;
|
||||
|
||||
__libc_creat; __libc_poll; __libc_pselect; __libc_select;
|
||||
__libc_sigpause; __libc_sigsuspend; __libc_sigwait; __libc_sigwaitinfo;
|
||||
__libc_waitid; __libc___xpg_sigpause; __librt_enable_asynccancel;
|
||||
__librt_disable_asynccancel; __librt_multiple_threads;
|
||||
|
||||
__libc_sigaction; __on_exit;
|
||||
}
|
||||
}
|
||||
|
||||
libpthread {
|
||||
GLIBC_2.0 {
|
||||
# Hidden entry point (through macros).
|
||||
_pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push;
|
||||
_pthread_cleanup_push_defer;
|
||||
|
||||
# Overwritten libc functions.
|
||||
accept; close; connect; fcntl; fork; fsync; longjmp; lseek; msync;
|
||||
nanosleep; open; pause; raise; read; recv; recvfrom; recvmsg; send;
|
||||
sendmsg; sendto; sigaction; siglongjmp; system; tcdrain; wait;
|
||||
waitpid; write;
|
||||
__close; __connect; __fcntl; __lseek; __open; __read; __send; __wait;
|
||||
__write;
|
||||
_IO_flockfile; _IO_ftrylockfile; _IO_funlockfile;
|
||||
vfork; __fork;
|
||||
|
||||
# POSIX.1c extensions to libc.
|
||||
flockfile; funlockfile; ftrylockfile;
|
||||
|
||||
# Non-standard POSIX1.x functions.
|
||||
pthread_kill_other_threads_np; pthread_mutexattr_getkind_np;
|
||||
pthread_mutexattr_setkind_np;
|
||||
|
||||
# Real POSIX.1c functions.
|
||||
pthread_atfork; pthread_attr_destroy; pthread_attr_getdetachstate;
|
||||
pthread_attr_getinheritsched; pthread_attr_getschedparam;
|
||||
pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init;
|
||||
pthread_attr_setdetachstate; pthread_attr_setinheritsched;
|
||||
pthread_attr_setschedparam; pthread_attr_setschedpolicy;
|
||||
pthread_attr_setscope; pthread_cancel; pthread_cond_broadcast;
|
||||
pthread_cond_destroy; pthread_cond_init; pthread_cond_signal;
|
||||
pthread_cond_timedwait; pthread_cond_wait; pthread_condattr_destroy;
|
||||
pthread_condattr_init; pthread_create; pthread_detach; pthread_equal;
|
||||
pthread_exit; pthread_getschedparam; pthread_getspecific; pthread_join;
|
||||
pthread_key_create; pthread_key_delete; pthread_kill;
|
||||
pthread_mutex_destroy; pthread_mutex_init; pthread_mutex_lock;
|
||||
pthread_mutex_trylock; pthread_mutex_unlock; pthread_mutexattr_destroy;
|
||||
pthread_mutexattr_init; pthread_once; pthread_self; pthread_setcancelstate;
|
||||
pthread_setcanceltype; pthread_setschedparam; pthread_setspecific;
|
||||
pthread_sigmask; pthread_testcancel;
|
||||
|
||||
sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
|
||||
sigwait;
|
||||
|
||||
# Protected names for functions used in other shared objects.
|
||||
__pthread_atfork; __pthread_getspecific;
|
||||
__pthread_key_create; __pthread_mutex_destroy; __pthread_mutex_init;
|
||||
__pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock;
|
||||
__pthread_mutexattr_destroy; __pthread_mutexattr_init;
|
||||
__pthread_mutexattr_settype; __pthread_once; __pthread_setspecific;
|
||||
|
||||
# The error functions.
|
||||
__errno_location; __h_errno_location;
|
||||
|
||||
# Must be preemptible
|
||||
__sigaction;
|
||||
}
|
||||
GLIBC_2.1 {
|
||||
# Functions with changed interface.
|
||||
pthread_attr_init; pthread_create;
|
||||
|
||||
# Unix98 extensions.
|
||||
pthread_rwlock_init; pthread_rwlock_destroy; pthread_rwlock_rdlock;
|
||||
pthread_rwlock_tryrdlock; pthread_rwlock_wrlock; 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_attr_getguardsize; pthread_attr_setguardsize;
|
||||
pthread_attr_getstackaddr; pthread_attr_setstackaddr;
|
||||
pthread_attr_getstacksize; pthread_attr_setstacksize;
|
||||
|
||||
pthread_getconcurrency; pthread_setconcurrency;
|
||||
|
||||
pthread_mutexattr_gettype; pthread_mutexattr_settype;
|
||||
|
||||
sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
|
||||
|
||||
# helper functions
|
||||
__libc_current_sigrtmin; __libc_current_sigrtmax;
|
||||
__libc_allocate_rtsig;
|
||||
}
|
||||
GLIBC_2.1.1 {
|
||||
sem_close; sem_open; sem_unlink;
|
||||
}
|
||||
GLIBC_2.1.2 {
|
||||
__vfork;
|
||||
}
|
||||
GLIBC_2.2 {
|
||||
# For the cancelation wrappers.
|
||||
pread; __pread64; pread64; pwrite; __pwrite64; pwrite64; lseek64;
|
||||
open64; __open64;
|
||||
|
||||
__res_state;
|
||||
|
||||
# Names used internally.
|
||||
__pthread_rwlock_init; __pthread_rwlock_destroy; __pthread_rwlock_rdlock;
|
||||
__pthread_rwlock_tryrdlock; __pthread_rwlock_wrlock;
|
||||
__pthread_rwlock_trywrlock; __pthread_rwlock_unlock;
|
||||
|
||||
# No really implemented.
|
||||
pthread_condattr_getpshared; pthread_condattr_setpshared;
|
||||
pthread_mutexattr_getpshared; pthread_mutexattr_setpshared;
|
||||
|
||||
# New functions from IEEE Std. 1003.1-200x.
|
||||
sem_timedwait;
|
||||
pthread_attr_getstack; pthread_attr_setstack;
|
||||
pthread_spin_destroy; pthread_spin_init; pthread_spin_lock;
|
||||
pthread_spin_trylock; pthread_spin_unlock;
|
||||
pthread_getcpuclockid;
|
||||
pthread_barrier_destroy; pthread_barrier_init; pthread_barrier_wait;
|
||||
pthread_barrierattr_destroy; pthread_barrierattr_init;
|
||||
pthread_barrierattr_setpshared;
|
||||
pthread_mutex_timedlock;
|
||||
pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock;
|
||||
|
||||
# Extensions.
|
||||
pthread_yield;
|
||||
}
|
||||
GLIBC_2.2.3 {
|
||||
# Extensions.
|
||||
pthread_getattr_np;
|
||||
}
|
||||
GLIBC_2.2.6 {
|
||||
# Cancellation wrapper
|
||||
__nanosleep;
|
||||
}
|
||||
GLIBC_2.3.2 {
|
||||
# Changed pthread_cond_t.
|
||||
pthread_cond_init; pthread_cond_destroy;
|
||||
pthread_cond_wait; pthread_cond_timedwait;
|
||||
pthread_cond_signal; pthread_cond_broadcast;
|
||||
}
|
||||
|
||||
# Hey you!! Yes, YOU! Do not add new symbols here!
|
||||
# The linuxthreads libpthread ABI froze at GLIBC_2.3.2 and lacks
|
||||
# numerous additions that NPTL's libpthread has. We can't go adding
|
||||
# any new symbols here unless we support all the new symbols in NPTL,
|
||||
# and we don't want to do that. Linuxthreads is only alive for
|
||||
# compatibility with old binaries using old interfaces.
|
||||
|
||||
GLIBC_PRIVATE {
|
||||
# Internal libc interface to libpthread
|
||||
__pthread_initialize;
|
||||
__pthread_kill_other_threads_np;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/* Determine whether block of given size can be allocated on the stack or not.
|
||||
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; 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 "internals.h"
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
int
|
||||
__libc_alloca_cutoff (size_t size)
|
||||
{
|
||||
if (! SINGLE_THREAD_P)
|
||||
{
|
||||
pthread_descr self = thread_self ();
|
||||
return size <= LIBC_THREAD_GETMEM (self, p_alloca_cutoff);
|
||||
}
|
||||
|
||||
return size <= __MAX_ALLOCA_CUTOFF;
|
||||
}
|
@ -1,485 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Handling of thread attributes */
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include <shlib-compat.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
|
||||
int __pthread_attr_init_2_1(pthread_attr_t *attr)
|
||||
{
|
||||
size_t ps = __getpagesize ();
|
||||
|
||||
attr->__detachstate = PTHREAD_CREATE_JOINABLE;
|
||||
attr->__schedpolicy = SCHED_OTHER;
|
||||
attr->__schedparam.sched_priority = 0;
|
||||
attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
|
||||
attr->__scope = PTHREAD_SCOPE_SYSTEM;
|
||||
#ifdef NEED_SEPARATE_REGISTER_STACK
|
||||
attr->__guardsize = ps + ps;
|
||||
#else
|
||||
attr->__guardsize = ps;
|
||||
#endif
|
||||
attr->__stackaddr = NULL;
|
||||
attr->__stackaddr_set = 0;
|
||||
attr->__stacksize = STACK_SIZE - ps;
|
||||
return 0;
|
||||
}
|
||||
|
||||
versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init,
|
||||
GLIBC_2_1);
|
||||
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
|
||||
int __pthread_attr_init_2_0(pthread_attr_t *attr)
|
||||
{
|
||||
attr->__detachstate = PTHREAD_CREATE_JOINABLE;
|
||||
attr->__schedpolicy = SCHED_OTHER;
|
||||
attr->__schedparam.sched_priority = 0;
|
||||
attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
|
||||
attr->__scope = PTHREAD_SCOPE_SYSTEM;
|
||||
return 0;
|
||||
}
|
||||
compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
int __pthread_attr_destroy(pthread_attr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_destroy, pthread_attr_destroy);
|
||||
|
||||
int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
|
||||
{
|
||||
if (detachstate < PTHREAD_CREATE_JOINABLE ||
|
||||
detachstate > PTHREAD_CREATE_DETACHED)
|
||||
return EINVAL;
|
||||
attr->__detachstate = detachstate;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate);
|
||||
|
||||
int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
|
||||
{
|
||||
*detachstate = attr->__detachstate;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate);
|
||||
|
||||
int __pthread_attr_setschedparam(pthread_attr_t *attr,
|
||||
const struct sched_param *param)
|
||||
{
|
||||
int max_prio = __sched_get_priority_max(attr->__schedpolicy);
|
||||
int min_prio = __sched_get_priority_min(attr->__schedpolicy);
|
||||
|
||||
if (param->sched_priority < min_prio || param->sched_priority > max_prio)
|
||||
return EINVAL;
|
||||
memcpy (&attr->__schedparam, param, sizeof (struct sched_param));
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam);
|
||||
|
||||
int __pthread_attr_getschedparam(const pthread_attr_t *attr,
|
||||
struct sched_param *param)
|
||||
{
|
||||
memcpy (param, &attr->__schedparam, sizeof (struct sched_param));
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam);
|
||||
|
||||
int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
|
||||
{
|
||||
if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
|
||||
return EINVAL;
|
||||
attr->__schedpolicy = policy;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
|
||||
|
||||
int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
|
||||
{
|
||||
*policy = attr->__schedpolicy;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
|
||||
|
||||
int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
|
||||
{
|
||||
if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
|
||||
return EINVAL;
|
||||
attr->__inheritsched = inherit;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched);
|
||||
|
||||
int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
|
||||
{
|
||||
*inherit = attr->__inheritsched;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched);
|
||||
|
||||
int __pthread_attr_setscope(pthread_attr_t *attr, int scope)
|
||||
{
|
||||
switch (scope) {
|
||||
case PTHREAD_SCOPE_SYSTEM:
|
||||
attr->__scope = scope;
|
||||
return 0;
|
||||
case PTHREAD_SCOPE_PROCESS:
|
||||
return ENOTSUP;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_attr_setscope, pthread_attr_setscope);
|
||||
|
||||
int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
|
||||
{
|
||||
*scope = attr->__scope;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_attr_getscope, pthread_attr_getscope);
|
||||
|
||||
int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
|
||||
{
|
||||
/* The guard size must not be larger than the stack itself */
|
||||
if (guardsize >= attr->__stacksize) return EINVAL;
|
||||
|
||||
attr->__guardsize = guardsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize)
|
||||
|
||||
int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
|
||||
{
|
||||
*guardsize = attr->__guardsize;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize)
|
||||
|
||||
int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
|
||||
{
|
||||
attr->__stackaddr = stackaddr;
|
||||
attr->__stackaddr_set = 1;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
|
||||
|
||||
link_warning (pthread_attr_setstackaddr,
|
||||
"the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
|
||||
|
||||
int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
|
||||
{
|
||||
/* XXX This function has a stupid definition. The standard specifies
|
||||
no error value but what is if no stack address was set? We simply
|
||||
return the value we have in the member. */
|
||||
*stackaddr = attr->__stackaddr;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
|
||||
|
||||
link_warning (pthread_attr_getstackaddr,
|
||||
"the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
|
||||
|
||||
|
||||
int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
|
||||
{
|
||||
#ifdef FLOATING_STACKS
|
||||
/* We have to check against the maximum allowed stack size. This is no
|
||||
problem if the manager is already started and we determined it. If
|
||||
this hasn't happened, we have to find the limit outself. */
|
||||
if (__pthread_max_stacksize == 0)
|
||||
__pthread_init_max_stacksize ();
|
||||
|
||||
if (stacksize > __pthread_max_stacksize)
|
||||
return EINVAL;
|
||||
#else
|
||||
/* We have a fixed size limit. */
|
||||
if (stacksize > STACK_SIZE)
|
||||
return EINVAL;
|
||||
#endif
|
||||
|
||||
/* We don't accept value smaller than PTHREAD_STACK_MIN. */
|
||||
if (stacksize < PTHREAD_STACK_MIN)
|
||||
return EINVAL;
|
||||
|
||||
attr->__stacksize = stacksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if PTHREAD_STACK_MIN == 16384
|
||||
weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
|
||||
#else
|
||||
versioned_symbol (libpthread, __pthread_attr_setstacksize,
|
||||
pthread_attr_setstacksize, GLIBC_2_3_3);
|
||||
|
||||
# if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3)
|
||||
|
||||
int __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
|
||||
{
|
||||
# ifdef FLOATING_STACKS
|
||||
/* We have to check against the maximum allowed stack size. This is no
|
||||
problem if the manager is already started and we determined it. If
|
||||
this hasn't happened, we have to find the limit outself. */
|
||||
if (__pthread_max_stacksize == 0)
|
||||
__pthread_init_max_stacksize ();
|
||||
|
||||
if (stacksize > __pthread_max_stacksize)
|
||||
return EINVAL;
|
||||
# else
|
||||
/* We have a fixed size limit. */
|
||||
if (stacksize > STACK_SIZE)
|
||||
return EINVAL;
|
||||
# endif
|
||||
|
||||
/* We don't accept value smaller than old PTHREAD_STACK_MIN. */
|
||||
if (stacksize < 16384)
|
||||
return EINVAL;
|
||||
|
||||
attr->__stacksize = stacksize;
|
||||
return 0;
|
||||
}
|
||||
compat_symbol (libpthread, __old_pthread_attr_setstacksize,
|
||||
pthread_attr_setstacksize, GLIBC_2_1);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
|
||||
{
|
||||
*stacksize = attr->__stacksize;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
|
||||
|
||||
int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
|
||||
size_t stacksize)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((((uintptr_t) stackaddr)
|
||||
& (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
|
||||
err = EINVAL;
|
||||
else
|
||||
err = __pthread_attr_setstacksize (attr, stacksize);
|
||||
if (err == 0)
|
||||
{
|
||||
#ifndef _STACK_GROWS_UP
|
||||
attr->__stackaddr = (char *) stackaddr + stacksize;
|
||||
#else
|
||||
attr->__stackaddr = stackaddr;
|
||||
#endif
|
||||
attr->__stackaddr_set = 1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if PTHREAD_STACK_MIN == 16384
|
||||
weak_alias (__pthread_attr_setstack, pthread_attr_setstack)
|
||||
#else
|
||||
versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack,
|
||||
GLIBC_2_3_3);
|
||||
# if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3)
|
||||
int __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
|
||||
size_t stacksize)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((((uintptr_t) stackaddr)
|
||||
& (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
|
||||
err = EINVAL;
|
||||
else
|
||||
err = __old_pthread_attr_setstacksize (attr, stacksize);
|
||||
if (err == 0)
|
||||
{
|
||||
# ifndef _STACK_GROWS_UP
|
||||
attr->__stackaddr = (char *) stackaddr + stacksize;
|
||||
# else
|
||||
attr->__stackaddr = stackaddr;
|
||||
# endif
|
||||
attr->__stackaddr_set = 1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack,
|
||||
GLIBC_2_2);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr,
|
||||
size_t *stacksize)
|
||||
{
|
||||
/* XXX This function has a stupid definition. The standard specifies
|
||||
no error value but what is if no stack address was set? We simply
|
||||
return the value we have in the member. */
|
||||
#ifndef _STACK_GROWS_UP
|
||||
*stackaddr = (char *) attr->__stackaddr - attr->__stacksize;
|
||||
#else
|
||||
*stackaddr = attr->__stackaddr;
|
||||
#endif
|
||||
*stacksize = attr->__stacksize;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_attr_getstack, pthread_attr_getstack)
|
||||
|
||||
int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
|
||||
{
|
||||
pthread_handle handle = thread_handle (thread);
|
||||
pthread_descr descr;
|
||||
int ret = 0;
|
||||
|
||||
if (handle == NULL)
|
||||
return ENOENT;
|
||||
|
||||
descr = handle->h_descr;
|
||||
|
||||
attr->__detachstate = (descr->p_detached
|
||||
? PTHREAD_CREATE_DETACHED
|
||||
: PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
attr->__schedpolicy = __sched_getscheduler (descr->p_pid);
|
||||
if (attr->__schedpolicy == -1)
|
||||
return errno;
|
||||
|
||||
if (__sched_getparam (descr->p_pid,
|
||||
(struct sched_param *) &attr->__schedparam) != 0)
|
||||
return errno;
|
||||
|
||||
attr->__inheritsched = descr->p_inheritsched;
|
||||
attr->__scope = PTHREAD_SCOPE_SYSTEM;
|
||||
|
||||
#ifdef _STACK_GROWS_DOWN
|
||||
# ifdef USE_TLS
|
||||
attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr
|
||||
- descr->p_guardsize;
|
||||
# else
|
||||
attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
|
||||
- descr->p_guardsize;
|
||||
# endif
|
||||
#else
|
||||
# ifdef USE_TLS
|
||||
attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr;
|
||||
# else
|
||||
attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
|
||||
# endif
|
||||
#endif
|
||||
attr->__guardsize = descr->p_guardsize;
|
||||
attr->__stackaddr_set = descr->p_userstack;
|
||||
#ifdef NEED_SEPARATE_REGISTER_STACK
|
||||
if (descr->p_userstack == 0)
|
||||
attr->__stacksize *= 2;
|
||||
/* XXX This is awkward. The guard pages are in the middle of the
|
||||
two stacks. We must count the guard size in the stack size since
|
||||
otherwise the range of the stack area cannot be computed. */
|
||||
attr->__stacksize += attr->__guardsize;
|
||||
#endif
|
||||
#ifdef USE_TLS
|
||||
attr->__stackaddr = descr->p_stackaddr;
|
||||
#else
|
||||
# ifndef _STACK_GROWS_UP
|
||||
attr->__stackaddr = (char *)(descr + 1);
|
||||
# else
|
||||
attr->__stackaddr = (char *)descr;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_TLS
|
||||
if (attr->__stackaddr == NULL)
|
||||
#else
|
||||
if (descr == &__pthread_initial_thread)
|
||||
#endif
|
||||
{
|
||||
/* 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. */
|
||||
attr->__stacksize = rl.rlim_cur;
|
||||
#ifdef _STACK_GROWS_UP
|
||||
/* Don't check to enforce a limit on the __stacksize */
|
||||
attr->__stackaddr = (void *) from;
|
||||
#else
|
||||
attr->__stackaddr = (void *) to;
|
||||
|
||||
/* The limit might be too high. */
|
||||
if ((size_t) attr->__stacksize
|
||||
> (size_t) attr->__stackaddr - last_to)
|
||||
attr->__stacksize = (size_t) attr->__stackaddr - last_to;
|
||||
#endif
|
||||
|
||||
/* We succeed and no need to look further. */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
last_to = to;
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
free (line);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/* POSIX barrier implementation for LinuxThreads.
|
||||
Copyright (C) 2000, 2003 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 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 "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "queue.h"
|
||||
#include "restart.h"
|
||||
|
||||
int
|
||||
pthread_barrier_wait(pthread_barrier_t *barrier)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
pthread_descr temp_wake_queue, th;
|
||||
int result = 0;
|
||||
|
||||
__pthread_lock(&barrier->__ba_lock, self);
|
||||
|
||||
/* If the required number of threads have achieved rendezvous... */
|
||||
if (barrier->__ba_present >= barrier->__ba_required - 1)
|
||||
{
|
||||
/* ... then this last caller shall be the serial thread */
|
||||
result = PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
/* Copy and clear wait queue and reset barrier. */
|
||||
temp_wake_queue = barrier->__ba_waiting;
|
||||
barrier->__ba_waiting = NULL;
|
||||
barrier->__ba_present = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
barrier->__ba_present++;
|
||||
enqueue(&barrier->__ba_waiting, self);
|
||||
}
|
||||
|
||||
__pthread_unlock(&barrier->__ba_lock);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
/* Non-serial threads have to suspend */
|
||||
suspend(self);
|
||||
/* We don't bother dealing with cancellation because the POSIX
|
||||
spec for barriers doesn't mention that pthread_barrier_wait
|
||||
is a cancellation point. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Serial thread wakes up all others. */
|
||||
while ((th = dequeue(&temp_wake_queue)) != NULL)
|
||||
restart(th);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_barrier_init(pthread_barrier_t *barrier,
|
||||
const pthread_barrierattr_t *attr,
|
||||
unsigned int count)
|
||||
{
|
||||
if (count == 0)
|
||||
return EINVAL;
|
||||
|
||||
__pthread_init_lock(&barrier->__ba_lock);
|
||||
barrier->__ba_required = count;
|
||||
barrier->__ba_present = 0;
|
||||
barrier->__ba_waiting = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_barrier_destroy(pthread_barrier_t *barrier)
|
||||
{
|
||||
if (barrier->__ba_waiting != NULL) return EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_barrierattr_init(pthread_barrierattr_t *attr)
|
||||
{
|
||||
attr->__pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
|
||||
int *pshared)
|
||||
{
|
||||
*pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
|
||||
{
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
|
||||
return EINVAL;
|
||||
|
||||
/* For now it is not possible to shared a conditional variable. */
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
||||
return ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/* PR libc/4005 */
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
void *
|
||||
run_thread (void *a)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
sleep (10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
pthread_t thr;
|
||||
void *result;
|
||||
alarm (4);
|
||||
printf ("Starting thread.\n");
|
||||
pthread_create (&thr, 0, run_thread, 0);
|
||||
sleep (2);
|
||||
printf ("Canceling thread.\n");
|
||||
pthread_cancel (thr);
|
||||
pthread_join (thr, &result);
|
||||
if (result == PTHREAD_CANCELED)
|
||||
printf ("Thread canceled.\n");
|
||||
else
|
||||
printf ("Thread exited.\n");
|
||||
return 0;
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Thread cancellation */
|
||||
|
||||
#include <errno.h>
|
||||
#include <libc-internal.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "restart.h"
|
||||
|
||||
#ifdef _STACK_GROWS_DOWN
|
||||
# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
|
||||
#elif _STACK_GROWS_UP
|
||||
# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
|
||||
#else
|
||||
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
|
||||
#endif
|
||||
|
||||
|
||||
int __pthread_setcancelstate(int state, int * oldstate)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
|
||||
return EINVAL;
|
||||
if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate);
|
||||
THREAD_SETMEM(self, p_cancelstate, state);
|
||||
if (THREAD_GETMEM(self, p_canceled) &&
|
||||
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
|
||||
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_setcancelstate, pthread_setcancelstate);
|
||||
|
||||
int __pthread_setcanceltype(int type, int * oldtype)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||
return EINVAL;
|
||||
if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype);
|
||||
THREAD_SETMEM(self, p_canceltype, type);
|
||||
if (THREAD_GETMEM(self, p_canceled) &&
|
||||
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
|
||||
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_setcanceltype, pthread_setcanceltype);
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
int oldtype = THREAD_GETMEM(self, p_canceltype);
|
||||
THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
|
||||
if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) &&
|
||||
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
return oldtype;
|
||||
}
|
||||
|
||||
void
|
||||
internal_function attribute_hidden
|
||||
__pthread_disable_asynccancel (int oldtype)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
THREAD_SETMEM(self, p_canceltype, oldtype);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cancel(pthread_t thread)
|
||||
{
|
||||
pthread_handle handle = thread_handle(thread);
|
||||
int pid;
|
||||
int dorestart = 0;
|
||||
pthread_descr th;
|
||||
pthread_extricate_if *pextricate;
|
||||
int already_canceled;
|
||||
|
||||
__pthread_lock(&handle->h_lock, NULL);
|
||||
if (invalid_handle(handle, thread)) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
th = handle->h_descr;
|
||||
|
||||
already_canceled = th->p_canceled;
|
||||
th->p_canceled = 1;
|
||||
|
||||
if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pextricate = th->p_extricate;
|
||||
pid = th->p_pid;
|
||||
|
||||
/* If the thread has registered an extrication interface, then
|
||||
invoke the interface. If it returns 1, then we succeeded in
|
||||
dequeuing the thread from whatever waiting object it was enqueued
|
||||
with. In that case, it is our responsibility to wake it up.
|
||||
And also to set the p_woken_by_cancel flag so the woken thread
|
||||
can tell that it was woken by cancellation. */
|
||||
|
||||
if (pextricate != NULL) {
|
||||
dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th);
|
||||
th->p_woken_by_cancel = dorestart;
|
||||
}
|
||||
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
|
||||
/* If the thread has suspended or is about to, then we unblock it by
|
||||
issuing a restart, instead of a cancel signal. Otherwise we send
|
||||
the cancel signal to unblock the thread from a cancellation point,
|
||||
or to initiate asynchronous cancellation. The restart is needed so
|
||||
we have proper accounting of restarts; suspend decrements the thread's
|
||||
resume count, and restart() increments it. This also means that suspend's
|
||||
handling of the cancel signal is obsolete. */
|
||||
|
||||
if (dorestart)
|
||||
restart(th);
|
||||
else
|
||||
kill(pid, __pthread_sig_cancel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pthread_testcancel(void)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
if (THREAD_GETMEM(self, p_canceled)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
|
||||
void (*routine)(void *), void * arg)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
buffer->__routine = routine;
|
||||
buffer->__arg = arg;
|
||||
buffer->__prev = THREAD_GETMEM(self, p_cleanup);
|
||||
if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
|
||||
buffer->__prev = NULL;
|
||||
THREAD_SETMEM(self, p_cleanup, buffer);
|
||||
}
|
||||
|
||||
void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
|
||||
int execute)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
if (execute) buffer->__routine(buffer->__arg);
|
||||
THREAD_SETMEM(self, p_cleanup, buffer->__prev);
|
||||
}
|
||||
|
||||
void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
|
||||
void (*routine)(void *), void * arg)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
buffer->__routine = routine;
|
||||
buffer->__arg = arg;
|
||||
buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
|
||||
buffer->__prev = THREAD_GETMEM(self, p_cleanup);
|
||||
if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
|
||||
buffer->__prev = NULL;
|
||||
THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
|
||||
THREAD_SETMEM(self, p_cleanup, buffer);
|
||||
}
|
||||
|
||||
void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
|
||||
int execute)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
if (execute) buffer->__routine(buffer->__arg);
|
||||
THREAD_SETMEM(self, p_cleanup, buffer->__prev);
|
||||
THREAD_SETMEM(self, p_canceltype, buffer->__canceltype);
|
||||
if (THREAD_GETMEM(self, p_canceled) &&
|
||||
THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
|
||||
THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
void __pthread_perform_cleanup(char *currentframe)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
struct _pthread_cleanup_buffer *c = THREAD_GETMEM(self, p_cleanup);
|
||||
struct _pthread_cleanup_buffer *last;
|
||||
|
||||
if (c != NULL)
|
||||
while (FRAME_LEFT (currentframe, c))
|
||||
{
|
||||
last = c;
|
||||
c = c->__prev;
|
||||
|
||||
if (c == NULL || FRAME_LEFT (last, c))
|
||||
{
|
||||
c = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (c != NULL)
|
||||
{
|
||||
c->__routine(c->__arg);
|
||||
|
||||
last = c;
|
||||
c = c->__prev;
|
||||
|
||||
if (FRAME_LEFT (last, c))
|
||||
break;
|
||||
}
|
||||
|
||||
/* And the TSD which needs special help. */
|
||||
THREAD_SETMEM (self, p_cancelstate, PTHREAD_CANCEL_DISABLE);
|
||||
__libc_thread_freeres ();
|
||||
}
|
@ -1,341 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* and Pavel Krauz (krauz@fsid.cvut.cz). */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Condition variables */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/time.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "queue.h"
|
||||
#include "restart.h"
|
||||
#include <shlib-compat.h>
|
||||
|
||||
int __pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *cond_attr)
|
||||
{
|
||||
__pthread_init_lock(&cond->__c_lock);
|
||||
cond->__c_waiting = NULL;
|
||||
return 0;
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_init, __old_pthread_cond_init)
|
||||
compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
int __pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
if (cond->__c_waiting != NULL) return EBUSY;
|
||||
return 0;
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_destroy, __old_pthread_cond_destroy)
|
||||
compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
/* Function called by pthread_cancel to remove the thread from
|
||||
waiting on a condition variable queue. */
|
||||
|
||||
static int cond_extricate_func(void *obj, pthread_descr th)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
pthread_cond_t *cond = obj;
|
||||
int did_remove = 0;
|
||||
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
did_remove = remove_from_queue(&cond->__c_waiting, th);
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
|
||||
return did_remove;
|
||||
}
|
||||
|
||||
int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
pthread_extricate_if extr;
|
||||
int already_canceled = 0;
|
||||
int spurious_wakeup_count;
|
||||
|
||||
/* Check whether the mutex is locked and owned by this thread. */
|
||||
if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
|
||||
&& mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
|
||||
&& mutex->__m_owner != self)
|
||||
return EINVAL;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = cond;
|
||||
extr.pu_extricate_func = cond_extricate_func;
|
||||
|
||||
/* Register extrication interface */
|
||||
THREAD_SETMEM(self, p_condvar_avail, 0);
|
||||
__pthread_set_own_extricate_if(self, &extr);
|
||||
|
||||
/* Atomically enqueue thread for waiting, but only if it is not
|
||||
canceled. If the thread is canceled, then it will fall through the
|
||||
suspend call below, and then call pthread_exit without
|
||||
having to worry about whether it is still on the condition variable queue.
|
||||
This depends on pthread_cancel setting p_canceled before calling the
|
||||
extricate function. */
|
||||
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
if (!(THREAD_GETMEM(self, p_canceled)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
|
||||
enqueue(&cond->__c_waiting, self);
|
||||
else
|
||||
already_canceled = 1;
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
|
||||
if (already_canceled) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutex);
|
||||
|
||||
spurious_wakeup_count = 0;
|
||||
while (1)
|
||||
{
|
||||
suspend(self);
|
||||
if (THREAD_GETMEM(self, p_condvar_avail) == 0
|
||||
&& (THREAD_GETMEM(self, p_woken_by_cancel) == 0
|
||||
|| THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
|
||||
{
|
||||
/* Count resumes that don't belong to us. */
|
||||
spurious_wakeup_count++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
|
||||
/* Check for cancellation again, to provide correct cancellation
|
||||
point behavior */
|
||||
|
||||
if (THREAD_GETMEM(self, p_woken_by_cancel)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
|
||||
THREAD_SETMEM(self, p_woken_by_cancel, 0);
|
||||
pthread_mutex_lock(mutex);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
/* Put back any resumes we caught that don't belong to us. */
|
||||
while (spurious_wakeup_count--)
|
||||
restart(self);
|
||||
|
||||
pthread_mutex_lock(mutex);
|
||||
return 0;
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_wait, __old_pthread_cond_wait)
|
||||
compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
static int
|
||||
pthread_cond_timedwait_relative(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
int already_canceled = 0;
|
||||
pthread_extricate_if extr;
|
||||
int spurious_wakeup_count;
|
||||
|
||||
/* Check whether the mutex is locked and owned by this thread. */
|
||||
if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
|
||||
&& mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
|
||||
&& mutex->__m_owner != self)
|
||||
return EINVAL;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = cond;
|
||||
extr.pu_extricate_func = cond_extricate_func;
|
||||
|
||||
/* Register extrication interface */
|
||||
THREAD_SETMEM(self, p_condvar_avail, 0);
|
||||
__pthread_set_own_extricate_if(self, &extr);
|
||||
|
||||
/* Enqueue to wait on the condition and check for cancellation. */
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
if (!(THREAD_GETMEM(self, p_canceled)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
|
||||
enqueue(&cond->__c_waiting, self);
|
||||
else
|
||||
already_canceled = 1;
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
|
||||
if (already_canceled) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(mutex);
|
||||
|
||||
spurious_wakeup_count = 0;
|
||||
while (1)
|
||||
{
|
||||
if (!timedsuspend(self, abstime)) {
|
||||
int was_on_queue;
|
||||
|
||||
/* __pthread_lock will queue back any spurious restarts that
|
||||
may happen to it. */
|
||||
|
||||
__pthread_lock(&cond->__c_lock, self);
|
||||
was_on_queue = remove_from_queue(&cond->__c_waiting, self);
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
|
||||
if (was_on_queue) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
pthread_mutex_lock(mutex);
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Eat the outstanding restart() from the signaller */
|
||||
suspend(self);
|
||||
}
|
||||
|
||||
if (THREAD_GETMEM(self, p_condvar_avail) == 0
|
||||
&& (THREAD_GETMEM(self, p_woken_by_cancel) == 0
|
||||
|| THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
|
||||
{
|
||||
/* Count resumes that don't belong to us. */
|
||||
spurious_wakeup_count++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
|
||||
/* The remaining logic is the same as in other cancellable waits,
|
||||
such as pthread_join sem_wait or pthread_cond wait. */
|
||||
|
||||
if (THREAD_GETMEM(self, p_woken_by_cancel)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
|
||||
THREAD_SETMEM(self, p_woken_by_cancel, 0);
|
||||
pthread_mutex_lock(mutex);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
/* Put back any resumes we caught that don't belong to us. */
|
||||
while (spurious_wakeup_count--)
|
||||
restart(self);
|
||||
|
||||
pthread_mutex_lock(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
/* Indirect call through pointer! */
|
||||
return pthread_cond_timedwait_relative(cond, mutex, abstime);
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_timedwait, __old_pthread_cond_timedwait)
|
||||
compat_symbol (libpthread, __old_pthread_cond_timedwait,
|
||||
pthread_cond_timedwait, GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
int __pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
pthread_descr th;
|
||||
|
||||
__pthread_lock(&cond->__c_lock, NULL);
|
||||
th = dequeue(&cond->__c_waiting);
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
if (th != NULL) {
|
||||
th->p_condvar_avail = 1;
|
||||
WRITE_MEMORY_BARRIER();
|
||||
restart(th);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_signal, __old_pthread_cond_signal)
|
||||
compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
int __pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
pthread_descr tosignal, th;
|
||||
|
||||
__pthread_lock(&cond->__c_lock, NULL);
|
||||
/* Copy the current state of the waiting queue and empty it */
|
||||
tosignal = cond->__c_waiting;
|
||||
cond->__c_waiting = NULL;
|
||||
__pthread_unlock(&cond->__c_lock);
|
||||
/* Now signal each process in the queue */
|
||||
while ((th = dequeue(&tosignal)) != NULL) {
|
||||
th->p_condvar_avail = 1;
|
||||
WRITE_MEMORY_BARRIER();
|
||||
restart(th);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
|
||||
GLIBC_2_3_2);
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_broadcast, __old_pthread_cond_broadcast)
|
||||
compat_symbol (libpthread, __old_pthread_cond_broadcast,
|
||||
pthread_cond_broadcast, GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
int __pthread_condattr_init(pthread_condattr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_condattr_init, pthread_condattr_init)
|
||||
|
||||
int __pthread_condattr_destroy(pthread_condattr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy)
|
||||
|
||||
int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
|
||||
{
|
||||
*pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
|
||||
{
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
|
||||
return EINVAL;
|
||||
|
||||
/* For now it is not possible to shared a conditional variable. */
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
||||
return ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
17
linuxthreads/configure
vendored
17
linuxthreads/configure
vendored
@ -1,17 +0,0 @@
|
||||
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
|
||||
|
||||
# LinuxThreads fragment for GNU C library configure mechanism.
|
||||
# This is a shell script fragment sourced by the main configure script.
|
||||
|
||||
for other in $add_ons; do
|
||||
test $other = nptl || continue
|
||||
if test $add_ons_automatic = yes; then
|
||||
echo "$as_me:$LINENO: result: $libc_add_on disabled because $other add-on is also in use" >&5
|
||||
echo "${ECHO_T}$libc_add_on disabled because $other add-on is also in use" >&6
|
||||
libc_add_on=
|
||||
else
|
||||
{ { echo "$as_me:$LINENO: error: cannot use both $libc_add_on and $other add-ons in one build" >&5
|
||||
echo "$as_me: error: cannot use both $libc_add_on and $other add-ons in one build" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
done
|
@ -1,14 +0,0 @@
|
||||
GLIBC_PROVIDES dnl See top-level configure.in.
|
||||
|
||||
# LinuxThreads fragment for GNU C library configure mechanism.
|
||||
# This is a shell script fragment sourced by the main configure script.
|
||||
|
||||
for other in $add_ons; do
|
||||
test $other = nptl || continue
|
||||
if test $add_ons_automatic = yes; then
|
||||
AC_MSG_RESULT($libc_add_on disabled because $other add-on is also in use)
|
||||
libc_add_on=
|
||||
else
|
||||
AC_MSG_ERROR(cannot use both $libc_add_on and $other add-ons in one build)
|
||||
fi
|
||||
done
|
@ -1,267 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
#ifndef _DESCR_H
|
||||
#define _DESCR_H 1
|
||||
|
||||
#define __need_res_state
|
||||
#include <resolv.h>
|
||||
#include <sched.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <hp-timing.h>
|
||||
#include <tls.h>
|
||||
|
||||
/* Fast thread-specific data internal to libc. */
|
||||
enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
|
||||
_LIBC_TSD_KEY_DL_ERROR,
|
||||
_LIBC_TSD_KEY_RPC_VARS,
|
||||
_LIBC_TSD_KEY_LOCALE,
|
||||
_LIBC_TSD_KEY_CTYPE_B,
|
||||
_LIBC_TSD_KEY_CTYPE_TOLOWER,
|
||||
_LIBC_TSD_KEY_CTYPE_TOUPPER,
|
||||
_LIBC_TSD_KEY_N };
|
||||
|
||||
/* The type of thread descriptors */
|
||||
typedef struct _pthread_descr_struct *pthread_descr;
|
||||
|
||||
|
||||
/* Some more includes. */
|
||||
#include <pt-machine.h>
|
||||
#include <linuxthreads_db/thread_dbP.h>
|
||||
|
||||
|
||||
/* Arguments passed to thread creation routine */
|
||||
struct pthread_start_args {
|
||||
void *(*start_routine)(void *); /* function to run */
|
||||
void *arg; /* its argument */
|
||||
sigset_t mask; /* initial signal mask for thread */
|
||||
int schedpolicy; /* initial scheduling policy (if any) */
|
||||
struct sched_param schedparam; /* initial scheduling parameters (if any) */
|
||||
};
|
||||
|
||||
|
||||
/* Callback interface for removing the thread from waiting on an
|
||||
object if it is cancelled while waiting or about to wait.
|
||||
This hold a pointer to the object, and a pointer to a function
|
||||
which ``extricates'' the thread from its enqueued state.
|
||||
The function takes two arguments: pointer to the wait object,
|
||||
and a pointer to the thread. It returns 1 if an extrication
|
||||
actually occured, and hence the thread must also be signalled.
|
||||
It returns 0 if the thread had already been extricated. */
|
||||
typedef struct _pthread_extricate_struct {
|
||||
void *pu_object;
|
||||
int (*pu_extricate_func)(void *, pthread_descr);
|
||||
} pthread_extricate_if;
|
||||
|
||||
|
||||
/* Atomic counter made possible by compare_and_swap */
|
||||
struct pthread_atomic {
|
||||
long p_count;
|
||||
int p_spinlock;
|
||||
};
|
||||
|
||||
|
||||
/* Context info for read write locks. The pthread_rwlock_info structure
|
||||
is information about a lock that has been read-locked by the thread
|
||||
in whose list this structure appears. The pthread_rwlock_context
|
||||
is embedded in the thread context and contains a pointer to the
|
||||
head of the list of lock info structures, as well as a count of
|
||||
read locks that are untracked, because no info structure could be
|
||||
allocated for them. */
|
||||
struct _pthread_rwlock_t;
|
||||
typedef struct _pthread_rwlock_info {
|
||||
struct _pthread_rwlock_info *pr_next;
|
||||
struct _pthread_rwlock_t *pr_lock;
|
||||
int pr_lock_count;
|
||||
} pthread_readlock_info;
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
union dtv;
|
||||
|
||||
struct _pthread_descr_struct
|
||||
{
|
||||
#if !defined USE_TLS || !TLS_DTV_AT_TP
|
||||
/* This overlaps tcbhead_t (see tls.h), as used for TLS without threads. */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
void *tcb; /* Pointer to the TCB. This is not always
|
||||
the address of this thread descriptor. */
|
||||
union dtv *dtvp;
|
||||
pthread_descr self; /* Pointer to this structure */
|
||||
int multiple_threads;
|
||||
# ifdef NEED_DL_SYSINFO
|
||||
uintptr_t sysinfo;
|
||||
# endif
|
||||
} data;
|
||||
void *__padding[16];
|
||||
} p_header;
|
||||
# define p_multiple_threads p_header.data.multiple_threads
|
||||
#elif TLS_MULTIPLE_THREADS_IN_TCB
|
||||
int p_multiple_threads;
|
||||
#endif
|
||||
|
||||
pthread_descr p_nextlive, p_prevlive;
|
||||
/* Double chaining of active threads */
|
||||
pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */
|
||||
pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */
|
||||
pthread_t p_tid; /* Thread identifier */
|
||||
int p_pid; /* PID of Unix process */
|
||||
int p_priority; /* Thread priority (== 0 if not realtime) */
|
||||
struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
|
||||
int p_signal; /* last signal received */
|
||||
sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
|
||||
sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
|
||||
char p_terminated; /* true if terminated e.g. by pthread_exit */
|
||||
char p_detached; /* true if detached */
|
||||
char p_exited; /* true if the assoc. process terminated */
|
||||
void * p_retval; /* placeholder for return value */
|
||||
int p_retcode; /* placeholder for return code */
|
||||
pthread_descr p_joining; /* thread joining on that thread or NULL */
|
||||
struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
|
||||
char p_cancelstate; /* cancellation state */
|
||||
char p_canceltype; /* cancellation type (deferred/async) */
|
||||
char p_canceled; /* cancellation request pending */
|
||||
char * p_in_sighandler; /* stack address of sighandler, or NULL */
|
||||
char p_sigwaiting; /* true if a sigwait() is in progress */
|
||||
struct pthread_start_args p_start_args; /* arguments for thread creation */
|
||||
void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
|
||||
#if !(USE_TLS && HAVE___THREAD)
|
||||
void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
|
||||
int * p_errnop; /* pointer to used errno variable */
|
||||
int p_errno; /* error returned by last system call */
|
||||
int * p_h_errnop; /* pointer to used h_errno variable */
|
||||
int p_h_errno; /* error returned by last netdb function */
|
||||
struct __res_state *p_resp; /* Pointer to resolver state */
|
||||
#endif
|
||||
struct __res_state p_res; /* per-thread resolver state */
|
||||
int p_userstack; /* nonzero if the user provided the stack */
|
||||
void *p_guardaddr; /* address of guard area or NULL */
|
||||
size_t p_guardsize; /* size of guard area */
|
||||
int p_nr; /* Index of descriptor in __pthread_handles */
|
||||
int p_report_events; /* Nonzero if events must be reported. */
|
||||
td_eventbuf_t p_eventbuf; /* Data for event. */
|
||||
struct pthread_atomic p_resume_count; /* number of times restart() was
|
||||
called on thread */
|
||||
char p_woken_by_cancel; /* cancellation performed wakeup */
|
||||
char p_condvar_avail; /* flag if conditional variable became avail */
|
||||
char p_sem_avail; /* flag if semaphore became available */
|
||||
pthread_extricate_if *p_extricate; /* See above */
|
||||
pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
|
||||
pthread_readlock_info *p_readlock_free; /* Free list of structs */
|
||||
int p_untracked_readlock_count; /* Readlocks not tracked by list */
|
||||
int p_inheritsched; /* copied from the thread attribute */
|
||||
#if HP_TIMING_AVAIL
|
||||
hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */
|
||||
#endif
|
||||
#ifdef USE_TLS
|
||||
char *p_stackaddr; /* Stack address. */
|
||||
#endif
|
||||
size_t p_alloca_cutoff; /* Maximum size which should be allocated
|
||||
using alloca() instead of malloc(). */
|
||||
/* New elements must be added at the end. */
|
||||
} __attribute__ ((aligned(32))); /* We need to align the structure so that
|
||||
doubles are aligned properly. This is 8
|
||||
bytes on MIPS and 16 bytes on MIPS64.
|
||||
32 bytes might give better cache
|
||||
utilization. */
|
||||
|
||||
|
||||
|
||||
/* Limit between the stack of the initial thread (above) and the
|
||||
stacks of other threads (below). Aligned on a STACK_SIZE boundary.
|
||||
Initially 0, meaning that the current thread is (by definition)
|
||||
the initial thread. */
|
||||
|
||||
extern char *__pthread_initial_thread_bos;
|
||||
|
||||
/* Descriptor of the initial thread */
|
||||
|
||||
extern struct _pthread_descr_struct __pthread_initial_thread;
|
||||
|
||||
/* Limits of the thread manager stack. */
|
||||
|
||||
extern char *__pthread_manager_thread_bos;
|
||||
extern char *__pthread_manager_thread_tos;
|
||||
|
||||
/* Descriptor of the manager thread */
|
||||
|
||||
extern struct _pthread_descr_struct __pthread_manager_thread;
|
||||
extern pthread_descr __pthread_manager_threadp attribute_hidden;
|
||||
|
||||
/* Indicate whether at least one thread has a user-defined stack (if 1),
|
||||
or all threads have stacks supplied by LinuxThreads (if 0). */
|
||||
|
||||
extern int __pthread_nonstandard_stacks;
|
||||
|
||||
/* The max size of the thread stack segments. If the default
|
||||
THREAD_SELF implementation is used, this must be a power of two and
|
||||
a multiple of PAGE_SIZE. */
|
||||
#ifndef STACK_SIZE
|
||||
#define STACK_SIZE (2 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
/* Get some notion of the current stack. Need not be exactly the top
|
||||
of the stack, just something somewhere in the current frame. */
|
||||
#ifndef CURRENT_STACK_FRAME
|
||||
#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
|
||||
#endif
|
||||
|
||||
/* Recover thread descriptor for the current thread */
|
||||
|
||||
extern pthread_descr __pthread_find_self (void) __attribute__ ((pure));
|
||||
|
||||
static inline pthread_descr thread_self (void) __attribute__ ((pure));
|
||||
static inline pthread_descr thread_self (void)
|
||||
{
|
||||
#ifdef THREAD_SELF
|
||||
return THREAD_SELF;
|
||||
#else
|
||||
char *sp = CURRENT_STACK_FRAME;
|
||||
if (sp >= __pthread_initial_thread_bos)
|
||||
return &__pthread_initial_thread;
|
||||
else if (sp >= __pthread_manager_thread_bos
|
||||
&& sp < __pthread_manager_thread_tos)
|
||||
return &__pthread_manager_thread;
|
||||
else if (__pthread_nonstandard_stacks)
|
||||
return __pthread_find_self();
|
||||
else
|
||||
#ifdef _STACK_GROWS_DOWN
|
||||
return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
|
||||
#else
|
||||
return (pthread_descr)((unsigned long)sp &~ (STACK_SIZE-1));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* descr.h */
|
@ -1,157 +0,0 @@
|
||||
/* Test of the error checking mutex and incidently also barriers. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static pthread_mutex_t locks[] =
|
||||
{
|
||||
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
|
||||
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
|
||||
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
|
||||
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
|
||||
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
};
|
||||
#define nlocks ((int) (sizeof (locks) / sizeof (locks[0])))
|
||||
|
||||
static pthread_barrier_t barrier;
|
||||
#define SYNC pthread_barrier_wait (&barrier)
|
||||
|
||||
#define NTHREADS nlocks
|
||||
|
||||
#define ROUNDS 20
|
||||
|
||||
|
||||
static void *
|
||||
worker (void *arg)
|
||||
{
|
||||
/* We are locking the and unlocked the locks and check the errors.
|
||||
Since we are using the error-checking variant the implementation
|
||||
should report them. */
|
||||
int nr = (long int) arg;
|
||||
int i;
|
||||
void *result = NULL;
|
||||
int retval;
|
||||
|
||||
for (i = 0; i < ROUNDS; ++i)
|
||||
{
|
||||
/* Skip the rounds which would make other == own. */
|
||||
if (i % nlocks == 0)
|
||||
continue;
|
||||
|
||||
/* Get the "own" mutex. */
|
||||
if (pthread_mutex_trylock (&locks[nr]) != 0)
|
||||
{
|
||||
printf ("thread %d failed getting own mutex\n", nr);
|
||||
result = (void *) 1;
|
||||
}
|
||||
|
||||
/* Try locking "own" mutex again. */
|
||||
retval = pthread_mutex_lock (&locks[nr]);
|
||||
if (retval != EDEADLK)
|
||||
{
|
||||
printf ("thread %d failed getting own mutex\n", nr);
|
||||
result = (void *) 1;
|
||||
}
|
||||
|
||||
/* Try to get a different semaphore. */
|
||||
SYNC;
|
||||
retval = pthread_mutex_trylock (&locks[(nr + i) % nlocks]);
|
||||
if (retval != EBUSY)
|
||||
{
|
||||
printf ("thread %d didn't deadlock on getting %d's lock\n",
|
||||
nr, (nr + i) % nlocks);
|
||||
result = (void *) 1;
|
||||
}
|
||||
|
||||
/* Try unlocking other's lock. */
|
||||
retval = pthread_mutex_unlock (&locks[(nr + i) % nlocks]);
|
||||
if (retval != EPERM)
|
||||
{
|
||||
printf ("thread %d managed releasing mutex %d\n",
|
||||
nr, (nr + i) % nlocks);
|
||||
result = (void *) 1;
|
||||
}
|
||||
|
||||
/* All lock one mutex now. */
|
||||
SYNC;
|
||||
retval = pthread_mutex_lock (&locks[i % nlocks]);
|
||||
if (nr == (i % nlocks))
|
||||
{
|
||||
if (retval != EDEADLK)
|
||||
{
|
||||
printf ("thread %d didn't deadlock on getting %d's lock\n",
|
||||
nr, (nr + i) % nlocks);
|
||||
result = (void *) 1;
|
||||
}
|
||||
if (pthread_mutex_unlock (&locks[i % nlocks]) != 0)
|
||||
{
|
||||
printf ("thread %d failed releasing own mutex\n", nr);
|
||||
result = (void *) 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (retval != 0)
|
||||
{
|
||||
printf ("thread %d failed acquiring mutex %d\n",
|
||||
nr, i % nlocks);
|
||||
result = (void *) 1;
|
||||
}
|
||||
else if (pthread_mutex_unlock (&locks[i % nlocks]) != 0)
|
||||
{
|
||||
printf ("thread %d failed releasing mutex %d\n",
|
||||
nr, i % nlocks);
|
||||
result = (void *) 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock the own lock. */
|
||||
SYNC;
|
||||
if (nr != (i % nlocks) && pthread_mutex_unlock (&locks[nr]) != 0)
|
||||
{
|
||||
printf ("thread %d failed releasing own mutex\n", nr);
|
||||
result = (void *) 1;
|
||||
}
|
||||
|
||||
/* Try unlocking again. */
|
||||
retval = pthread_mutex_unlock (&locks[nr]);
|
||||
if (retval == 0)
|
||||
{
|
||||
printf ("thread %d managed releasing own mutex twice\n", nr);
|
||||
result = (void *) 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
pthread_t threads[NTHREADS];
|
||||
int i;
|
||||
void *res;
|
||||
int result = 0;
|
||||
|
||||
pthread_barrier_init (&barrier, NULL, NTHREADS);
|
||||
|
||||
for (i = 0; i < NTHREADS; ++i)
|
||||
if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0)
|
||||
{
|
||||
printf ("failed to create thread %d: %m\n", i);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (i = 0; i < NTHREADS; ++i)
|
||||
if (pthread_join (threads[i], &res) != 0 || res != NULL)
|
||||
result = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include "../test-skeleton.c"
|
@ -1,47 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Define the location of errno for the remainder of the C library */
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv.h>
|
||||
#include <tls.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
|
||||
#if !USE_TLS || !HAVE___THREAD
|
||||
/* The definition in libc is sufficient if we use TLS. */
|
||||
int *
|
||||
__errno_location (void)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
return THREAD_GETMEM (self, p_errnop);
|
||||
}
|
||||
|
||||
int *
|
||||
__h_errno_location (void)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
return THREAD_GETMEM (self, p_h_errnop);
|
||||
}
|
||||
|
||||
/* Return thread specific resolver state. */
|
||||
struct __res_state *
|
||||
__res_state (void)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
return THREAD_GETMEM (self, p_resp);
|
||||
}
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
/* Event functions used while debugging.
|
||||
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; 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 "internals.h"
|
||||
|
||||
void
|
||||
__linuxthreads_create_event (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__linuxthreads_death_event (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__linuxthreads_reap_event (void)
|
||||
{
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
/* 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 <dlfcn.h>
|
||||
#include "internals.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <shlib-compat.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)
|
||||
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_1)
|
||||
FORWARD (__pthread_attr_init_2_0, (pthread_attr_t *attr), (attr), 0)
|
||||
compat_symbol (libc, __pthread_attr_init_2_0, pthread_attr_init, GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
FORWARD (__pthread_attr_init_2_1, (pthread_attr_t *attr), (attr), 0)
|
||||
versioned_symbol (libc, __pthread_attr_init_2_1, pthread_attr_init, GLIBC_2_1);
|
||||
|
||||
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)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_broadcast, __pthread_cond_broadcast_2_0)
|
||||
compat_symbol (libc, __pthread_cond_broadcast_2_0, pthread_cond_broadcast,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_broadcast, pthread_cond_broadcast,
|
||||
GLIBC_2_3_2);
|
||||
|
||||
FORWARD (__pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_destroy, __pthread_cond_destroy_2_0)
|
||||
compat_symbol (libc, __pthread_cond_destroy_2_0, pthread_cond_destroy,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_destroy, pthread_cond_destroy,
|
||||
GLIBC_2_3_2);
|
||||
|
||||
FORWARD (__pthread_cond_init,
|
||||
(pthread_cond_t *cond, const pthread_condattr_t *cond_attr),
|
||||
(cond, cond_attr), 0)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_init, __pthread_cond_init_2_0)
|
||||
compat_symbol (libc, __pthread_cond_init_2_0, pthread_cond_init, GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_init, pthread_cond_init, GLIBC_2_3_2);
|
||||
|
||||
FORWARD (__pthread_cond_signal, (pthread_cond_t *cond), (cond), 0)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_signal, __pthread_cond_signal_2_0)
|
||||
compat_symbol (libc, __pthread_cond_signal_2_0, pthread_cond_signal,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_signal, pthread_cond_signal,
|
||||
GLIBC_2_3_2);
|
||||
|
||||
FORWARD (__pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex),
|
||||
(cond, mutex), 0)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_wait, __pthread_cond_wait_2_0)
|
||||
compat_symbol (libc, __pthread_cond_wait_2_0, pthread_cond_wait, GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_wait, pthread_cond_wait, GLIBC_2_3_2);
|
||||
|
||||
FORWARD (__pthread_cond_timedwait,
|
||||
(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
const struct timespec *abstime), (cond, mutex, abstime), 0)
|
||||
#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3_2)
|
||||
strong_alias (__pthread_cond_timedwait, __pthread_cond_timedwait_2_0)
|
||||
compat_symbol (libc, __pthread_cond_timedwait_2_0, pthread_cond_timedwait, GLIBC_2_0);
|
||||
#endif
|
||||
versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait, GLIBC_2_3_2);
|
||||
|
||||
|
||||
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)
|
||||
|
||||
FORWARD (pthread_mutex_init,
|
||||
(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr),
|
||||
(mutex, mutexattr), 0)
|
||||
|
||||
FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0)
|
||||
|
||||
FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 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)
|
||||
|
||||
FORWARD2 (_pthread_cleanup_push, void, (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg), (buffer, routine, arg), return)
|
||||
|
||||
FORWARD2 (_pthread_cleanup_pop, void, (struct _pthread_cleanup_buffer * buffer, int execute), (buffer, execute), return)
|
@ -1,550 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
#ifndef _INTERNALS_H
|
||||
#define _INTERNALS_H 1
|
||||
|
||||
/* Internal data structures */
|
||||
|
||||
/* Includes */
|
||||
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stackinfo.h>
|
||||
#include <sigcontextinfo.h>
|
||||
|
||||
#include <tls.h>
|
||||
#include "descr.h"
|
||||
|
||||
#include "semaphore.h"
|
||||
#include <pthread-functions.h>
|
||||
|
||||
#ifndef THREAD_GETMEM
|
||||
# define THREAD_GETMEM(descr, member) descr->member
|
||||
#endif
|
||||
#ifndef THREAD_GETMEM_NC
|
||||
# define THREAD_GETMEM_NC(descr, member) descr->member
|
||||
#endif
|
||||
#ifndef THREAD_SETMEM
|
||||
# define THREAD_SETMEM(descr, member, value) descr->member = (value)
|
||||
#endif
|
||||
#ifndef THREAD_SETMEM_NC
|
||||
# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
|
||||
#endif
|
||||
|
||||
#if !defined NOT_IN_libc && defined FLOATING_STACKS
|
||||
# define LIBC_THREAD_GETMEM(descr, member) THREAD_GETMEM (descr, member)
|
||||
# define LIBC_THREAD_SETMEM(descr, member, value) \
|
||||
THREAD_SETMEM (descr, member, value)
|
||||
#else
|
||||
# define LIBC_THREAD_GETMEM(descr, member) descr->member
|
||||
# define LIBC_THREAD_SETMEM(descr, member, value) descr->member = (value)
|
||||
#endif
|
||||
|
||||
typedef void (*destr_function)(void *);
|
||||
|
||||
struct pthread_key_struct {
|
||||
int in_use; /* already allocated? */
|
||||
destr_function destr; /* destruction routine */
|
||||
};
|
||||
|
||||
|
||||
#define PTHREAD_START_ARGS_INITIALIZER(fct) \
|
||||
{ (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } }
|
||||
|
||||
|
||||
/* The type of thread handles. */
|
||||
|
||||
typedef struct pthread_handle_struct * pthread_handle;
|
||||
|
||||
struct pthread_handle_struct {
|
||||
struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */
|
||||
pthread_descr h_descr; /* Thread descriptor or NULL if invalid */
|
||||
char * h_bottom; /* Lowest address in the stack thread */
|
||||
};
|
||||
|
||||
/* The type of messages sent to the thread manager thread */
|
||||
|
||||
struct pthread_request {
|
||||
pthread_descr req_thread; /* Thread doing the request */
|
||||
enum { /* Request kind */
|
||||
REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
|
||||
REQ_POST, REQ_DEBUG, REQ_KICK, REQ_FOR_EACH_THREAD
|
||||
} req_kind;
|
||||
union { /* Arguments for request */
|
||||
struct { /* For REQ_CREATE: */
|
||||
const pthread_attr_t * attr; /* thread attributes */
|
||||
void * (*fn)(void *); /* start function */
|
||||
void * arg; /* argument to start function */
|
||||
sigset_t mask; /* signal mask */
|
||||
} create;
|
||||
struct { /* For REQ_FREE: */
|
||||
pthread_t thread_id; /* identifier of thread to free */
|
||||
} free;
|
||||
struct { /* For REQ_PROCESS_EXIT: */
|
||||
int code; /* exit status */
|
||||
} exit;
|
||||
void * post; /* For REQ_POST: the semaphore */
|
||||
struct { /* For REQ_FOR_EACH_THREAD: callback */
|
||||
void (*fn)(void *, pthread_descr);
|
||||
void *arg;
|
||||
} for_each;
|
||||
} req_args;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef void (*arch_sighandler_t) (int, SIGCONTEXT);
|
||||
union sighandler
|
||||
{
|
||||
arch_sighandler_t old;
|
||||
void (*rt) (int, struct siginfo *, struct ucontext *);
|
||||
};
|
||||
extern union sighandler __sighandler[NSIG];
|
||||
|
||||
|
||||
/* Signals used for suspend/restart and for cancellation notification. */
|
||||
|
||||
extern int __pthread_sig_restart;
|
||||
extern int __pthread_sig_cancel;
|
||||
|
||||
/* Signal used for interfacing with gdb */
|
||||
|
||||
extern int __pthread_sig_debug;
|
||||
|
||||
/* Global array of thread handles, used for validating a thread id
|
||||
and retrieving the corresponding thread descriptor. Also used for
|
||||
mapping the available stack segments. */
|
||||
|
||||
extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX];
|
||||
|
||||
/* Descriptor of the main thread */
|
||||
|
||||
extern pthread_descr __pthread_main_thread;
|
||||
|
||||
/* File descriptor for sending requests to the thread manager.
|
||||
Initially -1, meaning that __pthread_initialize_manager must be called. */
|
||||
|
||||
extern int __pthread_manager_request;
|
||||
|
||||
/* Other end of the pipe for sending requests to the thread manager. */
|
||||
|
||||
extern int __pthread_manager_reader;
|
||||
|
||||
#ifdef FLOATING_STACKS
|
||||
/* Maximum stack size. */
|
||||
extern size_t __pthread_max_stacksize;
|
||||
#endif
|
||||
|
||||
/* Pending request for a process-wide exit */
|
||||
|
||||
extern int __pthread_exit_requested, __pthread_exit_code;
|
||||
|
||||
/* Set to 1 by gdb if we're debugging */
|
||||
|
||||
extern volatile int __pthread_threads_debug;
|
||||
|
||||
/* Globally enabled events. */
|
||||
extern volatile td_thr_events_t __pthread_threads_events;
|
||||
|
||||
/* Pointer to descriptor of thread with last event. */
|
||||
extern volatile pthread_descr __pthread_last_event;
|
||||
|
||||
/* Flag which tells whether we are executing on SMP kernel. */
|
||||
extern int __pthread_smp_kernel;
|
||||
|
||||
/* Return the handle corresponding to a thread id */
|
||||
|
||||
static inline pthread_handle thread_handle(pthread_t id)
|
||||
{
|
||||
return &__pthread_handles[id % PTHREAD_THREADS_MAX];
|
||||
}
|
||||
|
||||
/* Validate a thread handle. Must have acquired h->h_spinlock before. */
|
||||
|
||||
static inline int invalid_handle(pthread_handle h, pthread_t id)
|
||||
{
|
||||
return h->h_descr == NULL || h->h_descr->p_tid != id || h->h_descr->p_terminated;
|
||||
}
|
||||
|
||||
static inline int nonexisting_handle(pthread_handle h, pthread_t id)
|
||||
{
|
||||
return h->h_descr == NULL || h->h_descr->p_tid != id;
|
||||
}
|
||||
|
||||
/* Fill in defaults left unspecified by pt-machine.h. */
|
||||
|
||||
/* We round up a value with page size. */
|
||||
#ifndef page_roundup
|
||||
#define page_roundup(v,p) ((((size_t) (v)) + (p) - 1) & ~((p) - 1))
|
||||
#endif
|
||||
|
||||
/* The page size we can get from the system. This should likely not be
|
||||
changed by the machine file but, you never know. */
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE (sysconf (_SC_PAGE_SIZE))
|
||||
#endif
|
||||
|
||||
/* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */
|
||||
#ifndef INITIAL_STACK_SIZE
|
||||
#define INITIAL_STACK_SIZE (4 * PAGE_SIZE)
|
||||
#endif
|
||||
|
||||
/* Size of the thread manager stack. The "- 32" avoids wasting space
|
||||
with some malloc() implementations. */
|
||||
#ifndef THREAD_MANAGER_STACK_SIZE
|
||||
#define THREAD_MANAGER_STACK_SIZE (2 * PAGE_SIZE - 32)
|
||||
#endif
|
||||
|
||||
/* The base of the "array" of thread stacks. The array will grow down from
|
||||
here. Defaults to the calculated bottom of the initial application
|
||||
stack. */
|
||||
#ifndef THREAD_STACK_START_ADDRESS
|
||||
#define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos
|
||||
#endif
|
||||
|
||||
/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the
|
||||
architecture doesn't need a memory barrier instruction (e.g. Intel
|
||||
x86). Still we need the compiler to respect the barrier and emit
|
||||
all outstanding operations which modify memory. Some architectures
|
||||
distinguish between full, read and write barriers. */
|
||||
|
||||
#ifndef MEMORY_BARRIER
|
||||
#define MEMORY_BARRIER() asm ("" : : : "memory")
|
||||
#endif
|
||||
#ifndef READ_MEMORY_BARRIER
|
||||
#define READ_MEMORY_BARRIER() MEMORY_BARRIER()
|
||||
#endif
|
||||
#ifndef WRITE_MEMORY_BARRIER
|
||||
#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER()
|
||||
#endif
|
||||
|
||||
/* Max number of times we must spin on a spinlock calling sched_yield().
|
||||
After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
|
||||
|
||||
#ifndef MAX_SPIN_COUNT
|
||||
#define MAX_SPIN_COUNT 50
|
||||
#endif
|
||||
|
||||
/* Max number of times the spinlock in the adaptive mutex implementation
|
||||
spins actively on SMP systems. */
|
||||
|
||||
#ifndef MAX_ADAPTIVE_SPIN_COUNT
|
||||
#define MAX_ADAPTIVE_SPIN_COUNT 100
|
||||
#endif
|
||||
|
||||
/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
|
||||
after MAX_SPIN_COUNT iterations of sched_yield().
|
||||
With the 2.0 and 2.1 kernels, this MUST BE > 2ms.
|
||||
(Otherwise the kernel does busy-waiting for realtime threads,
|
||||
giving other threads no chance to run.) */
|
||||
|
||||
#ifndef SPIN_SLEEP_DURATION
|
||||
#define SPIN_SLEEP_DURATION 2000001
|
||||
#endif
|
||||
|
||||
/* Defined and used in libc.so. */
|
||||
extern int __libc_multiple_threads attribute_hidden;
|
||||
extern int __librt_multiple_threads;
|
||||
|
||||
/* Debugging */
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <assert.h>
|
||||
#define ASSERT assert
|
||||
#define MSG __pthread_message
|
||||
#else
|
||||
#define ASSERT(x)
|
||||
#define MSG(msg,arg...)
|
||||
#endif
|
||||
|
||||
/* Internal global functions */
|
||||
|
||||
extern void __pthread_do_exit (void *retval, char *currentframe)
|
||||
__attribute__ ((__noreturn__));
|
||||
extern void __pthread_destroy_specifics (void);
|
||||
extern void __pthread_perform_cleanup (char *currentframe);
|
||||
extern void __pthread_init_max_stacksize (void);
|
||||
extern int __pthread_initialize_manager (void);
|
||||
extern void __pthread_message (const char * fmt, ...);
|
||||
extern int __pthread_manager (void *reqfd);
|
||||
extern int __pthread_manager_event (void *reqfd);
|
||||
extern void __pthread_manager_sighandler (int sig);
|
||||
extern void __pthread_reset_main_thread (void);
|
||||
extern void __pthread_once_fork_prepare (void);
|
||||
extern void __pthread_once_fork_parent (void);
|
||||
extern void __pthread_once_fork_child (void);
|
||||
extern void __flockfilelist (void);
|
||||
extern void __funlockfilelist (void);
|
||||
extern void __fresetlockfiles (void);
|
||||
extern void __pthread_manager_adjust_prio (int thread_prio);
|
||||
extern void __pthread_initialize_minimal (void);
|
||||
|
||||
extern int __pthread_attr_setguardsize (pthread_attr_t *__attr,
|
||||
size_t __guardsize);
|
||||
extern int __pthread_attr_getguardsize (const pthread_attr_t *__attr,
|
||||
size_t *__guardsize);
|
||||
extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr,
|
||||
void *__stackaddr);
|
||||
extern int __pthread_attr_getstackaddr (const pthread_attr_t *__attr,
|
||||
void **__stackaddr);
|
||||
extern int __pthread_attr_setstacksize (pthread_attr_t *__attr,
|
||||
size_t __stacksize);
|
||||
extern int __pthread_attr_getstacksize (const pthread_attr_t *__attr,
|
||||
size_t *__stacksize);
|
||||
extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
|
||||
size_t __stacksize);
|
||||
extern int __pthread_attr_getstack (const pthread_attr_t *__attr, void **__stackaddr,
|
||||
size_t *__stacksize);
|
||||
extern int __pthread_attr_destroy (pthread_attr_t *attr);
|
||||
extern int __pthread_attr_setdetachstate (pthread_attr_t *attr,
|
||||
int detachstate);
|
||||
extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr,
|
||||
int *detachstate);
|
||||
extern int __pthread_attr_setschedparam (pthread_attr_t *attr,
|
||||
const struct sched_param *param);
|
||||
extern int __pthread_attr_getschedparam (const pthread_attr_t *attr,
|
||||
struct sched_param *param);
|
||||
extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy);
|
||||
extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr,
|
||||
int *policy);
|
||||
extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit);
|
||||
extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr,
|
||||
int *inherit);
|
||||
extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope);
|
||||
extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope);
|
||||
|
||||
extern int __pthread_getconcurrency (void);
|
||||
extern int __pthread_setconcurrency (int __level);
|
||||
extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex,
|
||||
const struct timespec *__abstime);
|
||||
extern int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *__attr,
|
||||
int *__pshared);
|
||||
extern int __pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,
|
||||
int __pshared);
|
||||
extern int __pthread_mutexattr_gettype (const pthread_mutexattr_t *__attr,
|
||||
int *__kind);
|
||||
extern void __pthread_kill_other_threads_np (void);
|
||||
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_lock (pthread_mutex_t *__mutex);
|
||||
extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
|
||||
extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
|
||||
#if defined NOT_IN_libc && defined IS_IN_libpthread
|
||||
hidden_proto (__pthread_mutex_init)
|
||||
hidden_proto (__pthread_mutex_destroy)
|
||||
hidden_proto (__pthread_mutex_lock)
|
||||
hidden_proto (__pthread_mutex_trylock)
|
||||
hidden_proto (__pthread_mutex_unlock)
|
||||
#endif
|
||||
extern int __pthread_cond_init (pthread_cond_t *cond,
|
||||
const pthread_condattr_t *cond_attr);
|
||||
extern int __pthread_cond_destroy (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_cond_signal (pthread_cond_t *cond);
|
||||
extern int __pthread_cond_broadcast (pthread_cond_t *cond);
|
||||
extern int __pthread_condattr_init (pthread_condattr_t *attr);
|
||||
extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
|
||||
extern pthread_t __pthread_self (void);
|
||||
extern pthread_descr __pthread_thread_self (void);
|
||||
extern pthread_descr __pthread_self_stack (void) attribute_hidden;
|
||||
extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
|
||||
extern void __pthread_exit (void *retval);
|
||||
extern int __pthread_getschedparam (pthread_t thread, int *policy,
|
||||
struct sched_param *param);
|
||||
extern int __pthread_setschedparam (pthread_t thread, int policy,
|
||||
const struct sched_param *param);
|
||||
extern int __pthread_setcancelstate (int state, int * oldstate);
|
||||
extern int __pthread_setcanceltype (int type, int * oldtype);
|
||||
|
||||
extern void __pthread_restart_old(pthread_descr th);
|
||||
extern void __pthread_suspend_old(pthread_descr self);
|
||||
extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs);
|
||||
|
||||
extern void __pthread_restart_new(pthread_descr th);
|
||||
extern void __pthread_suspend_new(pthread_descr self);
|
||||
extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs);
|
||||
|
||||
extern void __pthread_wait_for_restart_signal(pthread_descr self);
|
||||
|
||||
extern void __pthread_sigsuspend (const sigset_t *mask) attribute_hidden;
|
||||
|
||||
extern int __pthread_yield (void);
|
||||
|
||||
extern int __pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
|
||||
__const struct timespec *__restrict
|
||||
__abstime);
|
||||
extern int __pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
|
||||
__const struct timespec *__restrict
|
||||
__abstime);
|
||||
extern int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);
|
||||
|
||||
extern int __pthread_barrierattr_getpshared (__const pthread_barrierattr_t *
|
||||
__restrict __attr,
|
||||
int *__restrict __pshared);
|
||||
|
||||
extern int __pthread_spin_lock (pthread_spinlock_t *__lock);
|
||||
extern int __pthread_spin_trylock (pthread_spinlock_t *__lock);
|
||||
extern int __pthread_spin_unlock (pthread_spinlock_t *__lock);
|
||||
extern int __pthread_spin_init (pthread_spinlock_t *__lock, int __pshared);
|
||||
extern int __pthread_spin_destroy (pthread_spinlock_t *__lock);
|
||||
|
||||
/* Global pointers to old or new suspend functions */
|
||||
|
||||
extern void (*__pthread_restart)(pthread_descr);
|
||||
extern void (*__pthread_suspend)(pthread_descr);
|
||||
extern int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *);
|
||||
|
||||
/* Prototypes for the function without cancelation support when the
|
||||
normal version has it. */
|
||||
extern int __libc_close (int fd);
|
||||
extern int __libc_nanosleep (const struct timespec *requested_time,
|
||||
struct timespec *remaining);
|
||||
/* Prototypes for some of the new semaphore functions. */
|
||||
extern int __new_sem_post (sem_t * sem);
|
||||
extern int __new_sem_init (sem_t *__sem, int __pshared, unsigned int __value);
|
||||
extern int __new_sem_wait (sem_t *__sem);
|
||||
extern int __new_sem_trywait (sem_t *__sem);
|
||||
extern int __new_sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval);
|
||||
extern int __new_sem_destroy (sem_t *__sem);
|
||||
|
||||
/* Prototypes for compatibility functions. */
|
||||
extern int __pthread_attr_init_2_1 (pthread_attr_t *__attr);
|
||||
extern int __pthread_attr_init_2_0 (pthread_attr_t *__attr);
|
||||
extern int __pthread_create_2_1 (pthread_t *__restrict __threadp,
|
||||
const pthread_attr_t *__attr,
|
||||
void *(*__start_routine) (void *),
|
||||
void *__restrict __arg);
|
||||
extern int __pthread_create_2_0 (pthread_t *__restrict thread,
|
||||
const pthread_attr_t *__attr,
|
||||
void *(*__start_routine) (void *),
|
||||
void *__restrict arg);
|
||||
|
||||
/* The functions called the signal events. */
|
||||
extern void __linuxthreads_create_event (void);
|
||||
extern void __linuxthreads_death_event (void);
|
||||
extern void __linuxthreads_reap_event (void);
|
||||
|
||||
/* This function is called to initialize the pthread library. */
|
||||
extern void __pthread_initialize (void);
|
||||
|
||||
/* TSD. */
|
||||
extern int __pthread_internal_tsd_set (int key, const void * pointer);
|
||||
extern void * __pthread_internal_tsd_get (int key);
|
||||
extern void ** __attribute__ ((__const__))
|
||||
__pthread_internal_tsd_address (int key);
|
||||
|
||||
/* Sighandler wrappers. */
|
||||
extern void __pthread_sighandler(int signo, SIGCONTEXT ctx);
|
||||
extern void __pthread_sighandler_rt(int signo, struct siginfo *si,
|
||||
struct ucontext *uc);
|
||||
extern void __pthread_null_sighandler(int sig);
|
||||
extern int __pthread_sigaction (int sig, const struct sigaction *act,
|
||||
struct sigaction *oact);
|
||||
extern int __pthread_sigwait (const sigset_t *set, int *sig);
|
||||
extern int __pthread_raise (int sig);
|
||||
|
||||
/* Cancellation. */
|
||||
extern int __pthread_enable_asynccancel (void) attribute_hidden;
|
||||
extern void __pthread_disable_asynccancel (int oldtype)
|
||||
internal_function attribute_hidden;
|
||||
|
||||
/* 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 libc.so and are exported. */
|
||||
extern int __librt_enable_asynccancel (void);
|
||||
extern void __librt_disable_asynccancel (int oldtype) internal_function;
|
||||
|
||||
extern void __pthread_cleanup_upto (__jmp_buf target,
|
||||
char *targetframe) attribute_hidden;
|
||||
extern pid_t __pthread_fork (struct fork_block *b) attribute_hidden;
|
||||
|
||||
#if !defined NOT_IN_libc
|
||||
# define LIBC_CANCEL_ASYNC() \
|
||||
__libc_enable_asynccancel ()
|
||||
# define LIBC_CANCEL_RESET(oldtype) \
|
||||
__libc_disable_asynccancel (oldtype)
|
||||
# define LIBC_CANCEL_HANDLED() \
|
||||
__asm (".globl " __SYMBOL_PREFIX "__libc_enable_asynccancel"); \
|
||||
__asm (".globl " __SYMBOL_PREFIX "__libc_disable_asynccancel")
|
||||
#elif defined IS_IN_libpthread
|
||||
# define LIBC_CANCEL_ASYNC() \
|
||||
__pthread_enable_asynccancel ()
|
||||
# define LIBC_CANCEL_RESET(oldtype) \
|
||||
__pthread_disable_asynccancel (oldtype)
|
||||
# define LIBC_CANCEL_HANDLED() \
|
||||
__asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \
|
||||
__asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel")
|
||||
#elif defined IS_IN_librt
|
||||
# define LIBC_CANCEL_ASYNC() \
|
||||
__librt_enable_asynccancel ()
|
||||
# define LIBC_CANCEL_RESET(oldtype) \
|
||||
__librt_disable_asynccancel (oldtype)
|
||||
# define LIBC_CANCEL_HANDLED() \
|
||||
__asm (".globl " __SYMBOL_PREFIX "__librt_enable_asynccancel"); \
|
||||
__asm (".globl " __SYMBOL_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
|
||||
|
||||
extern int * __libc_pthread_init (const struct pthread_functions *functions);
|
||||
|
||||
#if !defined NOT_IN_libc && !defined FLOATING_STACKS
|
||||
# ifdef SHARED
|
||||
# define thread_self() \
|
||||
(*__libc_pthread_functions.ptr_pthread_thread_self) ()
|
||||
# else
|
||||
weak_extern (__pthread_thread_self)
|
||||
# define thread_self() __pthread_thread_self ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_TLS
|
||||
# define __manager_thread (&__pthread_manager_thread)
|
||||
#else
|
||||
# define __manager_thread __pthread_manager_threadp
|
||||
#endif
|
||||
|
||||
extern inline __attribute__((always_inline)) pthread_descr
|
||||
check_thread_self (void)
|
||||
{
|
||||
pthread_descr self = thread_self ();
|
||||
#if defined THREAD_SELF && defined INIT_THREAD_SELF
|
||||
if (self == __manager_thread)
|
||||
{
|
||||
/* A new thread might get a cancel signal before it is fully
|
||||
initialized, so that the thread register might still point to the
|
||||
manager thread. Double check that this is really the manager
|
||||
thread. */
|
||||
self = __pthread_self_stack();
|
||||
if (self != __manager_thread)
|
||||
/* Oops, thread_self() isn't working yet.. */
|
||||
INIT_THREAD_SELF(self, self->p_nr);
|
||||
}
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
#endif /* internals.h */
|
@ -1,220 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Thread termination and joining */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "restart.h"
|
||||
#include <not-cancel.h>
|
||||
|
||||
void __pthread_exit(void * retval)
|
||||
{
|
||||
__pthread_do_exit (retval, CURRENT_STACK_FRAME);
|
||||
}
|
||||
strong_alias (__pthread_exit, pthread_exit);
|
||||
|
||||
void __pthread_do_exit(void *retval, char *currentframe)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
pthread_descr joining;
|
||||
struct pthread_request request;
|
||||
|
||||
/* Reset the cancellation flag to avoid looping if the cleanup handlers
|
||||
contain cancellation points */
|
||||
THREAD_SETMEM(self, p_canceled, 0);
|
||||
/* Call cleanup functions and destroy the thread-specific data */
|
||||
__pthread_perform_cleanup(currentframe);
|
||||
__pthread_destroy_specifics();
|
||||
/* Store return value */
|
||||
__pthread_lock(THREAD_GETMEM(self, p_lock), self);
|
||||
THREAD_SETMEM(self, p_retval, retval);
|
||||
/* See whether we have to signal the death. */
|
||||
if (THREAD_GETMEM(self, p_report_events))
|
||||
{
|
||||
/* See whether TD_DEATH is in any of the mask. */
|
||||
int idx = __td_eventword (TD_DEATH);
|
||||
uint32_t mask = __td_eventmask (TD_DEATH);
|
||||
|
||||
if ((mask & (__pthread_threads_events.event_bits[idx]
|
||||
| THREAD_GETMEM_NC(self,
|
||||
p_eventbuf.eventmask.event_bits[idx])))
|
||||
!= 0)
|
||||
{
|
||||
/* Yep, we have to signal the death. */
|
||||
THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH);
|
||||
THREAD_SETMEM(self, p_eventbuf.eventdata, self);
|
||||
__pthread_last_event = self;
|
||||
|
||||
/* Now call the function to signal the event. */
|
||||
__linuxthreads_death_event();
|
||||
}
|
||||
}
|
||||
/* Say that we've terminated */
|
||||
THREAD_SETMEM(self, p_terminated, 1);
|
||||
/* See if someone is joining on us */
|
||||
joining = THREAD_GETMEM(self, p_joining);
|
||||
__pthread_unlock(THREAD_GETMEM(self, p_lock));
|
||||
/* Restart joining thread if any */
|
||||
if (joining != NULL) restart(joining);
|
||||
/* If this is the initial thread, block until all threads have terminated.
|
||||
If another thread calls exit, we'll be terminated from our signal
|
||||
handler. */
|
||||
if (self == __pthread_main_thread && __pthread_manager_request >= 0) {
|
||||
request.req_thread = self;
|
||||
request.req_kind = REQ_MAIN_THREAD_EXIT;
|
||||
TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
|
||||
(char *)&request, sizeof(request)));
|
||||
suspend(self);
|
||||
/* Main thread flushes stdio streams and runs atexit functions.
|
||||
It also calls a handler within LinuxThreads which sends a process exit
|
||||
request to the thread manager. */
|
||||
exit(0);
|
||||
}
|
||||
/* Threads other than the main one terminate without flushing stdio streams
|
||||
or running atexit functions. */
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* Function called by pthread_cancel to remove the thread from
|
||||
waiting on a condition variable queue. */
|
||||
|
||||
static int join_extricate_func(void *obj, pthread_descr th)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
pthread_handle handle = obj;
|
||||
pthread_descr jo;
|
||||
int did_remove = 0;
|
||||
|
||||
__pthread_lock(&handle->h_lock, self);
|
||||
jo = handle->h_descr;
|
||||
did_remove = jo->p_joining != NULL;
|
||||
jo->p_joining = NULL;
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
|
||||
return did_remove;
|
||||
}
|
||||
|
||||
int pthread_join(pthread_t thread_id, void ** thread_return)
|
||||
{
|
||||
volatile pthread_descr self = thread_self();
|
||||
struct pthread_request request;
|
||||
pthread_handle handle = thread_handle(thread_id);
|
||||
pthread_descr th;
|
||||
pthread_extricate_if extr;
|
||||
int already_canceled = 0;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = handle;
|
||||
extr.pu_extricate_func = join_extricate_func;
|
||||
|
||||
__pthread_lock(&handle->h_lock, self);
|
||||
if (nonexisting_handle(handle, thread_id)) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return ESRCH;
|
||||
}
|
||||
th = handle->h_descr;
|
||||
if (th == self) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return EDEADLK;
|
||||
}
|
||||
/* If detached or already joined, error */
|
||||
if (th->p_detached || th->p_joining != NULL) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
/* If not terminated yet, suspend ourselves. */
|
||||
if (! th->p_terminated) {
|
||||
/* Register extrication interface */
|
||||
__pthread_set_own_extricate_if(self, &extr);
|
||||
if (!(THREAD_GETMEM(self, p_canceled)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
|
||||
th->p_joining = self;
|
||||
else
|
||||
already_canceled = 1;
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
|
||||
if (already_canceled) {
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
|
||||
suspend(self);
|
||||
/* Deregister extrication interface */
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
|
||||
/* This is a cancellation point */
|
||||
if (THREAD_GETMEM(self, p_woken_by_cancel)
|
||||
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
|
||||
THREAD_SETMEM(self, p_woken_by_cancel, 0);
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
__pthread_lock(&handle->h_lock, self);
|
||||
}
|
||||
/* Get return value */
|
||||
if (thread_return != NULL) *thread_return = th->p_retval;
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
/* Send notification to thread manager */
|
||||
if (__pthread_manager_request >= 0) {
|
||||
request.req_thread = self;
|
||||
request.req_kind = REQ_FREE;
|
||||
request.req_args.free.thread_id = thread_id;
|
||||
TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
|
||||
(char *) &request, sizeof(request)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_detach(pthread_t thread_id)
|
||||
{
|
||||
int terminated;
|
||||
struct pthread_request request;
|
||||
pthread_handle handle = thread_handle(thread_id);
|
||||
pthread_descr th;
|
||||
|
||||
__pthread_lock(&handle->h_lock, NULL);
|
||||
if (nonexisting_handle(handle, thread_id)) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return ESRCH;
|
||||
}
|
||||
th = handle->h_descr;
|
||||
/* If already detached, error */
|
||||
if (th->p_detached) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
/* If already joining, don't do anything. */
|
||||
if (th->p_joining != NULL) {
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
return 0;
|
||||
}
|
||||
/* Mark as detached */
|
||||
th->p_detached = 1;
|
||||
terminated = th->p_terminated;
|
||||
__pthread_unlock(&handle->h_lock);
|
||||
/* If already terminated, notify thread manager to reclaim resources */
|
||||
if (terminated && __pthread_manager_request >= 0) {
|
||||
request.req_thread = thread_self();
|
||||
request.req_kind = REQ_FREE;
|
||||
request.req_args.free.thread_id = thread_id;
|
||||
TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
|
||||
(char *) &request, sizeof(request)));
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/* Test case by Permaine Cheung <pcheung@cygnus.com>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void *
|
||||
sub1 (void *arg)
|
||||
{
|
||||
/* Nothing. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int istatus;
|
||||
int policy;
|
||||
int cnt;
|
||||
pthread_t thread1;
|
||||
struct sched_param spresult1, sp1;
|
||||
|
||||
for (cnt = 0; cnt < 100; ++cnt)
|
||||
{
|
||||
printf ("Round %d\n", cnt);
|
||||
|
||||
pthread_create (&thread1, NULL, &sub1, NULL);
|
||||
pthread_join (thread1, NULL);
|
||||
|
||||
istatus = pthread_getschedparam (thread1, &policy, &spresult1);
|
||||
if (istatus != ESRCH)
|
||||
{
|
||||
printf ("pthread_getschedparam returns: %d\n", istatus);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sp1.sched_priority = 0;
|
||||
istatus = pthread_setschedparam (thread1, SCHED_OTHER, &sp1);
|
||||
if (istatus != ESRCH)
|
||||
{
|
||||
printf ("pthread_setschedparam returns: %d\n", istatus);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/* Copyright (C) 2002 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 <rpc/rpc.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "restart.h"
|
||||
#include <bits/libc-lock.h>
|
||||
|
||||
#if !defined NOT_IN_libc
|
||||
|
||||
# ifndef SHARED
|
||||
weak_extern (__pthread_do_exit)
|
||||
# endif
|
||||
|
||||
int __libc_multiple_threads attribute_hidden __attribute__((nocommon));
|
||||
strong_alias (__libc_multiple_threads, __librt_multiple_threads);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
int oldtype = LIBC_THREAD_GETMEM(self, p_canceltype);
|
||||
LIBC_THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
|
||||
if (__builtin_expect (LIBC_THREAD_GETMEM(self, p_canceled), 0) &&
|
||||
LIBC_THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
|
||||
__libc_maybe_call2 (pthread_do_exit,
|
||||
(PTHREAD_CANCELED, CURRENT_STACK_FRAME), 0);
|
||||
return oldtype;
|
||||
}
|
||||
strong_alias (__libc_enable_asynccancel, __librt_enable_asynccancel)
|
||||
|
||||
void
|
||||
internal_function attribute_hidden
|
||||
__libc_disable_asynccancel (int oldtype)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
LIBC_THREAD_SETMEM(self, p_canceltype, oldtype);
|
||||
}
|
||||
strong_alias (__libc_disable_asynccancel, __librt_disable_asynccancel)
|
||||
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/* Special definitions for libc's own exposed thread-specific variables.
|
||||
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 <tls.h>
|
||||
|
||||
#if USE___THREAD
|
||||
# include <errno.h>
|
||||
# include <netdb.h>
|
||||
# include <resolv.h>
|
||||
|
||||
/* These functions have identical definitions in libc. But the versioned
|
||||
dependencies in executables bind them to libpthread.so definitions,
|
||||
so we must have some here. */
|
||||
|
||||
int *
|
||||
__errno_location (void)
|
||||
{
|
||||
return &errno;
|
||||
}
|
||||
|
||||
int *
|
||||
__h_errno_location (void)
|
||||
{
|
||||
return &h_errno;
|
||||
}
|
||||
|
||||
struct __res_state *
|
||||
__res_state (void)
|
||||
{
|
||||
return __resp;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,41 +0,0 @@
|
||||
/* Special hack used to build link-time libc.so object for linking libpthread.
|
||||
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; 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 <tls.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#if ! USE___THREAD
|
||||
|
||||
/* Special hack used to build link-time libc.so object for linking libpthread.
|
||||
See Makefile comments near libc_pic_lite.os rule for what this is for. */
|
||||
|
||||
# undef _res
|
||||
|
||||
int _errno;
|
||||
int _h_errno;
|
||||
struct __res_state _res;
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
__res_maybe_init (res_state resp, int preinit)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
libc_hidden_def (__res_maybe_init)
|
@ -1,46 +0,0 @@
|
||||
/* Copyright (C) 2002 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 <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tls.h>
|
||||
#include "internals.h"
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
int *
|
||||
__libc_pthread_init (functions)
|
||||
const struct pthread_functions *functions;
|
||||
{
|
||||
#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
|
||||
|
||||
#if !(USE_TLS && HAVE___THREAD)
|
||||
/* Initialize thread-locale current locale to point to the global one.
|
||||
With __thread support, the variable's initializer takes care of this. */
|
||||
__uselocale (LC_GLOBAL_LOCALE);
|
||||
#endif
|
||||
|
||||
return &__libc_multiple_threads;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,86 +0,0 @@
|
||||
/* lockfile - Handle locking and unlocking of stream.
|
||||
Copyright (C) 1996, 1998, 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; 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 <bits/libc-lock.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include "internals.h"
|
||||
#include "../libio/libioP.h"
|
||||
|
||||
void
|
||||
__flockfile (FILE *stream)
|
||||
{
|
||||
__pthread_mutex_lock (stream->_lock);
|
||||
}
|
||||
#undef _IO_flockfile
|
||||
strong_alias (__flockfile, _IO_flockfile)
|
||||
weak_alias (__flockfile, flockfile);
|
||||
|
||||
|
||||
void
|
||||
__funlockfile (FILE *stream)
|
||||
{
|
||||
__pthread_mutex_unlock (stream->_lock);
|
||||
}
|
||||
#undef _IO_funlockfile
|
||||
strong_alias (__funlockfile, _IO_funlockfile)
|
||||
weak_alias (__funlockfile, funlockfile);
|
||||
|
||||
|
||||
int
|
||||
__ftrylockfile (FILE *stream)
|
||||
{
|
||||
return __pthread_mutex_trylock (stream->_lock);
|
||||
}
|
||||
strong_alias (__ftrylockfile, _IO_ftrylockfile)
|
||||
weak_alias (__ftrylockfile, ftrylockfile);
|
||||
|
||||
void
|
||||
__flockfilelist(void)
|
||||
{
|
||||
_IO_list_lock();
|
||||
}
|
||||
|
||||
void
|
||||
__funlockfilelist(void)
|
||||
{
|
||||
_IO_list_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
__fresetlockfiles (void)
|
||||
{
|
||||
_IO_ITER i;
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
__pthread_mutexattr_init (&attr);
|
||||
__pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
|
||||
for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
|
||||
{
|
||||
_IO_lock_t *_lock = _IO_iter_file(i)->_lock;
|
||||
if (_lock)
|
||||
__pthread_mutex_init (_lock, &attr);
|
||||
}
|
||||
|
||||
__pthread_mutexattr_destroy (&attr);
|
||||
|
||||
_IO_list_resetlock();
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
SOURCES= pthread_cleanup_push.man \
|
||||
pthread_kill_other_threads_np.man pthread_mutexattr_setkind_np.man
|
||||
|
||||
MANPAGES=$(SOURCES:.man=.3thr)
|
||||
|
||||
PREPRO=perl troffprepro
|
||||
|
||||
MANDIR=/usr/man/man3
|
||||
|
||||
all: $(MANPAGES)
|
||||
|
||||
.SUFFIXES: .man .3thr
|
||||
|
||||
.man.3thr:
|
||||
$(PREPRO) $*.man $*.3thr
|
||||
|
||||
$(MANPAGES): troffprepro
|
||||
|
||||
clean:
|
||||
rm -f *.3thr
|
||||
rm -f *~
|
||||
|
||||
install:
|
||||
install *.3thr $(MANDIR)
|
||||
@echo "*** Remember to run /usr/sbin/makewhatis `dirname $(MANDIR)` at some point"
|
@ -1,53 +0,0 @@
|
||||
.TH PTHREAD_ATFORK 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_atfork \- register handlers to be called at fork(2) time
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
!pthread_atfork! registers handler functions to be called just before
|
||||
and just after a new process is created with !fork!(2). The |prepare|
|
||||
handler will be called from the parent process, just before the new
|
||||
process is created. The |parent| handler will be called from the parent
|
||||
process, just before !fork!(2) returns. The |child| handler will be
|
||||
called from the child process, just before !fork!(2) returns.
|
||||
|
||||
One or several of the three handlers |prepare|, |parent| and |child|
|
||||
can be given as !NULL!, meaning that no handler needs to be called at
|
||||
the corresponding point.
|
||||
|
||||
!pthread_atfork! can be called several times to install several sets
|
||||
of handlers. At !fork!(2) time, the |prepare| handlers are called in
|
||||
LIFO order (last added with !pthread_atfork!, first called before !fork!),
|
||||
while the |parent| and |child| handlers are called in FIFO order
|
||||
(first added, first called).
|
||||
|
||||
To understand the purpose of !pthread_atfork!, recall that !fork!(2)
|
||||
duplicates the whole memory space, including mutexes in their current
|
||||
locking state, but only the calling thread: other threads are not
|
||||
running in the child process. The mutexes are not usable after the
|
||||
!fork! and must be initialized with |pthread_mutex_init| in the child
|
||||
process. This is a limitation of the current implementation and might
|
||||
or might not be present in future versions.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
!pthread_atfork! returns 0 on success and a non-zero error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
.TP
|
||||
!ENOMEM!
|
||||
insufficient memory available to register the handlers.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!fork!(2),
|
||||
!pthread_mutex_lock!(3),
|
||||
!pthread_mutex_unlock!(3).
|
@ -1,221 +0,0 @@
|
||||
.TH PTHREAD_ATTR_INIT 3 LinuxThreads
|
||||
|
||||
.XREF pthread_attr_destroy
|
||||
.XREF pthread_attr_setdetachstate
|
||||
.XREF pthread_attr_getdetachstate
|
||||
.XREF pthread_attr_setschedparam
|
||||
.XREF pthread_attr_getschedparam
|
||||
.XREF pthread_attr_setschedpolicy
|
||||
.XREF pthread_attr_getschedpolicy
|
||||
.XREF pthread_attr_setinheritsched
|
||||
.XREF pthread_attr_getinheritsched
|
||||
.XREF pthread_attr_setscope
|
||||
.XREF pthread_attr_getscope
|
||||
|
||||
.SH NAME
|
||||
pthread_attr_init, pthread_attr_destroy, pthread_attr_setdetachstate, pthread_attr_getdetachstate, pthread_attr_setschedparam, pthread_attr_getschedparam, pthread_attr_setschedpolicy, pthread_attr_getschedpolicy, pthread_attr_setinheritsched, pthread_attr_getinheritsched, pthread_attr_setscope, pthread_attr_getscope \- thread creation attributes
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_attr_init(pthread_attr_t *attr);
|
||||
|
||||
int pthread_attr_destroy(pthread_attr_t *attr);
|
||||
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
|
||||
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
|
||||
|
||||
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
|
||||
|
||||
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
|
||||
|
||||
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
|
||||
|
||||
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
|
||||
|
||||
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
|
||||
|
||||
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);
|
||||
|
||||
int pthread_attr_setscope(pthread_attr_t *attr, int scope);
|
||||
|
||||
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Setting attributes for threads is achieved by filling a
|
||||
thread attribute object |attr| of type !pthread_attr_t!, then passing it as
|
||||
second argument to !pthread_create!(3). Passing !NULL! is equivalent to
|
||||
passing a thread attribute object with all attributes set to their
|
||||
default values.
|
||||
|
||||
!pthread_attr_init! initializes the thread attribute object |attr| and
|
||||
fills it with default values for the attributes. (The default values
|
||||
are listed below for each attribute.)
|
||||
|
||||
Each attribute |attrname| (see below for a list of all attributes) can
|
||||
be individually set using the function !pthread_attr_set!|attrname|
|
||||
and retrieved using the function !pthread_attr_get!|attrname|.
|
||||
|
||||
!pthread_attr_destroy! destroys a thread attribute object, which
|
||||
must not be reused until it is reinitialized. !pthread_attr_destroy!
|
||||
does nothing in the LinuxThreads implementation.
|
||||
|
||||
Attribute objects are consulted only when creating a new thread. The
|
||||
same attribute object can be used for creating several
|
||||
threads. Modifying an attribute object after a call to
|
||||
!pthread_create! does not change the attributes of the thread
|
||||
previously created.
|
||||
|
||||
The following thread attributes are supported:
|
||||
|
||||
.SS detachstate
|
||||
|
||||
Control whether the thread is created in the joinable state (value
|
||||
!PTHREAD_CREATE_JOINABLE!) or in the detached state
|
||||
(!PTHREAD_CREATE_DETACHED!).
|
||||
|
||||
Default value: !PTHREAD_CREATE_JOINABLE!.
|
||||
|
||||
In the joinable state, another thread can synchronize on the thread
|
||||
termination and recover its termination code using !pthread_join!(3),
|
||||
but some of the thread resources are kept allocated after the thread
|
||||
terminates, and reclaimed only when another thread performs
|
||||
!pthread_join!(3) on that thread.
|
||||
|
||||
In the detached state, the thread resources are immediately freed when
|
||||
it terminates, but !pthread_join!(3) cannot be used to synchronize on
|
||||
the thread termination.
|
||||
|
||||
A thread created in the joinable state can later be put in the
|
||||
detached thread using !pthread_detach!(3).
|
||||
|
||||
.SS schedpolicy
|
||||
|
||||
Select the scheduling policy for the thread: one of
|
||||
!SCHED_OTHER! (regular, non-realtime scheduling),
|
||||
!SCHED_RR! (realtime, round-robin) or
|
||||
!SCHED_FIFO! (realtime, first-in first-out). See
|
||||
!sched_setpolicy!(2) for more information on scheduling policies.
|
||||
|
||||
Default value: !SCHED_OTHER!.
|
||||
|
||||
The realtime scheduling policies !SCHED_RR! and !SCHED_FIFO! are
|
||||
available only to processes with superuser privileges.
|
||||
|
||||
The scheduling policy of a thread can be changed after creation with
|
||||
!pthread_setschedparam!(3).
|
||||
|
||||
.SS schedparam
|
||||
|
||||
Contain the scheduling parameters (essentially, the scheduling
|
||||
priority) for the thread. See !sched_setparam!(2) for more information
|
||||
on scheduling parameters.
|
||||
|
||||
Default value: priority is 0.
|
||||
|
||||
This attribute is not significant if the scheduling policy is !SCHED_OTHER!;
|
||||
it only matters for the realtime policies !SCHED_RR! and !SCHED_FIFO!.
|
||||
|
||||
The scheduling priority of a thread can be changed after creation with
|
||||
!pthread_setschedparam!(3).
|
||||
|
||||
.SS inheritsched
|
||||
|
||||
Indicate whether the scheduling policy and scheduling parameters for
|
||||
the newly created thread are determined by the values of the
|
||||
|schedpolicy| and |schedparam| attributes (value
|
||||
!PTHREAD_EXPLICIT_SCHED!) or are inherited from the parent thread
|
||||
(value !PTHREAD_INHERIT_SCHED!).
|
||||
|
||||
Default value: !PTHREAD_EXPLICIT_SCHED!.
|
||||
|
||||
.SS scope
|
||||
|
||||
Define the scheduling contention scope for the created thread. The
|
||||
only value supported in the LinuxThreads implementation is
|
||||
!PTHREAD_SCOPE_SYSTEM!, meaning that the threads contend for CPU time
|
||||
with all processes running on the machine. In particular, thread
|
||||
priorities are interpreted relative to the priorities of all other
|
||||
processes on the machine. The other value specified by the standard,
|
||||
!PTHREAD_SCOPE_PROCESS!, means that scheduling contention occurs only
|
||||
between the threads of the running process: thread priorities are
|
||||
interpreted relative to the priorities of the other threads of the
|
||||
process, regardless of the priorities of other processes.
|
||||
!PTHREAD_SCOPE_PROCESS! is not supported in LinuxThreads.
|
||||
|
||||
Default value: !PTHREAD_SCOPE_SYSTEM!.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
All functions return 0 on success and a non-zero error code on error.
|
||||
On success, the !pthread_attr_get!|attrname| functions also store the
|
||||
current value of the attribute |attrname| in the location pointed to
|
||||
by their second argument.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
The !pthread_attr_setdetachstate! function returns the following error
|
||||
codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the specified |detachstate| is not one of !PTHREAD_CREATE_JOINABLE! or
|
||||
!PTHREAD_CREATE_DETACHED!.
|
||||
.RE
|
||||
|
||||
The !pthread_attr_setschedparam! function returns the following error
|
||||
codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the priority specified in |param| is outside the range of allowed
|
||||
priorities for the scheduling policy currently in |attr|
|
||||
(1 to 99 for !SCHED_FIFO! and !SCHED_RR!; 0 for !SCHED_OTHER!).
|
||||
.RE
|
||||
|
||||
The !pthread_attr_setschedpolicy! function returns the following error
|
||||
codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the specified |policy| is not one of !SCHED_OTHER!, !SCHED_FIFO!, or
|
||||
!SCHED_RR!.
|
||||
|
||||
.TP
|
||||
!ENOTSUP!
|
||||
|policy| is !SCHED_FIFO! or !SCHED_RR!, and the effective user of the
|
||||
calling process is not super-user.
|
||||
.RE
|
||||
|
||||
The !pthread_attr_setinheritsched! function returns the following error
|
||||
codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the specified |inherit| is not one of !PTHREAD_INHERIT_SCHED! or
|
||||
!PTHREAD_EXPLICIT_SCHED!.
|
||||
.RE
|
||||
|
||||
The !pthread_attr_setscope! function returns the following error
|
||||
codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the specified |scope| is not one of !PTHREAD_SCOPE_SYSTEM! or
|
||||
!PTHREAD_SCOPE_PROCESS!.
|
||||
|
||||
.TP
|
||||
!ENOTSUP!
|
||||
the specified |scope| is !PTHREAD_SCOPE_PROCESS! (not supported).
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_create!(3),
|
||||
!pthread_join!(3),
|
||||
!pthread_detach!(3),
|
||||
!pthread_setschedparam!(3).
|
@ -1,155 +0,0 @@
|
||||
.TH PTHREAD_CANCEL 3 LinuxThreads
|
||||
|
||||
.XREF pthread_setcancelstate
|
||||
.XREF pthread_setcanceltype
|
||||
.XREF pthread_testcancel
|
||||
|
||||
.SH NAME
|
||||
pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel \- thread cancellation
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_cancel(pthread_t thread);
|
||||
|
||||
int pthread_setcancelstate(int state, int *oldstate);
|
||||
|
||||
int pthread_setcanceltype(int type, int *oldtype);
|
||||
|
||||
void pthread_testcancel(void);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Cancellation is the mechanism by which a thread can terminate the
|
||||
execution of another thread. More precisely, a thread can send a
|
||||
cancellation request to another thread. Depending on its settings, the
|
||||
target thread can then either ignore the request, honor it
|
||||
immediately, or defer it till it reaches a cancellation point.
|
||||
|
||||
When a thread eventually honors a cancellation request, it performs as
|
||||
if !pthread_exit(PTHREAD_CANCELED)! has been called at that point:
|
||||
all cleanup handlers are executed in reverse order, finalization
|
||||
functions for thread-specific data are called, and finally the thread
|
||||
stops executing with the return value !PTHREAD_CANCELED!. See
|
||||
!pthread_exit!(3) for more information.
|
||||
|
||||
!pthread_cancel! sends a cancellation request to the thread denoted
|
||||
by the |thread| argument.
|
||||
|
||||
!pthread_setcancelstate! changes the cancellation state for the
|
||||
calling thread -- that is, whether cancellation requests are ignored
|
||||
or not. The |state| argument is the new cancellation state: either
|
||||
!PTHREAD_CANCEL_ENABLE! to enable cancellation, or
|
||||
!PTHREAD_CANCEL_DISABLE! to disable cancellation (cancellation
|
||||
requests are ignored). If |oldstate| is not !NULL!, the previous
|
||||
cancellation state is stored in the location pointed to by |oldstate|,
|
||||
and can thus be restored later by another call to
|
||||
!pthread_setcancelstate!.
|
||||
|
||||
!pthread_setcanceltype! changes the type of responses to cancellation
|
||||
requests for the calling thread: asynchronous (immediate) or deferred.
|
||||
The |type| argument is the new cancellation type: either
|
||||
!PTHREAD_CANCEL_ASYNCHRONOUS! to cancel the calling thread as soon as
|
||||
the cancellation request is received, or !PTHREAD_CANCEL_DEFERRED! to
|
||||
keep the cancellation request pending until the next cancellation
|
||||
point. If |oldtype| is not !NULL!, the previous
|
||||
cancellation state is stored in the location pointed to by |oldtype|,
|
||||
and can thus be restored later by another call to
|
||||
!pthread_setcanceltype!.
|
||||
|
||||
Threads are always created by !pthread_create!(3) with cancellation
|
||||
enabled and deferred. That is, the initial cancellation state is
|
||||
!PTHREAD_CANCEL_ENABLE! and the initial type is
|
||||
!PTHREAD_CANCEL_DEFERRED!.
|
||||
|
||||
Cancellation points are those points in the program execution where a
|
||||
test for pending cancellation requests is performed and cancellation
|
||||
is executed if positive. The following POSIX threads functions
|
||||
are cancellation points:
|
||||
|
||||
!pthread_join!(3)
|
||||
.br
|
||||
!pthread_cond_wait!(3)
|
||||
.br
|
||||
!pthread_cond_timedwait!(3)
|
||||
.br
|
||||
!pthread_testcancel!(3)
|
||||
.br
|
||||
!sem_wait!(3)
|
||||
.br
|
||||
!sigwait!(3)
|
||||
|
||||
All other POSIX threads functions are guaranteed not to be
|
||||
cancellation points. That is, they never perform cancellation in
|
||||
deferred cancellation mode.
|
||||
|
||||
!pthread_testcancel! does nothing except testing for pending
|
||||
cancellation and executing it. Its purpose is to introduce explicit
|
||||
checks for cancellation in long sequences of code that do not call
|
||||
cancellation point functions otherwise.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
!pthread_cancel!, !pthread_setcancelstate! and
|
||||
!pthread_setcanceltype! return 0 on success and a non-zero error code
|
||||
on error.
|
||||
|
||||
.SH ERRORS
|
||||
!pthread_cancel! returns the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!ESRCH!
|
||||
no thread could be found corresponding to that specified by the |thread| ID.
|
||||
.RE
|
||||
|
||||
!pthread_setcancelstate! returns the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the |state| argument is not !PTHREAD_CANCEL_ENABLE! nor
|
||||
!PTHREAD_CANCEL_DISABLE!
|
||||
.RE
|
||||
|
||||
!pthread_setcanceltype! returns the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the |type| argument is not !PTHREAD_CANCEL_DEFERRED! nor
|
||||
!PTHREAD_CANCEL_ASYNCHRONOUS!
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_exit!(3),
|
||||
!pthread_cleanup_push!(3),
|
||||
!pthread_cleanup_pop!(3).
|
||||
|
||||
.SH BUGS
|
||||
|
||||
POSIX specifies that a number of system calls (basically, all
|
||||
system calls that may block, such as !read!(2), !write!(2), !wait!(2),
|
||||
etc.) and library functions that may call these system calls (e.g.
|
||||
!fprintf!(3)) are cancellation points. LinuxThreads is not yet
|
||||
integrated enough with the C library to implement this, and thus none
|
||||
of the C library functions is a cancellation point.
|
||||
|
||||
For system calls at least, there is a workaround. Cancellation
|
||||
requests are transmitted to the target thread by sending it a
|
||||
signal. That signal will interrupt all blocking system calls, causing
|
||||
them to return immediately with the !EINTR! error. So, checking for
|
||||
cancellation during a !read! system call, for instance, can be
|
||||
achieved as follows:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_testcancel();
|
||||
retcode = read(fd, buffer, length);
|
||||
pthread_testcancel();
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
@ -1,194 +0,0 @@
|
||||
.TH PTHREAD_CLEANUP 3 LinuxThreads
|
||||
|
||||
.XREF pthread_cleanup_pop
|
||||
.XREF pthread_cleanup_push_defer_np
|
||||
.XREF pthread_cleanup_pop_restore_np
|
||||
|
||||
.SH NAME
|
||||
pthread_cleanup_push, pthread_cleanup_pop, pthread_cleanup_push_defer_np, pthread_cleanup_pop_restore_np \- install and remove cleanup handlers
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
void pthread_cleanup_push(void (*routine) (void *), void *arg);
|
||||
|
||||
void pthread_cleanup_pop(int execute);
|
||||
|
||||
void pthread_cleanup_push_defer_np(void (*routine) (void *), void *arg);
|
||||
|
||||
void pthread_cleanup_pop_restore_np(int execute);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Cleanup handlers are functions that get called when a thread
|
||||
terminates, either by calling !pthread_exit!(3p) or because of
|
||||
cancellation. Cleanup handlers are installed and removed following a
|
||||
stack-like discipline.
|
||||
|
||||
The purpose of cleanup handlers is to free the resources that a thread
|
||||
may hold at the time it terminates. In particular, if a thread
|
||||
exits or is cancelled while it owns a locked mutex, the mutex will
|
||||
remain locked forever and prevent other threads from executing
|
||||
normally. The best way to avoid this is, just before locking the
|
||||
mutex, to install a cleanup handler whose effect is to unlock the
|
||||
mutex. Cleanup handlers can be used similarly to free blocks allocated
|
||||
with !malloc!(3) or close file descriptors on thread termination.
|
||||
|
||||
!pthread_cleanup_push! installs the |routine| function with argument
|
||||
|arg| as a cleanup handler. From this point on to the matching
|
||||
!pthread_cleanup_pop!, the function |routine| will be called with
|
||||
arguments |arg| when the thread terminates, either through !pthread_exit!(3p)
|
||||
or by cancellation. If several cleanup handlers are active at that
|
||||
point, they are called in LIFO order: the most recently installed
|
||||
handler is called first.
|
||||
|
||||
!pthread_cleanup_pop! removes the most recently installed cleanup
|
||||
handler. If the |execute| argument is not 0, it also executes the
|
||||
handler, by calling the |routine| function with arguments |arg|. If
|
||||
the |execute| argument is 0, the handler is only removed but not
|
||||
executed.
|
||||
|
||||
Matching pairs of !pthread_cleanup_push! and !pthread_cleanup_pop!
|
||||
must occur in the same function, at the same level of block nesting.
|
||||
Actually, !pthread_cleanup_push! and !pthread_cleanup_pop! are macros,
|
||||
and the expansion of !pthread_cleanup_push! introduces an open brace !{!
|
||||
with the matching closing brace !}! being introduced by the expansion
|
||||
of the matching !pthread_cleanup_pop!.
|
||||
|
||||
!pthread_cleanup_push_defer_np! is a non-portable extension that
|
||||
combines !pthread_cleanup_push! and !pthread_setcanceltype!(3p).
|
||||
It pushes a cleanup handler just as !pthread_cleanup_push! does, but
|
||||
also saves the current cancellation type and sets it to deferred
|
||||
cancellation. This ensures that the cleanup mechanism is effective
|
||||
even if the thread was initially in asynchronous cancellation mode.
|
||||
|
||||
!pthread_cleanup_pop_restore_np! pops a cleanup handler introduced by
|
||||
!pthread_cleanup_push_defer_np!, and restores the cancellation type to
|
||||
its value at the time !pthread_cleanup_push_defer_np! was called.
|
||||
|
||||
!pthread_cleanup_push_defer_np! and !pthread_cleanup_pop_restore_np!
|
||||
must occur in matching pairs, at the same level of block nesting.
|
||||
|
||||
The following sequence
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_cleanup_push_defer_np(routine, arg);
|
||||
...
|
||||
pthread_cleanup_pop_defer_np(execute);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
is functionally equivalent to (but more compact and more efficient than)
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
{ int oldtype;
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
|
||||
pthread_cleanup_push(routine, arg);
|
||||
...
|
||||
pthread_cleanup_pop(execute);
|
||||
pthread_setcanceltype(oldtype, NULL);
|
||||
}
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
None.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
None.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_exit!(3p),
|
||||
!pthread_cancel!(3p),
|
||||
!pthread_setcanceltype!(3p).
|
||||
|
||||
.SH EXAMPLE
|
||||
|
||||
Here is how to lock a mutex |mut| in such a way that it will be
|
||||
unlocked if the thread is canceled while |mut| is locked:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
|
||||
pthread_mutex_lock(&mut);
|
||||
/* do some work */
|
||||
pthread_mutex_unlock(&mut);
|
||||
pthread_cleanup_pop(0);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
Equivalently, the last two lines can be replaced by
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_cleanup_pop(1);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
Notice that the code above is safe only in deferred cancellation mode
|
||||
(see !pthread_setcanceltype!(3p)). In asynchronous cancellation mode,
|
||||
a cancellation can occur between !pthread_cleanup_push! and
|
||||
!pthread_mutex_lock!, or between !pthread_mutex_unlock! and
|
||||
!pthread_cleanup_pop!, resulting in both cases in the thread trying to
|
||||
unlock a mutex not locked by the current thread. This is the main
|
||||
reason why asynchronous cancellation is difficult to use.
|
||||
|
||||
If the code above must also work in asynchronous cancellation mode,
|
||||
then it must switch to deferred mode for locking and unlocking the
|
||||
mutex:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
|
||||
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
|
||||
pthread_mutex_lock(&mut);
|
||||
/* do some work */
|
||||
pthread_cleanup_pop(1);
|
||||
pthread_setcanceltype(oldtype, NULL);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
The code above can be rewritten in a more compact and more
|
||||
efficient way, using the non-portable functions
|
||||
!pthread_cleanup_push_defer_np! and !pthread_cleanup_pop_restore_np!:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_cleanup_push_restore_np(pthread_mutex_unlock, (void *) &mut);
|
||||
pthread_mutex_lock(&mut);
|
||||
/* do some work */
|
||||
pthread_cleanup_pop_restore_np(1);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
@ -1,234 +0,0 @@
|
||||
.TH PTHREAD_COND 3 LinuxThreads
|
||||
|
||||
.XREF pthread_cond_signal
|
||||
.XREF pthread_cond_broadcast
|
||||
.XREF pthread_cond_wait
|
||||
.XREF pthread_cond_timedwait
|
||||
.XREF pthread_cond_destroy
|
||||
|
||||
.SH NAME
|
||||
pthread_cond_init, pthread_cond_destroy, pthread_cond_signal, pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait \- operations on conditions
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
A condition (short for ``condition variable'') is a synchronization
|
||||
device that allows threads to suspend execution and relinquish the
|
||||
processors until some predicate on shared data is satisfied. The basic
|
||||
operations on conditions are: signal the condition (when the
|
||||
predicate becomes true), and wait for the condition, suspending the
|
||||
thread execution until another thread signals the condition.
|
||||
|
||||
A condition variable must always be associated with a mutex, to avoid
|
||||
the race condition where a thread prepares to wait on a condition
|
||||
variable and another thread signals the condition just before the
|
||||
first thread actually waits on it.
|
||||
|
||||
!pthread_cond_init! initializes the condition variable |cond|, using the
|
||||
condition attributes specified in |cond_attr|, or default attributes
|
||||
if |cond_attr| is !NULL!. The LinuxThreads implementation supports no
|
||||
attributes for conditions, hence the |cond_attr| parameter is actually
|
||||
ignored.
|
||||
|
||||
Variables of type !pthread_cond_t! can also be initialized
|
||||
statically, using the constant !PTHREAD_COND_INITIALIZER!.
|
||||
|
||||
!pthread_cond_signal! restarts one of the threads that are waiting on
|
||||
the condition variable |cond|. If no threads are waiting on |cond|,
|
||||
nothing happens. If several threads are waiting on |cond|, exactly one
|
||||
is restarted, but it is not specified which.
|
||||
|
||||
!pthread_cond_broadcast! restarts all the threads that are waiting on
|
||||
the condition variable |cond|. Nothing happens if no threads are
|
||||
waiting on |cond|.
|
||||
|
||||
!pthread_cond_wait! atomically unlocks the |mutex| (as per
|
||||
!pthread_unlock_mutex!) and waits for the condition variable |cond| to
|
||||
be signaled. The thread execution is suspended and does not consume
|
||||
any CPU time until the condition variable is signaled. The |mutex|
|
||||
must be locked by the calling thread on entrance to
|
||||
!pthread_cond_wait!. Before returning to the calling thread,
|
||||
!pthread_cond_wait! re-acquires |mutex| (as per !pthread_lock_mutex!).
|
||||
|
||||
Unlocking the mutex and suspending on the condition variable is done
|
||||
atomically. Thus, if all threads always acquire the mutex before
|
||||
signaling the condition, this guarantees that the condition cannot be
|
||||
signaled (and thus ignored) between the time a thread locks the mutex
|
||||
and the time it waits on the condition variable.
|
||||
|
||||
!pthread_cond_timedwait! atomically unlocks |mutex| and waits on
|
||||
|cond|, as !pthread_cond_wait! does, but it also bounds the duration
|
||||
of the wait. If |cond| has not been signaled within the amount of time
|
||||
specified by |abstime|, the mutex |mutex| is re-acquired and
|
||||
!pthread_cond_timedwait! returns the error !ETIMEDOUT!.
|
||||
The |abstime| parameter specifies an absolute time, with the same
|
||||
origin as !time!(2) and !gettimeofday!(2): an |abstime| of 0
|
||||
corresponds to 00:00:00 GMT, January 1, 1970.
|
||||
|
||||
!pthread_cond_destroy! destroys a condition variable, freeing the
|
||||
resources it might hold. No threads must be waiting on the condition
|
||||
variable on entrance to !pthread_cond_destroy!. In the LinuxThreads
|
||||
implementation, no resources are associated with condition variables,
|
||||
thus !pthread_cond_destroy! actually does nothing except checking that
|
||||
the condition has no waiting threads.
|
||||
|
||||
.SH CANCELLATION
|
||||
|
||||
!pthread_cond_wait! and !pthread_cond_timedwait! are cancellation
|
||||
points. If a thread is cancelled while suspended in one of these
|
||||
functions, the thread immediately resumes execution, then locks again
|
||||
the |mutex| argument to !pthread_cond_wait! and
|
||||
!pthread_cond_timedwait!, and finally executes the cancellation.
|
||||
Consequently, cleanup handlers are assured that |mutex| is locked when
|
||||
they are called.
|
||||
|
||||
.SH "ASYNC-SIGNAL SAFETY"
|
||||
|
||||
The condition functions are not async-signal safe, and should not be
|
||||
called from a signal handler. In particular, calling
|
||||
!pthread_cond_signal! or !pthread_cond_broadcast! from a signal
|
||||
handler may deadlock the calling thread.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
All condition variable functions return 0 on success and a non-zero
|
||||
error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
!pthread_cond_init!, !pthread_cond_signal!, !pthread_cond_broadcast!,
|
||||
and !pthread_cond_wait! never return an error code.
|
||||
|
||||
The !pthread_cond_timedwait! function returns the following error codes
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!ETIMEDOUT!
|
||||
the condition variable was not signaled until the timeout specified by
|
||||
|abstime|
|
||||
|
||||
.TP
|
||||
!EINTR!
|
||||
!pthread_cond_timedwait! was interrupted by a signal
|
||||
.RE
|
||||
|
||||
The !pthread_cond_destroy! function returns the following error code
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EBUSY!
|
||||
some threads are currently waiting on |cond|.
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_condattr_init!(3),
|
||||
!pthread_mutex_lock!(3),
|
||||
!pthread_mutex_unlock!(3),
|
||||
!gettimeofday!(2),
|
||||
!nanosleep!(2).
|
||||
|
||||
.SH EXAMPLE
|
||||
|
||||
Consider two shared variables |x| and |y|, protected by the mutex |mut|,
|
||||
and a condition variable |cond| that is to be signaled whenever |x|
|
||||
becomes greater than |y|.
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
int x,y;
|
||||
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
Waiting until |x| is greater than |y| is performed as follows:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_mutex_lock(&mut);
|
||||
while (x <= y) {
|
||||
pthread_cond_wait(&cond, &mut);
|
||||
}
|
||||
/* operate on x and y */
|
||||
pthread_mutex_unlock(&mut);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
Modifications on |x| and |y| that may cause |x| to become greater than
|
||||
|y| should signal the condition if needed:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_mutex_lock(&mut);
|
||||
/* modify x and y */
|
||||
if (x > y) pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mut);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
If it can be proved that at most one waiting thread needs to be waken
|
||||
up (for instance, if there are only two threads communicating through
|
||||
|x| and |y|), !pthread_cond_signal! can be used as a slightly more
|
||||
efficient alternative to !pthread_cond_broadcast!. In doubt, use
|
||||
!pthread_cond_broadcast!.
|
||||
|
||||
To wait for |x| to becomes greater than |y| with a timeout of 5
|
||||
seconds, do:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
int retcode;
|
||||
|
||||
pthread_mutex_lock(&mut);
|
||||
gettimeofday(&now);
|
||||
timeout.tv_sec = now.tv_sec + 5;
|
||||
timeout.tv_nsec = now.tv_usec * 1000;
|
||||
retcode = 0;
|
||||
while (x <= y && retcode != ETIMEDOUT) {
|
||||
retcode = pthread_cond_timedwait(&cond, &mut, &timeout);
|
||||
}
|
||||
if (retcode == ETIMEDOUT) {
|
||||
/* timeout occurred */
|
||||
} else {
|
||||
/* operate on x and y */
|
||||
}
|
||||
pthread_mutex_unlock(&mut);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
@ -1,39 +0,0 @@
|
||||
.TH PTHREAD_CONDATTR 3 LinuxThreads
|
||||
|
||||
.XREF pthread_condattr_destroy
|
||||
|
||||
.SH NAME
|
||||
pthread_condattr_init, pthread_condattr_destroy \- condition creation attributes
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_condattr_init(pthread_condattr_t *attr);
|
||||
|
||||
int pthread_condattr_destroy(pthread_condattr_t *attr);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Condition attributes can be specified at condition creation time, by passing a
|
||||
condition attribute object as second argument to !pthread_cond_init!(3).
|
||||
Passing !NULL! is equivalent to passing a condition attribute object with
|
||||
all attributes set to their default values.
|
||||
|
||||
The LinuxThreads implementation supports no attributes for
|
||||
conditions. The functions on condition attributes are included only
|
||||
for compliance with the POSIX standard.
|
||||
|
||||
!pthread_condattr_init! initializes the condition attribute object
|
||||
|attr| and fills it with default values for the attributes.
|
||||
!pthread_condattr_destroy! destroys a condition attribute object,
|
||||
which must not be reused until it is reinitialized. Both functions do
|
||||
nothing in the LinuxThreads implementation.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
!pthread_condattr_init! and !pthread_condattr_destroy! always return 0.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_cond_init!(3).
|
@ -1,46 +0,0 @@
|
||||
.TH PTHREAD_CREATE 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_create \- create a new thread
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_create! creates a new thread of control that executes
|
||||
concurrently with the calling thread. The new thread applies the
|
||||
function |start_routine| passing it |arg| as first argument. The new
|
||||
thread terminates either explicitly, by calling !pthread_exit!(3),
|
||||
or implicitly, by returning from the |start_routine| function. The
|
||||
latter case is equivalent to calling !pthread_exit!(3) with the result
|
||||
returned by |start_routine| as exit code.
|
||||
|
||||
The |attr| argument specifies thread attributes to be applied to the
|
||||
new thread. See !pthread_attr_init!(3) for a complete list of thread
|
||||
attributes. The |attr| argument can also be !NULL!, in which case
|
||||
default attributes are used: the created thread is joinable (not
|
||||
detached) and has default (non real-time) scheduling policy.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
On success, the identifier of the newly created thread is stored in
|
||||
the location pointed by the |thread| argument, and a 0 is returned. On
|
||||
error, a non-zero error code is returned.
|
||||
|
||||
.SH ERRORS
|
||||
.TP
|
||||
!EAGAIN!
|
||||
not enough system resources to create a process for the new thread.
|
||||
.TP
|
||||
!EAGAIN!
|
||||
more than !PTHREAD_THREADS_MAX! threads are already active.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_exit!(3),
|
||||
!pthread_join!(3),
|
||||
!pthread_detach!(3),
|
||||
!pthread_attr_init!(3).
|
@ -1,44 +0,0 @@
|
||||
.TH PTHREAD_DETACH 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_detach \- put a running thread in the detached state
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_detach(pthread_t th);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_detach! put the thread |th| in the detached state. This
|
||||
guarantees that the memory resources consumed by |th| will be freed
|
||||
immediately when |th| terminates. However, this prevents other threads
|
||||
from synchronizing on the termination of |th| using !pthread_join!.
|
||||
|
||||
A thread can be created initially in the detached state, using the
|
||||
!detachstate! attribute to !pthread_create!(3). In contrast,
|
||||
!pthread_detach! applies to threads created in the joinable state, and
|
||||
which need to be put in the detached state later.
|
||||
|
||||
After !pthread_detach! completes, subsequent attempts to perform
|
||||
!pthread_join! on |th| will fail. If another thread is already joining
|
||||
the thread |th| at the time !pthread_detach! is called,
|
||||
!pthread_detach! does nothing and leaves |th| in the joinable state.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
On success, 0 is returned. On error, a non-zero error code is returned.
|
||||
|
||||
.SH ERRORS
|
||||
.TP
|
||||
!ESRCH!
|
||||
No thread could be found corresponding to that specified by |th|
|
||||
.TP
|
||||
!EINVAL!
|
||||
the thread |th| is already in the detached state
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_create!(3),
|
||||
!pthread_join!(3),
|
||||
!pthread_attr_setdetachstate!(3).
|
@ -1,23 +0,0 @@
|
||||
.TH PTHREAD_EQUAL 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_equal \- compare two thread identifiers
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_equal(pthread_t thread1, pthread_t thread2);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_equal! determines if two thread identifiers refer to the same
|
||||
thread.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
A non-zero value is returned if |thread1| and |thread2| refer to the
|
||||
same thread. Otherwise, 0 is returned.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_self!(3).
|
@ -1,32 +0,0 @@
|
||||
.TH PTHREAD_EXIT 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_exit \- terminate the calling thread
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
void pthread_exit(void *retval);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_exit! terminates the execution of the calling thread.
|
||||
All cleanup handlers that have been set for the calling thread with
|
||||
!pthread_cleanup_push!(3) are executed in reverse order (the most
|
||||
recently pushed handler is executed first). Finalization functions for
|
||||
thread-specific data are then called for all keys that have non-!NULL!
|
||||
values associated with them in the calling thread (see
|
||||
!pthread_key_create!(3)). Finally, execution of the calling thread is
|
||||
stopped.
|
||||
|
||||
The |retval| argument is the return value of the thread. It can be
|
||||
consulted from another thread using !pthread_join!(3).
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
The !pthread_exit! function never returns.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_create!(3),
|
||||
!pthread_join!(3).
|
@ -1,70 +0,0 @@
|
||||
.TH PTHREAD_JOIN 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_join \- wait for termination of another thread
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_join(pthread_t th, void **thread_return);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_join! suspends the execution of the calling thread until the
|
||||
thread identified by |th| terminates, either by calling !pthread_exit!(3)
|
||||
or by being cancelled.
|
||||
|
||||
If |thread_return| is not !NULL!, the return value of |th| is stored
|
||||
in the location pointed to by |thread_return|. The return value of
|
||||
|th| is either the argument it gave to !pthread_exit!(3), or
|
||||
!PTHREAD_CANCELED! if |th| was cancelled.
|
||||
|
||||
The joined thread !th! must be in the joinable state: it must not have
|
||||
been detached using !pthread_detach!(3) or the
|
||||
!PTHREAD_CREATE_DETACHED! attribute to !pthread_create!(3).
|
||||
|
||||
When a joinable thread terminates, its memory resources (thread
|
||||
descriptor and stack) are not deallocated until another thread
|
||||
performs !pthread_join! on it. Therefore, !pthread_join! must be
|
||||
called once for each joinable thread created to avoid memory leaks.
|
||||
|
||||
At most one thread can wait for the termination of a given
|
||||
thread. Calling !pthread_join! on a thread |th| on which another
|
||||
thread is already waiting for termination returns an error.
|
||||
|
||||
.SH CANCELLATION
|
||||
|
||||
!pthread_join! is a cancellation point. If a thread is canceled while
|
||||
suspended in !pthread_join!, the thread execution resumes immediately
|
||||
and the cancellation is executed without waiting for the |th| thread
|
||||
to terminate. If cancellation occurs during !pthread_join!, the |th|
|
||||
thread remains not joined.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
On success, the return value of |th| is stored in the location pointed
|
||||
to by |thread_return|, and 0 is returned. On error, a non-zero error
|
||||
code is returned.
|
||||
|
||||
.SH ERRORS
|
||||
.TP
|
||||
!ESRCH!
|
||||
No thread could be found corresponding to that specified by |th|.
|
||||
.TP
|
||||
!EINVAL!
|
||||
The |th| thread has been detached.
|
||||
.TP
|
||||
!EINVAL!
|
||||
Another thread is already waiting on termination of |th|.
|
||||
.TP
|
||||
!EDEADLK!
|
||||
The |th| argument refers to the calling thread.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_exit!(3),
|
||||
!pthread_detach!(3),
|
||||
!pthread_create!(3),
|
||||
!pthread_attr_setdetachstate!(3),
|
||||
!pthread_cleanup_push!(3),
|
||||
!pthread_key_create!(3).
|
@ -1,151 +0,0 @@
|
||||
.TH PTHREAD_SPECIFIC 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_key_create, pthread_key_delete, pthread_setspecific, pthread_getspecific \- management of thread-specific data
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
|
||||
|
||||
int pthread_key_delete(pthread_key_t key);
|
||||
|
||||
int pthread_setspecific(pthread_key_t key, const void *pointer);
|
||||
|
||||
void * pthread_getspecific(pthread_key_t key);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Programs often need global or static variables that have different
|
||||
values in different threads. Since threads share one memory space,
|
||||
this cannot be achieved with regular variables. Thread-specific data
|
||||
is the POSIX threads answer to this need.
|
||||
|
||||
Each thread possesses a private memory block, the thread-specific data
|
||||
area, or TSD area for short. This area is indexed by TSD keys. The TSD
|
||||
area associates values of type !void *! to TSD keys. TSD keys are
|
||||
common to all threads, but the value associated with a given TSD key
|
||||
can be different in each thread.
|
||||
|
||||
For concreteness, the TSD areas can be viewed as arrays of !void *!
|
||||
pointers, TSD keys as integer indices into these arrays, and the value
|
||||
of a TSD key as the value of the corresponding array element in the
|
||||
calling thread.
|
||||
|
||||
When a thread is created, its TSD area initially associates !NULL!
|
||||
with all keys.
|
||||
|
||||
!pthread_key_create! allocates a new TSD key. The key is stored in the
|
||||
location pointed to by |key|. There is a limit of !PTHREAD_KEYS_MAX!
|
||||
on the number of keys allocated at a given time. The value initially
|
||||
associated with the returned key is !NULL! in all currently executing
|
||||
threads.
|
||||
|
||||
The |destr_function| argument, if not !NULL!, specifies a destructor
|
||||
function associated with the key. When a thread terminates via
|
||||
!pthread_exit! or by cancellation, |destr_function| is called with
|
||||
arguments the value associated with the key in that thread. The
|
||||
|destr_function| is not called if that value is !NULL!. The order in
|
||||
which destructor functions are called at thread termination time is
|
||||
unspecified.
|
||||
|
||||
Before the destructor function is called, the !NULL! value is
|
||||
associated with the key in the current thread. A destructor function
|
||||
might, however, re-associate non-!NULL! values to that key or some
|
||||
other key. To deal with this, if after all the destructors have been
|
||||
called for all non-!NULL! values, there are still some non-!NULL!
|
||||
values with associated destructors, then the process is repeated. The
|
||||
LinuxThreads implementation stops the process after
|
||||
!PTHREAD_DESTRUCTOR_ITERATIONS! iterations, even if some non-!NULL!
|
||||
values with associated descriptors remain. Other implementations may
|
||||
loop indefinitely.
|
||||
|
||||
!pthread_key_delete! deallocates a TSD key. It does not check whether
|
||||
non-!NULL! values are associated with that key in the currently
|
||||
executing threads, nor call the destructor function associated with
|
||||
the key.
|
||||
|
||||
!pthread_setspecific! changes the value associated with |key| in the
|
||||
calling thread, storing the given |pointer| instead.
|
||||
|
||||
!pthread_getspecific! returns the value currently associated with
|
||||
|key| in the calling thread.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
!pthread_key_create!, !pthread_key_delete!, and !pthread_setspecific!
|
||||
return 0 on success and a non-zero error code on failure. If
|
||||
successful, !pthread_key_create! stores the newly allocated key in the
|
||||
location pointed to by its |key| argument.
|
||||
|
||||
!pthread_getspecific! returns the value associated with |key| on
|
||||
success, and !NULL! on error.
|
||||
|
||||
.SH ERRORS
|
||||
!pthread_key_create! returns the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EAGAIN!
|
||||
!PTHREAD_KEYS_MAX! keys are already allocated
|
||||
.RE
|
||||
|
||||
!pthread_key_delete! and !pthread_setspecific! return the following
|
||||
error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
|key| is not a valid, allocated TSD key
|
||||
.RE
|
||||
|
||||
!pthread_getspecific! returns !NULL! if |key| is not a valid,
|
||||
allocated TSD key.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
pthread_create(3), pthread_exit(3), pthread_testcancel(3).
|
||||
|
||||
.SH EXAMPLE
|
||||
|
||||
The following code fragment allocates a thread-specific array of 100
|
||||
characters, with automatic reclaimation at thread exit:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
/* Key for the thread-specific buffer */
|
||||
static pthread_key_t buffer_key;
|
||||
|
||||
/* Once-only initialisation of the key */
|
||||
static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
/* Allocate the thread-specific buffer */
|
||||
void buffer_alloc(void)
|
||||
{
|
||||
pthread_once(&buffer_key_once, buffer_key_alloc);
|
||||
pthread_setspecific(buffer_key, malloc(100));
|
||||
}
|
||||
|
||||
/* Return the thread-specific buffer */
|
||||
char * get_buffer(void)
|
||||
{
|
||||
return (char *) pthread_getspecific(buffer_key);
|
||||
}
|
||||
|
||||
/* Allocate the key */
|
||||
static void buffer_key_alloc()
|
||||
{
|
||||
pthread_key_create(&buffer_key, buffer_destroy);
|
||||
}
|
||||
|
||||
/* Free the thread-specific buffer */
|
||||
static void buffer_destroy(void * buf)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
@ -1,40 +0,0 @@
|
||||
.TH PTHREAD_KILL_OTHER_THREADS_NP 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_kill_other_threads_np \- terminate all threads in program except calling thread
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
void pthread_kill_other_threads_np(void);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_kill_other_threads_np! is a non-portable LinuxThreads extension.
|
||||
It causes all threads in the program to terminate immediately, except
|
||||
the calling thread which proceeds normally. It is intended to be
|
||||
called just before a thread calls one of the !exec! functions,
|
||||
e.g. !execve!(2).
|
||||
|
||||
Termination of the other threads is not performed through
|
||||
!pthread_cancel!(3p) and completely bypasses the cancellation
|
||||
mechanism. Hence, the current settings for cancellation state and
|
||||
cancellation type are ignored, and the cleanup handlers are not
|
||||
executed in the terminated threads.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!execve!(2),
|
||||
!pthread_setcancelstate!(3p),
|
||||
!pthread_setcanceltype!(3p),
|
||||
!pthread_cancel!(3p).
|
||||
|
||||
.SH BUGS
|
||||
|
||||
According to POSIX 1003.1c, a successful !exec*! in one of the threads
|
||||
should terminate automatically all other threads in the program.
|
||||
This behavior is not yet implemented in LinuxThreads.
|
||||
Calling !pthread_kill_other_threads_np! before !exec*! achieves much
|
||||
of the same behavior, except that if !exec*! ultimately fails, then
|
||||
all other threads are already killed.
|
@ -1,213 +0,0 @@
|
||||
.TH PTHREAD_MUTEX 3 LinuxThreads
|
||||
|
||||
.XREF pthread_mutex_lock
|
||||
.XREF pthread_mutex_unlock
|
||||
.XREF pthread_mutex_trylock
|
||||
.XREF pthread_mutex_destroy
|
||||
|
||||
.SH NAME
|
||||
pthread_mutex_init, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutex_destroy \- operations on mutexes
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
|
||||
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||
|
||||
.SH DESCRIPTION
|
||||
A mutex is a MUTual EXclusion device, and is useful for protecting
|
||||
shared data structures from concurrent modifications, and implementing
|
||||
critical sections and monitors.
|
||||
|
||||
A mutex has two possible states: unlocked (not owned by any thread),
|
||||
and locked (owned by one thread). A mutex can never be owned by two
|
||||
different threads simultaneously. A thread attempting to lock a mutex
|
||||
that is already locked by another thread is suspended until the owning
|
||||
thread unlocks the mutex first.
|
||||
|
||||
!pthread_mutex_init! initializes the mutex object pointed to by
|
||||
|mutex| according to the mutex attributes specified in |mutexattr|.
|
||||
If |mutexattr| is !NULL!, default attributes are used instead.
|
||||
|
||||
The LinuxThreads implementation supports only one mutex attributes,
|
||||
the |mutex kind|, which is either ``fast'', ``recursive'', or
|
||||
``error checking''. The kind of a mutex determines whether
|
||||
it can be locked again by a thread that already owns it.
|
||||
The default kind is ``fast''. See !pthread_mutexattr_init!(3) for more
|
||||
information on mutex attributes.
|
||||
|
||||
Variables of type !pthread_mutex_t! can also be initialized
|
||||
statically, using the constants !PTHREAD_MUTEX_INITIALIZER! (for fast
|
||||
mutexes), !PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP! (for recursive
|
||||
mutexes), and !PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP! (for error checking
|
||||
mutexes).
|
||||
|
||||
!pthread_mutex_lock! locks the given mutex. If the mutex is currently
|
||||
unlocked, it becomes locked and owned by the calling thread, and
|
||||
!pthread_mutex_lock! returns immediately. If the mutex is already
|
||||
locked by another thread, !pthread_mutex_lock! suspends the calling
|
||||
thread until the mutex is unlocked.
|
||||
|
||||
If the mutex is already locked by the calling thread, the behavior of
|
||||
!pthread_mutex_lock! depends on the kind of the mutex. If the mutex is
|
||||
of the ``fast'' kind, the calling thread is suspended until the mutex
|
||||
is unlocked, thus effectively causing the calling thread to
|
||||
deadlock. If the mutex is of the ``error checking'' kind,
|
||||
!pthread_mutex_lock! returns immediately with the error code !EDEADLK!.
|
||||
If the mutex is of the ``recursive'' kind, !pthread_mutex_lock!
|
||||
succeeds and returns immediately, recording the number of times the
|
||||
calling thread has locked the mutex. An equal number of
|
||||
!pthread_mutex_unlock! operations must be performed before the mutex
|
||||
returns to the unlocked state.
|
||||
|
||||
!pthread_mutex_trylock! behaves identically to !pthread_mutex_lock!,
|
||||
except that it does not block the calling thread if the mutex is
|
||||
already locked by another thread (or by the calling thread in the case
|
||||
of a ``fast'' mutex). Instead, !pthread_mutex_trylock! returns
|
||||
immediately with the error code !EBUSY!.
|
||||
|
||||
!pthread_mutex_unlock! unlocks the given mutex. The mutex is assumed
|
||||
to be locked and owned by the calling thread on entrance to
|
||||
!pthread_mutex_unlock!. If the mutex is of the ``fast'' kind,
|
||||
!pthread_mutex_unlock! always returns it to the unlocked state. If it
|
||||
is of the ``recursive'' kind, it decrements the locking count of the
|
||||
mutex (number of !pthread_mutex_lock! operations performed on it by
|
||||
the calling thread), and only when this count reaches zero is the
|
||||
mutex actually unlocked.
|
||||
|
||||
On ``error checking'' mutexes, !pthread_mutex_unlock! actually checks
|
||||
at run-time that the mutex is locked on entrance, and that it was
|
||||
locked by the same thread that is now calling !pthread_mutex_unlock!.
|
||||
If these conditions are not met, an error code is returned and the
|
||||
mutex remains unchanged. ``Fast'' and ``recursive'' mutexes perform
|
||||
no such checks, thus allowing a locked mutex to be unlocked by a
|
||||
thread other than its owner. This is non-portable behavior and must
|
||||
not be relied upon.
|
||||
|
||||
!pthread_mutex_destroy! destroys a mutex object, freeing the resources
|
||||
it might hold. The mutex must be unlocked on entrance. In the
|
||||
LinuxThreads implementation, no resources are associated with mutex
|
||||
objects, thus !pthread_mutex_destroy! actually does nothing except
|
||||
checking that the mutex is unlocked.
|
||||
|
||||
.SH CANCELLATION
|
||||
|
||||
None of the mutex functions is a cancellation point, not even
|
||||
!pthread_mutex_lock!, in spite of the fact that it can suspend a
|
||||
thread for arbitrary durations. This way, the status of mutexes at
|
||||
cancellation points is predictable, allowing cancellation handlers to
|
||||
unlock precisely those mutexes that need to be unlocked before the
|
||||
thread stops executing. Consequently, threads using deferred
|
||||
cancellation should never hold a mutex for extended periods of time.
|
||||
|
||||
.SH "ASYNC-SIGNAL SAFETY"
|
||||
|
||||
The mutex functions are not async-signal safe. What this means is that
|
||||
they should not be called from a signal handler. In particular,
|
||||
calling !pthread_mutex_lock! or !pthread_mutex_unlock! from a signal
|
||||
handler may deadlock the calling thread.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
!pthread_mutex_init! always returns 0. The other mutex functions
|
||||
return 0 on success and a non-zero error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
The !pthread_mutex_lock! function returns the following error code
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the mutex has not been properly initialized.
|
||||
|
||||
.TP
|
||||
!EDEADLK!
|
||||
the mutex is already locked by the calling thread
|
||||
(``error checking'' mutexes only).
|
||||
.RE
|
||||
|
||||
The !pthread_mutex_trylock! function returns the following error codes
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EBUSY!
|
||||
the mutex could not be acquired because it was currently locked.
|
||||
|
||||
.TP
|
||||
!EINVAL!
|
||||
the mutex has not been properly initialized.
|
||||
.RE
|
||||
|
||||
The !pthread_mutex_unlock! function returns the following error code
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
the mutex has not been properly initialized.
|
||||
|
||||
.TP
|
||||
!EPERM!
|
||||
the calling thread does not own the mutex (``error checking'' mutexes only).
|
||||
.RE
|
||||
|
||||
The !pthread_mutex_destroy! function returns the following error code
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EBUSY!
|
||||
the mutex is currently locked.
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_mutexattr_init!(3),
|
||||
!pthread_mutexattr_setkind_np!(3),
|
||||
!pthread_cancel!(3).
|
||||
|
||||
.SH EXAMPLE
|
||||
|
||||
A shared global variable |x| can be protected by a mutex as follows:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
int x;
|
||||
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
All accesses and modifications to |x| should be bracketed by calls to
|
||||
!pthread_mutex_lock! and !pthread_mutex_unlock! as follows:
|
||||
|
||||
.RS
|
||||
.ft 3
|
||||
.nf
|
||||
.sp
|
||||
pthread_mutex_lock(&mut);
|
||||
/* operate on x */
|
||||
pthread_mutex_unlock(&mut);
|
||||
.ft
|
||||
.LP
|
||||
.RE
|
||||
.fi
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
.TH PTHREAD_MUTEXATTR 3 LinuxThreads
|
||||
|
||||
.XREF pthread_mutexattr_destroy
|
||||
.XREF pthread_mutexattr_settype
|
||||
.XREF pthread_mutexattr_gettype
|
||||
|
||||
.SH NAME
|
||||
pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_settype, pthread_mutexattr_gettype \- mutex creation attributes
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
|
||||
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
|
||||
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||
|
||||
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Mutex attributes can be specified at mutex creation time, by passing a
|
||||
mutex attribute object as second argument to !pthread_mutex_init!(3).
|
||||
Passing !NULL! is equivalent to passing a mutex attribute object with
|
||||
all attributes set to their default values.
|
||||
|
||||
!pthread_mutexattr_init! initializes the mutex attribute object |attr|
|
||||
and fills it with default values for the attributes.
|
||||
|
||||
!pthread_mutexattr_destroy! destroys a mutex attribute object, which
|
||||
must not be reused until it is reinitialized. !pthread_mutexattr_destroy!
|
||||
does nothing in the LinuxThreads implementation.
|
||||
|
||||
LinuxThreads supports only one mutex attribute: the mutex kind, which
|
||||
is either !PTHREAD_MUTEX_FAST_NP! for ``fast'' mutexes,
|
||||
!PTHREAD_MUTEX_RECURSIVE_NP! for ``recursive'' mutexes,
|
||||
or !PTHREAD_MUTEX_ERRORCHECK_NP! for ``error checking'' mutexes.
|
||||
As the !NP! suffix indicates, this is a non-portable extension to the
|
||||
POSIX standard and should not be employed in portable programs.
|
||||
|
||||
The mutex kind determines what happens if a thread attempts to lock a
|
||||
mutex it already owns with !pthread_mutex_lock!(3). If the mutex is of
|
||||
the ``fast'' kind, !pthread_mutex_lock!(3) simply suspends the calling
|
||||
thread forever. If the mutex is of the ``error checking'' kind,
|
||||
!pthread_mutex_lock!(3) returns immediately with the error code
|
||||
!EDEADLK!. If the mutex is of the ``recursive'' kind, the call to
|
||||
!pthread_mutex_lock!(3) returns immediately with a success return
|
||||
code. The number of times the thread owning the mutex has locked it is
|
||||
recorded in the mutex. The owning thread must call
|
||||
!pthread_mutex_unlock!(3) the same number of times before the mutex
|
||||
returns to the unlocked state.
|
||||
|
||||
The default mutex kind is ``fast'', that is, !PTHREAD_MUTEX_FAST_NP!.
|
||||
|
||||
!pthread_mutexattr_settype! sets the mutex kind attribute in |attr|
|
||||
to the value specified by |kind|.
|
||||
|
||||
!pthread_mutexattr_gettype! retrieves the current value of the
|
||||
mutex kind attribute in |attr| and stores it in the location pointed
|
||||
to by |kind|.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
!pthread_mutexattr_init!, !pthread_mutexattr_destroy! and
|
||||
!pthread_mutexattr_gettype! always return 0.
|
||||
|
||||
!pthread_mutexattr_settype! returns 0 on success and a non-zero
|
||||
error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
On error, !pthread_mutexattr_settype! returns the following error code:
|
||||
.TP
|
||||
!EINVAL!
|
||||
|kind| is neither !PTHREAD_MUTEX_FAST_NP! nor !PTHREAD_MUTEX_RECURSIVE_NP!
|
||||
nor !PTHREAD_MUTEX_ERRORCHECK_NP!
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_mutex_init!(3),
|
||||
!pthread_mutex_lock!(3),
|
||||
!pthread_mutex_unlock!(3).
|
@ -1,39 +0,0 @@
|
||||
.TH PTHREAD_MUTEXATTR_SETKIND_NP 3 LinuxThreads
|
||||
|
||||
.XREF pthread_mutexattr_getkind_np
|
||||
|
||||
.SH NAME
|
||||
pthread_mutexattr_setkind_np, pthread_mutexattr_getkind_np \- deprecated mutex creation attributes
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind);
|
||||
|
||||
int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *kind);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
These functions are deprecated, use !pthread_mutexattr_settype!(3p)
|
||||
and !pthread_mutexattr_gettype!(3p) instead.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
!pthread_mutexattr_getkind_np! always returns 0.
|
||||
|
||||
!pthread_mutexattr_setkind_np! returns 0 on success and a non-zero
|
||||
error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
On error, !pthread_mutexattr_setkind_np! returns the following error code:
|
||||
.TP
|
||||
!EINVAL!
|
||||
|kind| is neither !PTHREAD_MUTEX_FAST_NP! nor !PTHREAD_MUTEX_RECURSIVE_NP!
|
||||
nor !PTHREAD_MUTEX_ERRORCHECK_NP!
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_mutexattr_settype!(3p),
|
||||
!pthread_mutexattr_gettype!(3p).
|
@ -1,34 +0,0 @@
|
||||
.TH PTHREAD_ONCE 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_once \- once-only initialization
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
|
||||
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
The purpose of !pthread_once! is to ensure that a piece of
|
||||
initialization code is executed at most once. The |once_control|
|
||||
argument points to a static or extern variable statically initialized
|
||||
to !PTHREAD_ONCE_INIT!.
|
||||
|
||||
The first time !pthread_once! is called with a given |once_control|
|
||||
argument, it calls |init_routine| with no argument and changes the
|
||||
value of the |once_control| variable to record that initialization has
|
||||
been performed. Subsequent calls to !pthread_once! with the same
|
||||
!once_control! argument do nothing.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
!pthread_once! always returns 0.
|
||||
|
||||
.SH ERRORS
|
||||
None.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
@ -1,23 +0,0 @@
|
||||
.TH PTHREAD_SELF 3 LinuxThreads
|
||||
|
||||
.SH NAME
|
||||
pthread_self \- return identifier of current thread
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_t pthread_self(void);
|
||||
|
||||
.SH DESCRIPTION
|
||||
!pthread_self! return the thread identifier for the calling thread.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_equal!(3),
|
||||
!pthread_join!(3),
|
||||
!pthread_detach!(3),
|
||||
!pthread_setschedparam!(3),
|
||||
!pthread_getschedparam!(3).
|
||||
|
@ -1,79 +0,0 @@
|
||||
.TH PTHREAD_SETSCHEDPARAM 3 LinuxThreads
|
||||
|
||||
.XREF pthread_getschedparam
|
||||
|
||||
.SH NAME
|
||||
pthread_setschedparam, pthread_getschedparam \- control thread scheduling parameters
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
|
||||
int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param);
|
||||
|
||||
int pthread_getschedparam(pthread_t target_thread, int *policy, struct sched_param *param);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
!pthread_setschedparam! sets the scheduling parameters for the thread
|
||||
|target_thread| as indicated by |policy| and |param|. |policy| can be
|
||||
either !SCHED_OTHER! (regular, non-realtime scheduling), !SCHED_RR!
|
||||
(realtime, round-robin) or !SCHED_FIFO! (realtime, first-in
|
||||
first-out). |param| specifies the scheduling priority for the two
|
||||
realtime policies. See !sched_setpolicy!(2) for more information on
|
||||
scheduling policies.
|
||||
|
||||
The realtime scheduling policies !SCHED_RR! and !SCHED_FIFO! are
|
||||
available only to processes with superuser privileges.
|
||||
|
||||
!pthread_getschedparam! retrieves the scheduling policy and scheduling
|
||||
parameters for the thread |target_thread| and store them in the
|
||||
locations pointed to by |policy| and |param|, respectively.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
!pthread_setschedparam! and !pthread_getschedparam! return 0 on
|
||||
success and a non-zero error code on error.
|
||||
|
||||
.SH ERRORS
|
||||
On error, !pthread_setschedparam! returns the following error codes:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
|policy| is not one of !SCHED_OTHER!, !SCHED_RR!, !SCHED_FIFO!
|
||||
|
||||
.TP
|
||||
!EINVAL!
|
||||
the priority value specified by |param| is not valid for the specified policy
|
||||
|
||||
.TP
|
||||
!EPERM!
|
||||
the calling process does not have superuser permissions
|
||||
|
||||
.TP
|
||||
!ESRCH!
|
||||
the |target_thread| is invalid or has already terminated
|
||||
|
||||
.TP
|
||||
!EFAULT!
|
||||
|param| points outside the process memory space
|
||||
.RE
|
||||
|
||||
On error, !pthread_getschedparam! returns the following error codes:
|
||||
.RS
|
||||
.TP
|
||||
!ESRCH!
|
||||
the |target_thread| is invalid or has already terminated
|
||||
|
||||
.TP
|
||||
!EFAULT!
|
||||
|policy| or |param| point outside the process memory space
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!sched_setscheduler!(2),
|
||||
!sched_getscheduler!(2),
|
||||
!sched_getparam!(2),
|
||||
!pthread_attr_setschedpolicy!(3),
|
||||
!pthread_attr_setschedparam!(3).
|
@ -1,123 +0,0 @@
|
||||
.TH PTHREAD_SIGNAL 3 LinuxThreads
|
||||
|
||||
.XREF pthread_kill
|
||||
.XREF sigwait
|
||||
|
||||
.SH NAME
|
||||
pthread_sigmask, pthread_kill, sigwait \- handling of signals in threads
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <pthread.h>
|
||||
.br
|
||||
#include <signal.h>
|
||||
|
||||
int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask);
|
||||
|
||||
int pthread_kill(pthread_t thread, int signo);
|
||||
|
||||
int sigwait(const sigset_t *set, int *sig);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
!pthread_sigmask! changes the signal mask for the calling thread as
|
||||
described by the |how| and |newmask| arguments. If |oldmask| is not
|
||||
!NULL!, the previous signal mask is stored in the location pointed to
|
||||
by |oldmask|.
|
||||
|
||||
The meaning of the |how| and |newmask| arguments is the same as for
|
||||
!sigprocmask!(2). If |how| is !SIG_SETMASK!, the signal mask is set to
|
||||
|newmask|. If |how| is !SIG_BLOCK!, the signals specified to |newmask|
|
||||
are added to the current signal mask. If |how| is !SIG_UNBLOCK!, the
|
||||
signals specified to |newmask| are removed from the current signal
|
||||
mask.
|
||||
|
||||
Recall that signal masks are set on a per-thread basis, but signal
|
||||
actions and signal handlers, as set with !sigaction!(2), are shared
|
||||
between all threads.
|
||||
|
||||
!pthread_kill! send signal number |signo| to the thread
|
||||
|thread|. The signal is delivered and handled as described in
|
||||
!kill!(2).
|
||||
|
||||
!sigwait! suspends the calling thread until one of the signals
|
||||
in |set| is delivered to the calling thread. It then stores the number
|
||||
of the signal received in the location pointed to by |sig| and
|
||||
returns. The signals in |set| must be blocked and not ignored on
|
||||
entrance to !sigwait!. If the delivered signal has a signal handler
|
||||
function attached, that function is |not| called.
|
||||
|
||||
.SH CANCELLATION
|
||||
|
||||
!sigwait! is a cancellation point.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
On success, 0 is returned. On failure, a non-zero error code is returned.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
The !pthread_sigmask! function returns the following error codes
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
|how| is not one of !SIG_SETMASK!, !SIG_BLOCK!, or !SIG_UNBLOCK!
|
||||
|
||||
.TP
|
||||
!EFAULT!
|
||||
|newmask| or |oldmask| point to invalid addresses
|
||||
.RE
|
||||
|
||||
The !pthread_kill! function returns the following error codes
|
||||
on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
|signo| is not a valid signal number
|
||||
|
||||
.TP
|
||||
!ESRCH!
|
||||
the thread |thread| does not exist (e.g. it has already terminated)
|
||||
.RE
|
||||
|
||||
The !sigwait! function never returns an error.
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!sigprocmask!(2),
|
||||
!kill!(2),
|
||||
!sigaction!(2),
|
||||
!sigsuspend!(2).
|
||||
|
||||
.SH NOTES
|
||||
|
||||
For !sigwait! to work reliably, the signals being waited for must be
|
||||
blocked in all threads, not only in the calling thread, since
|
||||
otherwise the POSIX semantics for signal delivery do not guarantee
|
||||
that it's the thread doing the !sigwait! that will receive the signal.
|
||||
The best way to achieve this is block those signals before any threads
|
||||
are created, and never unblock them in the program other than by
|
||||
calling !sigwait!.
|
||||
|
||||
.SH BUGS
|
||||
|
||||
Signal handling in LinuxThreads departs significantly from the POSIX
|
||||
standard. According to the standard, ``asynchronous'' (external)
|
||||
signals are addressed to the whole process (the collection of all
|
||||
threads), which then delivers them to one particular thread. The
|
||||
thread that actually receives the signal is any thread that does
|
||||
not currently block the signal.
|
||||
|
||||
In LinuxThreads, each thread is actually a kernel process with its own
|
||||
PID, so external signals are always directed to one particular thread.
|
||||
If, for instance, another thread is blocked in !sigwait! on that
|
||||
signal, it will not be restarted.
|
||||
|
||||
The LinuxThreads implementation of !sigwait! installs dummy signal
|
||||
handlers for the signals in |set| for the duration of the wait. Since
|
||||
signal handlers are shared between all threads, other threads must not
|
||||
attach their own signal handlers to these signals, or alternatively
|
||||
they should all block these signals (which is recommended anyway --
|
||||
see the Notes section).
|
@ -1,132 +0,0 @@
|
||||
.TH SEMAPHORES 3 LinuxThreads
|
||||
|
||||
.XREF sem_wait
|
||||
.XREF sem_trywait
|
||||
.XREF sem_post
|
||||
.XREF sem_getvalue
|
||||
.XREF sem_destroy
|
||||
|
||||
.SH NAME
|
||||
sem_init, sem_wait, sem_trywait, sem_post, sem_getvalue, sem_destroy \- operations on semaphores
|
||||
|
||||
.SH SYNOPSIS
|
||||
#include <semaphore.h>
|
||||
|
||||
int sem_init(sem_t *sem, int pshared, unsigned int value);
|
||||
|
||||
int sem_wait(sem_t * sem);
|
||||
|
||||
int sem_trywait(sem_t * sem);
|
||||
|
||||
int sem_post(sem_t * sem);
|
||||
|
||||
int sem_getvalue(sem_t * sem, int * sval);
|
||||
|
||||
int sem_destroy(sem_t * sem);
|
||||
|
||||
.SH DESCRIPTION
|
||||
This manual page documents POSIX 1003.1b semaphores, not to be
|
||||
confused with SystemV semaphores as described in !ipc!(5), !semctl!(2)
|
||||
and !semop!(2).
|
||||
|
||||
Semaphores are counters for resources shared between threads. The
|
||||
basic operations on semaphores are: increment the counter atomically,
|
||||
and wait until the counter is non-null and decrement it atomically.
|
||||
|
||||
!sem_init! initializes the semaphore object pointed to by |sem|. The
|
||||
count associated with the semaphore is set initially to |value|. The
|
||||
|pshared| argument indicates whether the semaphore is local to the
|
||||
current process (|pshared| is zero) or is to be shared between several
|
||||
processes (|pshared| is not zero). LinuxThreads currently does not
|
||||
support process-shared semaphores, thus !sem_init! always returns with
|
||||
error !ENOSYS! if |pshared| is not zero.
|
||||
|
||||
!sem_wait! suspends the calling thread until the semaphore pointed to
|
||||
by |sem| has non-zero count. It then atomically decreases the
|
||||
semaphore count.
|
||||
|
||||
!sem_trywait! is a non-blocking variant of !sem_wait!. If the
|
||||
semaphore pointed to by |sem| has non-zero count, the count is
|
||||
atomically decreased and !sem_trywait! immediately returns 0.
|
||||
If the semaphore count is zero, !sem_trywait! immediately returns with
|
||||
error !EAGAIN!.
|
||||
|
||||
!sem_post! atomically increases the count of the semaphore pointed to
|
||||
by |sem|. This function never blocks and can safely be used in
|
||||
asynchronous signal handlers.
|
||||
|
||||
!sem_getvalue! stores in the location pointed to by |sval| the current
|
||||
count of the semaphore |sem|.
|
||||
|
||||
!sem_destroy! destroys a semaphore object, freeing the resources it
|
||||
might hold. No threads should be waiting on the semaphore at the time
|
||||
!sem_destroy! is called. In the LinuxThreads implementation, no
|
||||
resources are associated with semaphore objects, thus !sem_destroy!
|
||||
actually does nothing except checking that no thread is waiting on the
|
||||
semaphore.
|
||||
|
||||
.SH CANCELLATION
|
||||
|
||||
!sem_wait! is a cancellation point.
|
||||
|
||||
.SH "ASYNC-SIGNAL SAFETY"
|
||||
|
||||
On processors supporting atomic compare-and-swap (Intel 486, Pentium
|
||||
and later, Alpha, PowerPC, MIPS II, Motorola 68k), the !sem_post!
|
||||
function is async-signal safe and can therefore be
|
||||
called from signal handlers. This is the only thread synchronization
|
||||
function provided by POSIX threads that is async-signal safe.
|
||||
|
||||
On the Intel 386 and the Sparc, the current LinuxThreads
|
||||
implementation of !sem_post! is not async-signal safe by lack of the
|
||||
required atomic operations.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
|
||||
The !sem_wait! and !sem_getvalue! functions always return 0.
|
||||
All other semaphore functions return 0 on success and -1 on error, in
|
||||
addition to writing an error code in !errno!.
|
||||
|
||||
.SH ERRORS
|
||||
|
||||
The !sem_init! function sets !errno! to the following codes on error:
|
||||
.RS
|
||||
.TP
|
||||
!EINVAL!
|
||||
|value| exceeds the maximal counter value !SEM_VALUE_MAX!
|
||||
.TP
|
||||
!ENOSYS!
|
||||
|pshared| is not zero
|
||||
.RE
|
||||
|
||||
The !sem_trywait! function sets !errno! to the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EAGAIN!
|
||||
the semaphore count is currently 0
|
||||
.RE
|
||||
|
||||
The !sem_post! function sets !errno! to the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!ERANGE!
|
||||
after incrementation, the semaphore value would exceed !SEM_VALUE_MAX!
|
||||
(the semaphore count is left unchanged in this case)
|
||||
.RE
|
||||
|
||||
The !sem_destroy! function sets !errno! to the following error code on error:
|
||||
.RS
|
||||
.TP
|
||||
!EBUSY!
|
||||
some threads are currently blocked waiting on the semaphore.
|
||||
.RE
|
||||
|
||||
.SH AUTHOR
|
||||
Xavier Leroy <Xavier.Leroy@inria.fr>
|
||||
|
||||
.SH "SEE ALSO"
|
||||
!pthread_mutex_init!(3),
|
||||
!pthread_cond_init!(3),
|
||||
!pthread_cancel!(3),
|
||||
!ipc!(5).
|
||||
|
@ -1,68 +0,0 @@
|
||||
#!/usr/local/bin/perl
|
||||
|
||||
$insynopsis = 0;
|
||||
|
||||
open(INPUT, $ARGV[0]) || die("cannot open $ARGV[0]");
|
||||
open(OUTPUT, "> $ARGV[1]") || die("cannot create $ARGV[1]");
|
||||
|
||||
select(OUTPUT);
|
||||
|
||||
line:
|
||||
while(<INPUT>) {
|
||||
if (/^\.XREF (.*)$/) {
|
||||
$xref = $1;
|
||||
$_ = $ARGV[1];
|
||||
m/^.*\.(([1-8]).*)$/;
|
||||
$suffix = $1;
|
||||
$extension = $2;
|
||||
open(XREF, "> $xref.$suffix");
|
||||
print XREF ".so man$extension/$ARGV[1]\n";
|
||||
close(XREF);
|
||||
next line;
|
||||
}
|
||||
if (/^\.SH/) {
|
||||
$insynopsis = /SYNOPSIS/;
|
||||
print $_;
|
||||
next;
|
||||
}
|
||||
if ($insynopsis) {
|
||||
if (/^#/) {
|
||||
print ".B ", $_;
|
||||
}
|
||||
elsif (/^[a-z]/) {
|
||||
chop;
|
||||
# if (m/^([a-zA-Z][a-zA-Z0-9_]*\s+[a-zA-Z][a-zA-Z0-9_]*)\(/) {
|
||||
# print ".B \"", $1, "\"\n";
|
||||
# $_ = '(' . $';
|
||||
# }
|
||||
# s/([a-zA-Z][a-zA-Z0-9_]*)(\s*[,()=])/" \1 "\2/g;
|
||||
s/([ *])([a-zA-Z][a-zA-Z0-9_]*)(\s*[,)=])/\1" \2 "\3/g;
|
||||
print ".BI \"", $_, "\"\n";
|
||||
}
|
||||
else {
|
||||
print $_;
|
||||
}
|
||||
next;
|
||||
}
|
||||
chop;
|
||||
s/!([^!]+)!\|([^|]+)\|([^\s]*)\s*/\n.BI "\1" "\2\3"\n/g;
|
||||
s/([!|])([^!|]+)\1([^\s]*)\s*/do subst($1,$2,$3)/eg;
|
||||
s/^\n+//;
|
||||
s/\n+$//;
|
||||
s/\n\n+/\n/g;
|
||||
print $_, "\n";
|
||||
}
|
||||
|
||||
close(INPUT);
|
||||
close(OUTPUT);
|
||||
|
||||
sub subst {
|
||||
local ($a, $b, $c) = @_;
|
||||
if ($c) {
|
||||
"\n" . ($a eq "!" ? ".BR " : ".IR ") . "\"$b\" $c\n"
|
||||
} else {
|
||||
"\n" . ($a eq "!" ? ".B " : ".I ") . "\"$b\"\n"
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,362 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Mutexes */
|
||||
|
||||
#include <bits/libc-lock.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "queue.h"
|
||||
#include "restart.h"
|
||||
|
||||
int __pthread_mutex_init(pthread_mutex_t * mutex,
|
||||
const pthread_mutexattr_t * mutex_attr)
|
||||
{
|
||||
__pthread_init_lock(&mutex->__m_lock);
|
||||
mutex->__m_kind =
|
||||
mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind;
|
||||
mutex->__m_count = 0;
|
||||
mutex->__m_owner = NULL;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_mutex_init, pthread_mutex_init)
|
||||
hidden_def (__pthread_mutex_init)
|
||||
|
||||
int __pthread_mutex_destroy(pthread_mutex_t * mutex)
|
||||
{
|
||||
switch (mutex->__m_kind) {
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
case PTHREAD_MUTEX_RECURSIVE_NP:
|
||||
if ((mutex->__m_lock.__status & 1) != 0)
|
||||
return EBUSY;
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
case PTHREAD_MUTEX_TIMED_NP:
|
||||
if (mutex->__m_lock.__status != 0)
|
||||
return EBUSY;
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
|
||||
hidden_def (__pthread_mutex_destroy)
|
||||
|
||||
int __pthread_mutex_trylock(pthread_mutex_t * mutex)
|
||||
{
|
||||
pthread_descr self;
|
||||
int retcode;
|
||||
|
||||
switch(mutex->__m_kind) {
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
retcode = __pthread_trylock(&mutex->__m_lock);
|
||||
return retcode;
|
||||
case PTHREAD_MUTEX_RECURSIVE_NP:
|
||||
self = thread_self();
|
||||
if (mutex->__m_owner == self) {
|
||||
mutex->__m_count++;
|
||||
return 0;
|
||||
}
|
||||
retcode = __pthread_trylock(&mutex->__m_lock);
|
||||
if (retcode == 0) {
|
||||
mutex->__m_owner = self;
|
||||
mutex->__m_count = 0;
|
||||
}
|
||||
return retcode;
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
retcode = __pthread_alt_trylock(&mutex->__m_lock);
|
||||
if (retcode == 0) {
|
||||
mutex->__m_owner = thread_self();
|
||||
}
|
||||
return retcode;
|
||||
case PTHREAD_MUTEX_TIMED_NP:
|
||||
retcode = __pthread_alt_trylock(&mutex->__m_lock);
|
||||
return retcode;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
|
||||
hidden_def (__pthread_mutex_trylock)
|
||||
|
||||
int __pthread_mutex_lock(pthread_mutex_t * mutex)
|
||||
{
|
||||
pthread_descr self;
|
||||
|
||||
switch(mutex->__m_kind) {
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
__pthread_lock(&mutex->__m_lock, NULL);
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_RECURSIVE_NP:
|
||||
self = thread_self();
|
||||
if (mutex->__m_owner == self) {
|
||||
mutex->__m_count++;
|
||||
return 0;
|
||||
}
|
||||
__pthread_lock(&mutex->__m_lock, self);
|
||||
mutex->__m_owner = self;
|
||||
mutex->__m_count = 0;
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
self = thread_self();
|
||||
if (mutex->__m_owner == self) return EDEADLK;
|
||||
__pthread_alt_lock(&mutex->__m_lock, self);
|
||||
mutex->__m_owner = self;
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_TIMED_NP:
|
||||
__pthread_alt_lock(&mutex->__m_lock, NULL);
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
|
||||
hidden_def (__pthread_mutex_lock)
|
||||
|
||||
int __pthread_mutex_timedlock (pthread_mutex_t *mutex,
|
||||
const struct timespec *abstime)
|
||||
{
|
||||
pthread_descr self;
|
||||
int res;
|
||||
|
||||
if (__builtin_expect (abstime->tv_nsec, 0) < 0
|
||||
|| __builtin_expect (abstime->tv_nsec, 0) >= 1000000000)
|
||||
return EINVAL;
|
||||
|
||||
switch(mutex->__m_kind) {
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
__pthread_lock(&mutex->__m_lock, NULL);
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_RECURSIVE_NP:
|
||||
self = thread_self();
|
||||
if (mutex->__m_owner == self) {
|
||||
mutex->__m_count++;
|
||||
return 0;
|
||||
}
|
||||
__pthread_lock(&mutex->__m_lock, self);
|
||||
mutex->__m_owner = self;
|
||||
mutex->__m_count = 0;
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
self = thread_self();
|
||||
if (mutex->__m_owner == self) return EDEADLK;
|
||||
res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime);
|
||||
if (res != 0)
|
||||
{
|
||||
mutex->__m_owner = self;
|
||||
return 0;
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
case PTHREAD_MUTEX_TIMED_NP:
|
||||
/* Only this type supports timed out lock. */
|
||||
return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime)
|
||||
? 0 : ETIMEDOUT);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock)
|
||||
|
||||
int __pthread_mutex_unlock(pthread_mutex_t * mutex)
|
||||
{
|
||||
switch (mutex->__m_kind) {
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
__pthread_unlock(&mutex->__m_lock);
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_RECURSIVE_NP:
|
||||
if (mutex->__m_owner != thread_self())
|
||||
return EPERM;
|
||||
if (mutex->__m_count > 0) {
|
||||
mutex->__m_count--;
|
||||
return 0;
|
||||
}
|
||||
mutex->__m_owner = NULL;
|
||||
__pthread_unlock(&mutex->__m_lock);
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0)
|
||||
return EPERM;
|
||||
mutex->__m_owner = NULL;
|
||||
__pthread_alt_unlock(&mutex->__m_lock);
|
||||
return 0;
|
||||
case PTHREAD_MUTEX_TIMED_NP:
|
||||
__pthread_alt_unlock(&mutex->__m_lock);
|
||||
return 0;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
|
||||
hidden_def (__pthread_mutex_unlock)
|
||||
|
||||
int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
|
||||
{
|
||||
attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP;
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
|
||||
|
||||
int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
|
||||
|
||||
int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
|
||||
{
|
||||
if (kind != PTHREAD_MUTEX_ADAPTIVE_NP
|
||||
&& kind != PTHREAD_MUTEX_RECURSIVE_NP
|
||||
&& kind != PTHREAD_MUTEX_ERRORCHECK_NP
|
||||
&& kind != PTHREAD_MUTEX_TIMED_NP)
|
||||
return EINVAL;
|
||||
attr->__mutexkind = kind;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
|
||||
strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
|
||||
weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
|
||||
|
||||
int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind)
|
||||
{
|
||||
*kind = attr->__mutexkind;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype)
|
||||
strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np)
|
||||
weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np)
|
||||
|
||||
int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
|
||||
int *pshared)
|
||||
{
|
||||
*pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_mutexattr_getpshared, pthread_mutexattr_getpshared)
|
||||
|
||||
int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
|
||||
{
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
|
||||
return EINVAL;
|
||||
|
||||
/* For now it is not possible to shared a conditional variable. */
|
||||
if (pshared != PTHREAD_PROCESS_PRIVATE)
|
||||
return ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
|
||||
|
||||
/* Once-only execution */
|
||||
|
||||
static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER;
|
||||
static int fork_generation = 0; /* Child process increments this after fork. */
|
||||
|
||||
enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 };
|
||||
|
||||
/* If a thread is canceled while calling the init_routine out of
|
||||
pthread once, this handler will reset the once_control variable
|
||||
to the NEVER state. */
|
||||
|
||||
static void pthread_once_cancelhandler(void *arg)
|
||||
{
|
||||
pthread_once_t *once_control = arg;
|
||||
|
||||
pthread_mutex_lock(&once_masterlock);
|
||||
*once_control = NEVER;
|
||||
pthread_mutex_unlock(&once_masterlock);
|
||||
pthread_cond_broadcast(&once_finished);
|
||||
}
|
||||
|
||||
int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void))
|
||||
{
|
||||
/* flag for doing the condition broadcast outside of mutex */
|
||||
int state_changed;
|
||||
|
||||
/* Test without locking first for speed */
|
||||
if (*once_control == DONE) {
|
||||
READ_MEMORY_BARRIER();
|
||||
return 0;
|
||||
}
|
||||
/* Lock and test again */
|
||||
|
||||
state_changed = 0;
|
||||
|
||||
pthread_mutex_lock(&once_masterlock);
|
||||
|
||||
/* If this object was left in an IN_PROGRESS state in a parent
|
||||
process (indicated by stale generation field), reset it to NEVER. */
|
||||
if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation)
|
||||
*once_control = NEVER;
|
||||
|
||||
/* If init_routine is being called from another routine, wait until
|
||||
it completes. */
|
||||
while ((*once_control & 3) == IN_PROGRESS) {
|
||||
pthread_cond_wait(&once_finished, &once_masterlock);
|
||||
}
|
||||
/* Here *once_control is stable and either NEVER or DONE. */
|
||||
if (*once_control == NEVER) {
|
||||
*once_control = IN_PROGRESS | fork_generation;
|
||||
pthread_mutex_unlock(&once_masterlock);
|
||||
pthread_cleanup_push(pthread_once_cancelhandler, once_control);
|
||||
init_routine();
|
||||
pthread_cleanup_pop(0);
|
||||
pthread_mutex_lock(&once_masterlock);
|
||||
WRITE_MEMORY_BARRIER();
|
||||
*once_control = DONE;
|
||||
state_changed = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&once_masterlock);
|
||||
|
||||
if (state_changed)
|
||||
pthread_cond_broadcast(&once_finished);
|
||||
|
||||
return 0;
|
||||
}
|
||||
strong_alias (__pthread_once, pthread_once)
|
||||
|
||||
/*
|
||||
* Handle the state of the pthread_once mechanism across forks. The
|
||||
* once_masterlock is acquired in the parent process prior to a fork to ensure
|
||||
* that no thread is in the critical region protected by the lock. After the
|
||||
* fork, the lock is released. In the child, the lock and the condition
|
||||
* variable are simply reset. The child also increments its generation
|
||||
* counter which lets pthread_once calls detect stale IN_PROGRESS states
|
||||
* and reset them back to NEVER.
|
||||
*/
|
||||
|
||||
void __pthread_once_fork_prepare(void)
|
||||
{
|
||||
pthread_mutex_lock(&once_masterlock);
|
||||
}
|
||||
|
||||
void __pthread_once_fork_parent(void)
|
||||
{
|
||||
pthread_mutex_unlock(&once_masterlock);
|
||||
}
|
||||
|
||||
void __pthread_once_fork_child(void)
|
||||
{
|
||||
pthread_mutex_init(&once_masterlock, NULL);
|
||||
pthread_cond_init(&once_finished, NULL);
|
||||
if (fork_generation <= INT_MAX - 4)
|
||||
fork_generation += 4; /* leave least significant two bits zero */
|
||||
else
|
||||
fork_generation = 0;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/* 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 <shlib-compat.h>
|
||||
|
||||
#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_3)
|
||||
# define __pthread_atfork __dyn_pthread_atfork
|
||||
# include "pthread_atfork.c"
|
||||
# undef __pthread_atfork
|
||||
compat_symbol (libpthread, __dyn_pthread_atfork, pthread_atfork, GLIBC_2_0);
|
||||
#endif
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
* This file contains the old semaphore code that we need to
|
||||
* preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1
|
||||
* done by Cristian Gafton.
|
||||
*/
|
||||
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Semaphores a la POSIX 1003.1b */
|
||||
#include <shlib-compat.h>
|
||||
#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
|
||||
|
||||
#include <errno.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
#include "spinlock.h"
|
||||
#include "restart.h"
|
||||
#include "queue.h"
|
||||
|
||||
typedef struct {
|
||||
long int sem_status;
|
||||
int sem_spinlock;
|
||||
} old_sem_t;
|
||||
|
||||
extern int __old_sem_init (old_sem_t *__sem, int __pshared, unsigned int __value);
|
||||
extern int __old_sem_wait (old_sem_t *__sem);
|
||||
extern int __old_sem_trywait (old_sem_t *__sem);
|
||||
extern int __old_sem_post (old_sem_t *__sem);
|
||||
extern int __old_sem_getvalue (old_sem_t *__sem, int *__sval);
|
||||
extern int __old_sem_destroy (old_sem_t *__sem);
|
||||
|
||||
static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval)
|
||||
{
|
||||
return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock);
|
||||
}
|
||||
|
||||
/* The state of a semaphore is represented by a long int encoding
|
||||
either the semaphore count if >= 0 and no thread is waiting on it,
|
||||
or the head of the list of threads waiting for the semaphore.
|
||||
To distinguish the two cases, we encode the semaphore count N
|
||||
as 2N+1, so that it has the lowest bit set.
|
||||
|
||||
A sequence of sem_wait operations on a semaphore initialized to N
|
||||
result in the following successive states:
|
||||
2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ...
|
||||
*/
|
||||
|
||||
static void sem_restart_list(pthread_descr waiting);
|
||||
|
||||
int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value)
|
||||
{
|
||||
if (value > SEM_VALUE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (pshared) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
sem->sem_spinlock = __LT_SPINLOCK_INIT;
|
||||
sem->sem_status = ((long)value << 1) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function called by pthread_cancel to remove the thread from
|
||||
waiting inside __old_sem_wait. Here we simply unconditionally
|
||||
indicate that the thread is to be woken, by returning 1. */
|
||||
|
||||
static int old_sem_extricate_func(void *obj, pthread_descr th)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __old_sem_wait(old_sem_t * sem)
|
||||
{
|
||||
long oldstatus, newstatus;
|
||||
volatile pthread_descr self = thread_self();
|
||||
pthread_descr * th;
|
||||
pthread_extricate_if extr;
|
||||
|
||||
/* Set up extrication interface */
|
||||
extr.pu_object = 0;
|
||||
extr.pu_extricate_func = old_sem_extricate_func;
|
||||
|
||||
while (1) {
|
||||
/* Register extrication interface */
|
||||
__pthread_set_own_extricate_if(self, &extr);
|
||||
do {
|
||||
oldstatus = sem->sem_status;
|
||||
if ((oldstatus & 1) && (oldstatus != 1))
|
||||
newstatus = oldstatus - 2;
|
||||
else {
|
||||
newstatus = (long) self;
|
||||
self->p_nextwaiting = (pthread_descr) oldstatus;
|
||||
}
|
||||
}
|
||||
while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
||||
if (newstatus & 1) {
|
||||
/* We got the semaphore. */
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
self->p_nextwaiting = NULL;
|
||||
return 0;
|
||||
}
|
||||
/* Wait for sem_post or cancellation */
|
||||
suspend(self);
|
||||
__pthread_set_own_extricate_if(self, 0);
|
||||
|
||||
/* This is a cancellation point */
|
||||
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
|
||||
/* Remove ourselves from the waiting list if we're still on it */
|
||||
/* First check if we're at the head of the list. */
|
||||
do {
|
||||
oldstatus = sem->sem_status;
|
||||
if (oldstatus != (long) self) break;
|
||||
newstatus = (long) self->p_nextwaiting;
|
||||
}
|
||||
while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
||||
/* Now, check if we're somewhere in the list.
|
||||
There's a race condition with sem_post here, but it does not matter:
|
||||
the net result is that at the time pthread_exit is called,
|
||||
self is no longer reachable from sem->sem_status. */
|
||||
if (oldstatus != (long) self && (oldstatus & 1) == 0) {
|
||||
for (th = &(((pthread_descr) oldstatus)->p_nextwaiting);
|
||||
*th != NULL && *th != (pthread_descr) 1;
|
||||
th = &((*th)->p_nextwaiting)) {
|
||||
if (*th == self) {
|
||||
*th = self->p_nextwaiting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
__pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __old_sem_trywait(old_sem_t * sem)
|
||||
{
|
||||
long oldstatus, newstatus;
|
||||
|
||||
do {
|
||||
oldstatus = sem->sem_status;
|
||||
if ((oldstatus & 1) == 0 || (oldstatus == 1)) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
newstatus = oldstatus - 2;
|
||||
}
|
||||
while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __old_sem_post(old_sem_t * sem)
|
||||
{
|
||||
long oldstatus, newstatus;
|
||||
|
||||
do {
|
||||
oldstatus = sem->sem_status;
|
||||
if ((oldstatus & 1) == 0)
|
||||
newstatus = 3;
|
||||
else {
|
||||
if (oldstatus >= SEM_VALUE_MAX) {
|
||||
/* Overflow */
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
newstatus = oldstatus + 2;
|
||||
}
|
||||
}
|
||||
while (! sem_compare_and_swap(sem, oldstatus, newstatus));
|
||||
if ((oldstatus & 1) == 0)
|
||||
sem_restart_list((pthread_descr) oldstatus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __old_sem_getvalue(old_sem_t * sem, int * sval)
|
||||
{
|
||||
long status = sem->sem_status;
|
||||
if (status & 1)
|
||||
*sval = (int)((unsigned long) status >> 1);
|
||||
else
|
||||
*sval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __old_sem_destroy(old_sem_t * sem)
|
||||
{
|
||||
if ((sem->sem_status & 1) == 0) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Auxiliary function for restarting all threads on a waiting list,
|
||||
in priority order. */
|
||||
|
||||
static void sem_restart_list(pthread_descr waiting)
|
||||
{
|
||||
pthread_descr th, towake, *p;
|
||||
|
||||
/* Sort list of waiting threads by decreasing priority (insertion sort) */
|
||||
towake = NULL;
|
||||
while (waiting != (pthread_descr) 1) {
|
||||
th = waiting;
|
||||
waiting = waiting->p_nextwaiting;
|
||||
p = &towake;
|
||||
while (*p != NULL && th->p_priority < (*p)->p_priority)
|
||||
p = &((*p)->p_nextwaiting);
|
||||
th->p_nextwaiting = *p;
|
||||
*p = th;
|
||||
}
|
||||
/* Wake up threads in priority order */
|
||||
while (towake != NULL) {
|
||||
th = towake;
|
||||
towake = towake->p_nextwaiting;
|
||||
th->p_nextwaiting = NULL;
|
||||
restart(th);
|
||||
}
|
||||
}
|
||||
|
||||
compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
|
||||
compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
|
||||
compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0);
|
||||
compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
|
||||
compat_symbol (libpthread, __old_sem_getvalue, sem_getvalue, GLIBC_2_0);
|
||||
compat_symbol (libpthread, __old_sem_destroy, sem_destroy, GLIBC_2_0);
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
/* 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 <signal.h>
|
||||
|
||||
|
||||
/* These are defined in libc. We want to have only one definition
|
||||
so we "forward" the calls. */
|
||||
extern int __libc_current_sigrtmin_private (void);
|
||||
extern int __libc_current_sigrtmax_private (void);
|
||||
extern int __libc_allocate_rtsig_private (int high);
|
||||
|
||||
|
||||
/* We reserve __SIGRTMIN for use as the cancelation signal. This
|
||||
signal is used internally. */
|
||||
int
|
||||
__libc_current_sigrtmin (void)
|
||||
{
|
||||
return __libc_current_sigrtmin_private ();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__libc_current_sigrtmax (void)
|
||||
{
|
||||
return __libc_current_sigrtmax_private ();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__libc_allocate_rtsig (int high)
|
||||
{
|
||||
return __libc_allocate_rtsig_private (high);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/* "Instantiation of machine-dependent pthreads inline functions.
|
||||
Copyright (C) 1998 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. */
|
||||
|
||||
#define PT_EI
|
||||
|
||||
extern long int testandset (int *spinlock);
|
||||
extern int __compare_and_swap (long int *p, long int oldval, long int newval);
|
||||
|
||||
#include <pt-machine.h>
|
@ -1,32 +0,0 @@
|
||||
/* 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 <stdlib.h>
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
|
||||
int
|
||||
system (const char *line)
|
||||
{
|
||||
return __libc_system (line);
|
||||
}
|
||||
|
||||
/* __libc_system in libc.so handles cancellation. */
|
||||
LIBC_CANCEL_HANDLED ();
|
@ -1,52 +0,0 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1998, 2004 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/* Redefine siglongjmp and longjmp so that they interact correctly
|
||||
with cleanup handlers */
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "pthread.h"
|
||||
#include "internals.h"
|
||||
|
||||
void __pthread_cleanup_upto (__jmp_buf target, char *targetframe)
|
||||
{
|
||||
pthread_descr self = thread_self();
|
||||
struct _pthread_cleanup_buffer * c;
|
||||
|
||||
for (c = THREAD_GETMEM(self, p_cleanup);
|
||||
c != NULL && _JMPBUF_UNWINDS(target, c);
|
||||
c = c->__prev)
|
||||
{
|
||||
#if _STACK_GROWS_DOWN
|
||||
if ((char *) c <= targetframe)
|
||||
{
|
||||
c = NULL;
|
||||
break;
|
||||
}
|
||||
#elif _STACK_GROWS_UP
|
||||
if ((char *) c >= targetframe)
|
||||
{
|
||||
c = NULL;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
|
||||
#endif
|
||||
c->__routine(c->__arg);
|
||||
}
|
||||
THREAD_SETMEM(self, p_cleanup, c);
|
||||
if (THREAD_GETMEM(self, p_in_sighandler)
|
||||
&& _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler)))
|
||||
THREAD_SETMEM(self, p_in_sighandler, NULL);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user