diff options
author | Jakub Jelinek <jakub@redhat.com> | 2006-08-15 05:53:50 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2006-08-15 05:53:50 +0000 |
commit | 3a2ba84afba2d9b315c65aa46ba036fd22ef4fb0 (patch) | |
tree | 47a553a26365a6738426804af7609434daf047b8 | |
parent | 256926546643ba909661c83e7a7d24d733b9b390 (diff) | |
download | glibc-3a2ba84afba2d9b315c65aa46ba036fd22ef4fb0.tar.gz glibc-3a2ba84afba2d9b315c65aa46ba036fd22ef4fb0.tar.xz glibc-3a2ba84afba2d9b315c65aa46ba036fd22ef4fb0.zip |
Updated to fedora-glibc-20060815T0533
54 files changed, 2257 insertions, 321 deletions
diff --git a/ChangeLog b/ChangeLog index a356c15e3d..e54bd15b93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,82 @@ +2006-08-15 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/sparc/sparc64/pause.c: Use + sysdeps/posix/pause.c implementation instead. + +2006-08-09 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/nice.c (nice): Transform EACCES errno from setpriority + to EPERM. + +2006-08-13 Andreas Schwab <schwab@suse.de> + + * sysdeps/powerpc/powerpc32/dl-trampoline.S (_dl_runtime_resolve): + Don't clobber caller's LRSAVE. + (_dl_prof_resolve): Likewise. + +2006-08-14 Ulrich Drepper <drepper@redhat.com> + + [BZ #1996] + * libio/memstream.c (open_memstream): Allocate initial buffer with + calloc. + * libio/wmemstream.c (open_wmemstream): Likewise. + * libio/strops.c: Pretty printing. + (_IO_str_overflow): Clear uninitialized part of the new buffer. + (enlarge_userbuf): New function. + (_IO_str_seekoff): Call it if seek position is larger than current + buffer. + * libio/wstrops.c: Likewise. + * libio/vasprintf.c: Add comment as to why we do not have to use + calloc instead of malloc to allocate initial buffer. + * libio/Makefile (tests): Add bug-memstream1 and bug-wmemstream1. + * libio/bug-memstream1.c: New file. + * libio/bug-wmemstream1.c: New file. + +2006-08-13 Ulrich Drepper <drepper@redhat.com> + + * libio/wstrops.c: Remove dead macro definitions and comments. + * libio/strops.c: Likewise. + + [BZ #2764] + * login/utmpname.c (__utmpname): Remove unnecessary test. + +2006-06-08 Joseph Myers <jsm28@gcc.gnu.org> + + [BZ #2832] + * math/gen-libm-test.pl (clean_up_number): Do not remove trailing + 0s from integers. + +2006-08-13 Ulrich Drepper <drepper@redhat.com> + + [BZ #2987] + * sysdeps/unix/sysv/linux/clock_settime.c: Add code to use syscall + for CPU clocks. + * sysdeps/unix/clock_settime.c: Add support for platform-specific + setting of CPU clocks. + +2006-06-23 Paul Eggert <eggert@cs.ucla.edu> + + [BZ #2841] + * sysdeps/generic/stdint.h (UINT8_C, UINT16_C): Don't append 'U', + since C99 requires the result to promote to 'int' when uint_least8_t + and uint_least16_t promote to 'int'. + +2006-08-12 Ulrich Drepper <drepper@redhat.com> + + [BZ #3013] + * locale/programs/ld-ctype.c (ctype_output): Adjust alignments, fix + lenght of one output field, correct bitmask creation. + * locale/programs/ld-time.c: Add alignment. + + [BZ #2997] + * misc/error.c: Add space between program name and message if file + name is missing. + +2006-08-03 Eric Blake <ebb9@byu.net> + + [BZ #2998] + * misc/error.c (error_tail) [_LIBC]: Avoid invalid free. + 2006-08-09 Ulrich Drepper <drepper@redhat.com> * malloc/memusagestat.c: Silence warnings. diff --git a/NEWS b/NEWS index 55855ad81a..14abed4782 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU C Library NEWS -- history of user-visible changes. 2006-07-28 +GNU C Library NEWS -- history of user-visible changes. 2006-08-14 Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc. See the end for copying conditions. @@ -36,6 +36,8 @@ Version 2.5 * Support for priority inheritance mutexes added by Jakub Jelinek and Ulrich Drepper. +* Support for priority protected mutexes added by Jakub Jelinek. + Version 2.4 diff --git a/fedora/branch.mk b/fedora/branch.mk index 4a26c92c8e..2416955f13 100644 --- a/fedora/branch.mk +++ b/fedora/branch.mk @@ -3,5 +3,5 @@ glibc-branch := fedora glibc-base := HEAD DIST_BRANCH := devel COLLECTION := dist-fc4 -fedora-sync-date := 2006-08-10 06:27 UTC -fedora-sync-tag := fedora-glibc-20060810T0627 +fedora-sync-date := 2006-08-15 05:33 UTC +fedora-sync-tag := fedora-glibc-20060815T0533 diff --git a/libio/Makefile b/libio/Makefile index e9c1d522fd..0529744e3d 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -56,7 +56,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \ bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \ tst-memstream1 tst-memstream2 \ - tst-wmemstream1 tst-wmemstream2 + tst-wmemstream1 tst-wmemstream2 \ + bug-memstream1 bug-wmemstream1 test-srcs = test-freopen all: # Make this the default target; it will be defined in Rules. diff --git a/libio/bug-memstream1.c b/libio/bug-memstream1.c new file mode 100644 index 0000000000..8af36fee2d --- /dev/null +++ b/libio/bug-memstream1.c @@ -0,0 +1,133 @@ +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + size_t size; + char *buf; + FILE *fp = open_memstream (&buf, &size); + if (fp == NULL) + { + puts ("open_memstream failed"); + return 1; + } + + off64_t off = ftello64 (fp); + if (off != 0) + { + puts ("initial position wrong"); + return 1; + } + + if (fseek (fp, 32768, SEEK_SET) != 0) + { + puts ("fseek failed"); + return 1; + } + + if (fputs ("foo", fp) == EOF) + { + puts ("fputs failed"); + return 1; + } + + if (fclose (fp) == EOF) + { + puts ("fclose failed"); + return 1; + } + + if (size != 32768 + 3) + { + printf ("expected size %d, got %zu\n", 32768 + 3, size); + return 1; + } + + for (int i = 0; i < 32768; ++i) + if (buf[i] != '\0') + { + printf ("byte at offset %d is %#hhx\n", i, buf[i]); + return 1; + } + + if (memcmp (buf + 32768, "foo", 3) != 0) + { + puts ("written string incorrect"); + return 1; + } + + /* Mark the buffer. */ + memset (buf, 'A', size); + free (buf); + + /* Try again, this time with write mode enabled before the seek. */ + fp = open_memstream (&buf, &size); + if (fp == NULL) + { + puts ("2nd open_memstream failed"); + return 1; + } + + off = ftello64 (fp); + if (off != 0) + { + puts ("2nd initial position wrong"); + return 1; + } + + if (fputs ("bar", fp) == EOF) + { + puts ("2nd fputs failed"); + return 1; + } + + if (fseek (fp, 32768, SEEK_SET) != 0) + { + puts ("2nd fseek failed"); + return 1; + } + + if (fputs ("foo", fp) == EOF) + { + puts ("3rd fputs failed"); + return 1; + } + + if (fclose (fp) == EOF) + { + puts ("2nd fclose failed"); + return 1; + } + + if (size != 32768 + 3) + { + printf ("2nd expected size %d, got %zu\n", 32768 + 3, size); + return 1; + } + + if (memcmp (buf, "bar", 3) != 0) + { + puts ("initial string incorrect in 2nd try"); + return 1; + } + + for (int i = 3; i < 32768; ++i) + if (buf[i] != '\0') + { + printf ("byte at offset %d is %#hhx in 2nd try\n", i, buf[i]); + return 1; + } + + if (memcmp (buf + 32768, "foo", 3) != 0) + { + puts ("written string incorrect in 2nd try"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/libio/bug-wmemstream1.c b/libio/bug-wmemstream1.c new file mode 100644 index 0000000000..2190593c93 --- /dev/null +++ b/libio/bug-wmemstream1.c @@ -0,0 +1,135 @@ +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + size_t size; + wchar_t *buf; + FILE *fp = open_wmemstream (&buf, &size); + if (fp == NULL) + { + puts ("open_wmemstream failed"); + return 1; + } + + off64_t off = ftello64 (fp); + if (off != 0) + { + puts ("initial position wrong"); + return 1; + } + + if (fseek (fp, 32768, SEEK_SET) != 0) + { + puts ("fseek failed"); + return 1; + } + + if (fputws (L"foo", fp) == EOF) + { + puts ("fputws failed"); + return 1; + } + + if (fclose (fp) == EOF) + { + puts ("fclose failed"); + return 1; + } + + if (size != 32768 + 3) + { + printf ("expected size %d, got %zu\n", 32768 + 3, size); + return 1; + } + + for (int i = 0; i < 32768; ++i) + if (buf[i] != L'\0') + { + printf ("wide character at offset %d is %#x\n", + i, (unsigned int) buf[i]); + return 1; + } + + if (wmemcmp (buf + 32768, L"foo", 3) != 0) + { + puts ("written string incorrect"); + return 1; + } + + /* Mark the buffer. */ + wmemset (buf, L'A', size); + free (buf); + + /* Try again, this time with write mode enabled before the seek. */ + fp = open_wmemstream (&buf, &size); + if (fp == NULL) + { + puts ("2nd open_wmemstream failed"); + return 1; + } + + off = ftello64 (fp); + if (off != 0) + { + puts ("2nd initial position wrong"); + return 1; + } + + if (fputws (L"bar", fp) == EOF) + { + puts ("2nd fputws failed"); + return 1; + } + + if (fseek (fp, 32768, SEEK_SET) != 0) + { + puts ("2nd fseek failed"); + return 1; + } + + if (fputws (L"foo", fp) == EOF) + { + puts ("3rd fputws failed"); + return 1; + } + + if (fclose (fp) == EOF) + { + puts ("2nd fclose failed"); + return 1; + } + + if (size != 32768 + 3) + { + printf ("2nd expected size %d, got %zu\n", 32768 + 3, size); + return 1; + } + + if (wmemcmp (buf, L"bar", 3) != 0) + { + puts ("initial string incorrect in 2nd try"); + return 1; + } + + for (int i = 3; i < 32768; ++i) + if (buf[i] != L'\0') + { + printf ("wide character at offset %d is %#x in 2nd try\n", + i, (unsigned int) buf[i]); + return 1; + } + + if (wmemcmp (buf + 32768, L"foo", 3) != 0) + { + puts ("written string incorrect in 2nd try"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/libio/memstream.c b/libio/memstream.c index 742da740ef..877383f3a8 100644 --- a/libio/memstream.c +++ b/libio/memstream.c @@ -83,7 +83,7 @@ open_memstream (bufloc, sizeloc) new_f->fp._sf._sbf._f._lock = &new_f->lock; #endif - buf = malloc (_IO_BUFSIZ); + buf = calloc (1, _IO_BUFSIZ); if (buf == NULL) return NULL; INTUSE(_IO_init) (&new_f->fp._sf._sbf._f, 0); diff --git a/libio/strops.c b/libio/strops.c index 2de83403a2..05270ce407 100644 --- a/libio/strops.c +++ b/libio/strops.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1997-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1997-2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -25,43 +25,12 @@ This exception applies to code released by its copyright holders in files containing the exception. */ +#include <assert.h> #include "strfile.h" #include "libioP.h" #include <string.h> #include <stdio_ext.h> -#if 0 -/* The following definitions are for exposition only. - They map the terminology used in the ANSI/ISO C++ draft standard - to the implementation. */ - -/* allocated: set when a dynamic array object has been allocated, and - hence should be freed by the destructor for the strstreambuf object. */ -#define ALLOCATED(FP) ((FP)->_f._IO_buf_base && DYNAMIC(FP)) - -/* constant: set when the array object has const elements, - so the output sequence cannot be written. */ -#define CONSTANT(FP) ((FP)->_f._IO_file_flags & _IO_NO_WRITES) - -/* alsize: the suggested minimum size for a dynamic array object. */ -#define ALSIZE(FP) ??? /* not stored */ - -/* palloc: points to the function to call to allocate a dynamic array object.*/ -#define PALLOC(FP) \ - ((FP)->_s._allocate_buffer == default_alloc ? 0 : (FP)->_s._allocate_buffer) - -/* pfree: points to the function to call to free a dynamic array object. */ -#define PFREE(FP) \ - ((FP)->_s._free_buffer == default_free ? 0 : (FP)->_s._free_buffer) - -#endif - -#ifdef TODO -/* An "unbounded buffer" is when a buffer is supplied, but with no - specified length. An example is the buffer argument to sprintf. - */ -#endif - void _IO_str_init_static_internal (sf, ptr, size, pstart) _IO_strfile *sf; @@ -134,7 +103,7 @@ _IO_str_overflow (fp, c) fp->_IO_write_ptr = fp->_IO_read_ptr; fp->_IO_read_ptr = fp->_IO_read_end; } - pos = fp->_IO_write_ptr - fp->_IO_write_base; + pos = fp->_IO_write_ptr - fp->_IO_write_base; if (pos >= (_IO_size_t) (_IO_blen (fp) + flush_only)) { if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */ @@ -143,7 +112,10 @@ _IO_str_overflow (fp, c) { char *new_buf; char *old_buf = fp->_IO_buf_base; - _IO_size_t new_size = 2 * _IO_blen (fp) + 100; + size_t old_blen = _IO_blen (fp); + _IO_size_t new_size = 2 * old_blen + 100; + if (new_size < old_blen) + return EOF; new_buf = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); if (new_buf == NULL) @@ -153,15 +125,13 @@ _IO_str_overflow (fp, c) } if (old_buf) { - memcpy (new_buf, old_buf, _IO_blen (fp)); + memcpy (new_buf, old_buf, old_blen); (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_IO_buf_base = NULL; } -#if 0 - if (lenp == &LEN(fp)) /* use '\0'-filling */ - memset (new_buf + pos, 0, blen() - pos); -#endif + memset (new_buf + old_blen, '\0', new_size - old_blen); + INTUSE(_IO_setb) (fp, new_buf, new_buf + new_size, 1); fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf); fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf); @@ -211,6 +181,71 @@ _IO_str_count (fp) - fp->_IO_read_base); } + +static int +enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) +{ + if ((_IO_ssize_t) offset <= _IO_blen (fp)) + return 0; + + _IO_ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base; + + /* Try to enlarge the buffer. */ + if (fp->_flags & _IO_USER_BUF) + /* User-provided buffer. */ + return 1; + + _IO_size_t newsize = offset + 100; + char *oldbuf = fp->_IO_buf_base; + char *newbuf + = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + memcpy (newbuf, oldbuf, _IO_blen (fp)); + (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + fp->_IO_buf_base = NULL; + } + + INTUSE(_IO_setb) (fp, newbuf, newbuf + newsize, 1); + + if (reading) + { + fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf); + fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf); + fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf); + fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf); + + fp->_IO_read_base = newbuf; + fp->_IO_read_end = fp->_IO_buf_end; + } + else + { + fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf); + fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf); + fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf); + fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf); + + fp->_IO_write_base = newbuf; + fp->_IO_write_end = fp->_IO_buf_end; + } + + /* Clear the area between the last write position and th + new position. */ + assert (offset >= oldend); + if (reading) + memset (fp->_IO_read_base + oldend, '\0', offset - oldend); + else + memset (fp->_IO_write_base + oldend, '\0', offset - oldend); + + return 0; +} + + _IO_off64_t _IO_str_seekoff (fp, offset, dir, mode) _IO_FILE *fp; @@ -251,7 +286,10 @@ _IO_str_seekoff (fp, offset, dir, mode) default: /* case _IO_seek_set: */ break; } - if (offset < 0 || (_IO_ssize_t) offset > cur_size) + if (offset < 0) + return EOF; + if ((_IO_ssize_t) offset > cur_size + && enlarge_userbuf (fp, offset, 1) != 0) return EOF; fp->_IO_read_ptr = fp->_IO_read_base + offset; fp->_IO_read_end = fp->_IO_read_base + cur_size; @@ -272,7 +310,10 @@ _IO_str_seekoff (fp, offset, dir, mode) default: /* case _IO_seek_set: */ break; } - if (offset < 0 || (_IO_ssize_t) offset > cur_size) + if (offset < 0) + return EOF; + if ((_IO_ssize_t) offset > cur_size + && enlarge_userbuf (fp, offset, 0) != 0) return EOF; fp->_IO_write_ptr = fp->_IO_write_base + offset; new_pos = offset; diff --git a/libio/vasprintf.c b/libio/vasprintf.c index ac7733006d..2fdb9f6ed2 100644 --- a/libio/vasprintf.c +++ b/libio/vasprintf.c @@ -46,6 +46,8 @@ _IO_vasprintf (result_ptr, format, args) int ret; _IO_size_t needed; _IO_size_t allocated; + /* No need to clear the memory here (unlike for open_memstream) since + we know we will never seek on the stream. */ string = (char *) malloc (init_string_size); if (string == NULL) return -1; diff --git a/libio/wmemstream.c b/libio/wmemstream.c index 1709f2dd33..85ea64991a 100644 --- a/libio/wmemstream.c +++ b/libio/wmemstream.c @@ -83,7 +83,7 @@ open_wmemstream (bufloc, sizeloc) new_f->fp._sf._sbf._f._lock = &new_f->lock; #endif - buf = malloc (_IO_BUFSIZ); + buf = calloc (1, _IO_BUFSIZ); if (buf == NULL) return NULL; diff --git a/libio/wstrops.c b/libio/wstrops.c index 32f7ef3cf7..8b862fb989 100644 --- a/libio/wstrops.c +++ b/libio/wstrops.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993,1997-1999,2001-2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1993,1997-1999,2001-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -25,44 +25,13 @@ This exception applies to code released by its copyright holders in files containing the exception. */ +#include <assert.h> #include "strfile.h" #include "libioP.h" #include <string.h> #include <wchar.h> #include <stdio_ext.h> -#if 0 -/* The following definitions are for exposition only. - They map the terminology used in the ANSI/ISO C++ draft standard - to the implementation. */ - -/* allocated: set when a dynamic array object has been allocated, and - hence should be freed by the destructor for the strstreambuf object. */ -#define ALLOCATED(FP) ((FP)->_f._IO_buf_base && DYNAMIC(FP)) - -/* constant: set when the array object has const elements, - so the output sequence cannot be written. */ -#define CONSTANT(FP) ((FP)->_f._IO_file_flags & _IO_NO_WRITES) - -/* alsize: the suggested minimum size for a dynamic array object. */ -#define ALSIZE(FP) ??? /* not stored */ - -/* palloc: points to the function to call to allocate a dynamic array object.*/ -#define PALLOC(FP) \ - ((FP)->_s._allocate_buffer == default_alloc ? 0 : (FP)->_s._allocate_buffer) - -/* pfree: points to the function to call to free a dynamic array object. */ -#define PFREE(FP) \ - ((FP)->_s._free_buffer == default_free ? 0 : (FP)->_s._free_buffer) - -#endif - -#ifdef TODO -/* An "unbounded buffer" is when a buffer is supplied, but with no - specified length. An example is the buffer argument to sprintf. - */ -#endif - void _IO_wstr_init_static (fp, ptr, size, pstart) _IO_FILE *fp; @@ -98,7 +67,7 @@ _IO_wstr_init_static (fp, ptr, size, pstart) fp->_wide_data->_IO_read_end = end; } /* A null _allocate_buffer function flags the strfile as being static. */ - (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0; + (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0; } _IO_wint_t @@ -116,7 +85,7 @@ _IO_wstr_overflow (fp, c) fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr; fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end; } - pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base; + pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base; if (pos >= (_IO_size_t) (_IO_wblen (fp) + flush_only)) { if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */ @@ -125,7 +94,10 @@ _IO_wstr_overflow (fp, c) { wchar_t *new_buf; wchar_t *old_buf = fp->_wide_data->_IO_buf_base; - _IO_size_t new_size = 2 * _IO_wblen (fp) + 100; + size_t old_wblen = _IO_wblen (fp); + _IO_size_t new_size = 2 * old_wblen + 100; + if (new_size < old_wblen) + return EOF; new_buf = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size * sizeof (wchar_t)); @@ -136,11 +108,14 @@ _IO_wstr_overflow (fp, c) } if (old_buf) { - __wmemcpy (new_buf, old_buf, _IO_wblen (fp)); + __wmemcpy (new_buf, old_buf, old_wblen); (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); /* Make sure _IO_setb won't try to delete _IO_buf_base. */ fp->_wide_data->_IO_buf_base = NULL; } + + wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen); + INTUSE(_IO_wsetb) (fp, new_buf, new_buf + new_size, 1); fp->_wide_data->_IO_read_base = new_buf + (fp->_wide_data->_IO_read_base - old_buf); @@ -163,6 +138,7 @@ _IO_wstr_overflow (fp, c) return c; } + _IO_wint_t _IO_wstr_underflow (fp) _IO_FILE *fp; @@ -181,17 +157,87 @@ _IO_wstr_underflow (fp) return WEOF; } -/* The size of the valid part of the buffer. */ +/* The size of the valid part of the buffer. */ _IO_ssize_t _IO_wstr_count (fp) _IO_FILE *fp; { - return ((fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end - ? fp->_wide_data->_IO_write_ptr : fp->_wide_data->_IO_read_end) - - fp->_wide_data->_IO_read_base); + struct _IO_wide_data *wd = fp->_wide_data; + + return ((wd->_IO_write_ptr > wd->_IO_read_end + ? wd->_IO_write_ptr : wd->_IO_read_end) + - wd->_IO_read_base); } + +static int +enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) +{ + if ((_IO_ssize_t) offset <= _IO_blen (fp)) + return 0; + + struct _IO_wide_data *wd = fp->_wide_data; + + _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base; + + /* Try to enlarge the buffer. */ + if (fp->_flags & _IO_USER_BUF) + /* User-provided buffer. */ + return 1; + + _IO_size_t newsize = offset + 100; + wchar_t *oldbuf = wd->_IO_buf_base; + wchar_t *newbuf + = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize + * sizeof (wchar_t)); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + __wmemcpy (newbuf, oldbuf, _IO_wblen (fp)); + (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + wd->_IO_buf_base = NULL; + } + + INTUSE(_IO_wsetb) (fp, newbuf, newbuf + newsize, 1); + + if (reading) + { + wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf); + wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf); + wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf); + wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf); + + wd->_IO_read_base = newbuf; + wd->_IO_read_end = wd->_IO_buf_end; + } + else + { + wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf); + wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf); + wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf); + wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf); + + wd->_IO_write_base = newbuf; + wd->_IO_write_end = wd->_IO_buf_end; + } + + /* Clear the area between the last write position and th + new position. */ + assert (offset >= oldend); + if (reading) + wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend); + else + wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend); + + return 0; +} + + _IO_off64_t _IO_wstr_seekoff (fp, offset, dir, mode) _IO_FILE *fp; @@ -234,7 +280,10 @@ _IO_wstr_seekoff (fp, offset, dir, mode) default: /* case _IO_seek_set: */ break; } - if (offset < 0 || (_IO_ssize_t) offset > cur_size) + if (offset < 0) + return EOF; + if ((_IO_ssize_t) offset > cur_size + && enlarge_userbuf (fp, offset, 1) != 0) return EOF; fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base + offset); @@ -258,7 +307,10 @@ _IO_wstr_seekoff (fp, offset, dir, mode) default: /* case _IO_seek_set: */ break; } - if (offset < 0 || (_IO_ssize_t) offset > cur_size) + if (offset < 0) + return EOF; + if ((_IO_ssize_t) offset > cur_size + && enlarge_userbuf (fp, offset, 0) != 0) return EOF; fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base + offset); diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c index b0b2e3f805..f38231f984 100644 --- a/locale/programs/ld-ctype.c +++ b/locale/programs/ld-ctype.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc. +/* Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@gnu.org>, 1995. @@ -992,8 +992,8 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap, total += iov[2 + elem + offset].iov_len; } iov[2 + elem + offset].iov_base = (void *) nulbytes; - iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4)); - total += 1 + (4 - ((total + 1) % 4)); + iov[2 + elem + offset].iov_len = 4 - (total % 4); + total += 4 - (total % 4); idx[elem + 1] = idx[elem] + total; break; @@ -1010,8 +1010,8 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap, total += iov[2 + elem + offset].iov_len; } iov[2 + elem + offset].iov_base = (void *) nulbytes; - iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4)); - total += 1 + (4 - ((total + 1) % 4)); + iov[2 + elem + offset].iov_len = 4 - (total % 4); + total += 4 - (total % 4); idx[elem + 1] = idx[elem] + total; break; @@ -1153,7 +1153,7 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap, iov[2 + elem + offset].iov_base = ctype->default_missing ?: (uint32_t *) L""; iov[2 + elem + offset].iov_len = - wcslen (iov[2 + elem + offset].iov_base); + wcslen (iov[2 + elem + offset].iov_base) * sizeof (uint32_t); idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len; break; @@ -3844,9 +3844,14 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, { ctype->class_b[nr] = (uint32_t *) xcalloc (256 / 32, sizeof (uint32_t)); - for (idx = 0; idx < 256; ++idx) - if (ctype->class256_collection[idx] & _ISbit (nr)) - ctype->class_b[nr][idx >> 5] |= (uint32_t)1 << (idx & 0x1f); + /* We only set CLASS_B for the bits in the ISO C classes, not + the user defined classes. The number should not change but + who knows. */ +#define LAST_ISO_C_BIT 11 + if (nr <= LAST_ISO_C_BIT) + for (idx = 0; idx < 256; ++idx) + if (ctype->class256_collection[idx] & _ISbit (nr)) + ctype->class_b[nr][idx >> 5] |= (uint32_t) 1 << (idx & 0x1f); } for (nr = 0; nr < ctype->nr_charclass; nr++) diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c index 4f1dcb0ce7..bf5151858a 100644 --- a/locale/programs/ld-time.c +++ b/locale/programs/ld-time.c @@ -542,7 +542,7 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap, * (2 + _NL_ITEM_INDEX (_NL_NUM_LC_TIME) + time->num_era - 1 + 2 * 99 - + 2 + time->num_era * 10 - 1)); + + 2 + time->num_era * 10)); struct locale_file data; uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_TIME)]; size_t cnt, last_idx, num, n; @@ -901,6 +901,12 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap, ++cnt; ++last_idx; + /* We must align the following data. */ + iov[2 + cnt].iov_base = (void *) "\0\0"; + iov[2 + cnt].iov_len = -idx[last_idx] & 3; + idx[last_idx] += -idx[last_idx] & 3; + ++cnt; + iov[2 + cnt].iov_base = (void *) time->wdate_fmt; iov[2 + cnt].iov_len = ((wcslen (iov[2 + cnt].iov_base) + 1) * sizeof (uint32_t)); @@ -916,7 +922,7 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap, assert (cnt == (_NL_ITEM_INDEX (_NL_NUM_LC_TIME) + time->num_era - 1 + 2 * 99 - + 2 + time->num_era * 10 - 1)); + + 2 + time->num_era * 10)); assert (last_idx == _NL_ITEM_INDEX (_NL_NUM_LC_TIME)); write_locale_data (output_path, LC_TIME, "LC_TIME", 2 + cnt, iov); diff --git a/localedata/ChangeLog b/localedata/ChangeLog index 76129512b6..80adc04066 100644 --- a/localedata/ChangeLog +++ b/localedata/ChangeLog @@ -1,3 +1,19 @@ +2006-08-13 Ulrich Drepper <drepper@redhat.com> + + [BZ #935] + * SUPPORTED (SUPPORTED-LOCALES): Add fy_NL. + * locales/fy_NL: New file. + +2006-08-12 Ulrich Drepper <drepper@redhat.com> + + [BZ #3034] + * locales/pa_IN (day): Fix spelling of Saturday. + * locales/or_IN (mon): Fix spelling of May. + * locales/ml_IN (day): Fix spelling of Sunday, Monday, Wednesday. + (abmon): Fix spelling of March to October. + (mon): Fix spelling of March, April, June, August to December. + Patches by Mayank Jain <majain@redhat.com>. + 2006-06-03 Eddy Petrisor <eddy.petrisor@gmail.com> [BZ #2125] diff --git a/localedata/SUPPORTED b/localedata/SUPPORTED index cd6d91710c..9de5b7ae15 100644 --- a/localedata/SUPPORTED +++ b/localedata/SUPPORTED @@ -193,6 +193,7 @@ fr_FR@euro/ISO-8859-15 \ fr_LU.UTF-8/UTF-8 \ fr_LU/ISO-8859-1 \ fr_LU@euro/ISO-8859-15 \ +fy_NL/UTF-8 \ ga_IE.UTF-8/UTF-8 \ ga_IE/ISO-8859-1 \ ga_IE@euro/ISO-8859-15 \ diff --git a/localedata/locales/fy_NL b/localedata/locales/fy_NL new file mode 100644 index 0000000000..d247e50d0c --- /dev/null +++ b/localedata/locales/fy_NL @@ -0,0 +1,139 @@ +comment_char % +escape_char / +% +% Frisian Language Locale for the Netherlands +% Language: fy +% Territory: NL +% Date: 2006-8-13 +% Users: general +% Charset: ISO-8859-1 +% Distribution and use is free, also +% for commercial purposes. + +LC_IDENTIFICATION +title "Frisian locale for the Netherlands" +source "Free Software Foundation, Inc." +address "59 Temple Place - Suite 330, Boston, MA 02111-1307, USA" +contact "" +email "bug-glibc-locales@gnu.org" +tel "" +fax "" +language "Frisian" +territory "Netherlands" +revision "1.0" +date "2006-08-13" +% +category "fy_NL:2000";LC_IDENTIFICATION +category "fy_NL:2000";LC_CTYPE +category "fy_NL:2000";LC_COLLATE +category "fy_NL:2000";LC_TIME +category "fy_NL:2000";LC_NUMERIC +category "fy_NL:2000";LC_MONETARY +category "fy_NL:2000";LC_MEASUREMENT +category "fy_NL:2000";LC_MESSAGES +category "fy_NL:2000";LC_PAPER +category "fy_NL:2000";LC_NAME +category "fy_NL:2000";LC_ADDRESS +category "fy_NL:2000";LC_TELEPHONE +END LC_IDENTIFICATION + +LC_CTYPE +copy "nl_NL" +END LC_CTYPE + +LC_COLLATE +copy "nl_NL" +END LC_COLLATE + +LC_TIME +abday "<U0053><U006E>";/ + "<U004D><U006F>";/ + "<U0054><U0069>";/ + "<U0057><U006F>";/ + "<U0054><U006F>";/ + "<U0046><U0072>";/ + "<U0053><U006E>" +day "<U0053><U006E><U0065><U0069><U006E>";/ + "<U004D><U006F><U0061><U006E><U0064><U0065><U0069>";/ + "<U0054><U0069><U0069><U0073><U0064><U0065><U0069>";/ + "<U0057><U006F><U0061><U006E><U0073><U0064><U0065><U0069>";/ + "<U0054><U006F><U006E><U0067><U0065><U0072><U0073><U0064><U0065><U0069>";/ + "<U0046><U0072><U0065><U0065><U0064>";/ + "<U0053><U006E><U0065><U006F><U006E>" +abmon "<U004A><U0061><U006E>";/ + "<U0046><U0065><U0062>";/ + "<U004D><U0061><U0061>";/ + "<U0041><U0070><U0072>";/ + "<U004D><U0061><U0061>";/ + "<U004A><U0075><U006E>";/ + "<U004A><U0075><U006C>";/ + "<U0041><U0075><U0067>";/ + "<U0053><U0065><U0070>";/ + "<U004F><U006B><U0074>";/ + "<U004E><U006F><U0076>";/ + "<U0044><U0065><U0073>" +mon "<U004A><U0061><U006E><U0061><U0072><U0069><U0073>";/ + "<U0046><U0065><U0062><U0072><U0065><U0077><U0061><U0072><U0069><U0073>";/ + "<U004D><U0061><U0061><U0072><U0074>";/ + "<U0041><U0070><U0072><U0069><U006C>";/ + "<U004D><U0061><U0061><U0069><U0065>";/ + "<U004A><U0075><U006E><U0079>";/ + "<U004A><U0075><U006C><U0079>";/ + "<U0041><U0075><U0067><U0075><U0073><U0074><U0075><U0073>";/ + "<U0053><U0065><U0070><U0074><U0069><U006D><U0062><U0065><U0072>";/ + "<U004F><U006B><U0074><U006F><U0062><U0065><U0072>";/ + "<U004E><U006F><U0076><U0069><U006D><U0062><U0065><U0072>";/ + "<U0044><U0065><U0073><U0069><U006D><U0062><U0065><U0072>" +d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>" +d_fmt "<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0079>" +t_fmt "<U0025><U0054>" +am_pm "";"" +t_fmt_ampm "" +date_fmt "<U0025><U0061><U0020><U0025><U0062><U0020><U0025><U0065>/ +<U0020><U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053><U0020>/ +<U0025><U005A><U0020><U0025><U0059>" +END LC_TIME + +LC_NUMERIC +copy "nl_NL" +END LC_NUMERIC + +LC_MONETARY +copy "nl_NL" +END LC_MONETARY + +LC_MEASUREMENT +copy "nl_NL" +END LC_MEASUREMENT + +LC_MESSAGES +copy "nl_NL" +END LC_MESSAGES + +LC_PAPER +copy "nl_NL" +END LC_PAPER + +LC_NAME +copy "nl_NL" +END LC_NAME + +LC_ADDRESS +postal_fmt "<U0025><U0066><U0025><U004E><U0025><U0061><U0025><U004E>/ +<U0025><U0064><U0025><U004E><U0025><U0062><U0025><U004E><U0025><U0073>/ +<U0020><U0025><U0068><U0020><U0025><U0065><U0020><U0025><U0072><U0025>/ +<U004E><U0025><U0025><U007A><U0020><U0025><U0054><U0025>/ +<U004E><U0025><U0063><U0025><U004E>" +country_ab2 "<U004E><U004C>" +country_ab3 "<U004E><U004C><U0044>" +country_num 528 +country_car "<U004E><U004C>" +lang_name "<U0046><U0072><U0069><U0073><U0069><U0061><U006E>" +lang_ab "<U0066><U0079>" +lang_term "<U0066><U0072><U0079>" +lang_lib "<U0066><U0072><U0079>" +END LC_ADDRESS + +LC_TELEPHONE +copy "nl_NL" +END LC_TELEPHONE diff --git a/localedata/locales/or_IN b/localedata/locales/or_IN index 6170d03823..03123026d5 100644 --- a/localedata/locales/or_IN +++ b/localedata/locales/or_IN @@ -644,7 +644,7 @@ mon "<U0B1C><U0B3E><U0B28><U0B41><U0B06><U0B30><U0B40>";/ "<U0B2B><U0B47><U0B2C><U0B4D><U0B30><U0B41><U0B5F><U0B3E><U0B30><U0B40>";/ "<U0B2E><U0B3E><U0B30><U0B4D><U0B1A><U0B4D><U0B1A>";/ "<U0B05><U0B2A><U0B4D><U0B30><U0B47><U0B32>";/ - "<U0B2E><U0B47>";/ + "<U0B2E><U0B07>";/ "<U0B1C><U0B41><U0B28>";/ "<U0B1C><U0B41><U0B32><U0B3E><U0B07>";/ "<U0B05><U0B17><U0B37><U0B4D><U0B1F>";/ diff --git a/localedata/locales/pa_IN b/localedata/locales/pa_IN index d432a169e5..e38308dfac 100644 --- a/localedata/locales/pa_IN +++ b/localedata/locales/pa_IN @@ -89,7 +89,7 @@ day "<U0A10><U0A24><U0A35><U0A3E><U0A30><U0020>";/ "<U0A2C><U0A41><U0A71><U0A27><U0A35><U0A3E><U0A30><U0020>";/ "<U0A35><U0A40><U0A30><U0A35><U0A3E><U0A30><U0020>";/ "<U0A36><U0A41><U0A71><U0A15><U0A30><U0A35><U0A3E><U0A30><U0020>";/ - "<U0A36><U0A28><U0A40><U0A1A><U0A30><U0A35><U0A3E><U0A30><U0020>" + "<U0A36><U0A28><U0A3F><U0A71><U0A1A><U0A30><U0A35><U0A3E><U0A30><U0020>" % Abbreviated month names (%b) diff --git a/login/utmpname.c b/login/utmpname.c index 875dbd5973..24ed7f3c46 100644 --- a/login/utmpname.c +++ b/login/utmpname.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 2002 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2002, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997. @@ -50,8 +50,7 @@ __utmpname (const char *file) { if (strcmp (file, default_file_name) == 0) { - if (__libc_utmp_file_name != default_file_name) - free ((char *) __libc_utmp_file_name); + free ((char *) __libc_utmp_file_name); __libc_utmp_file_name = default_file_name; } diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl index a63f62a1cb..0b0b8ca19f 100755 --- a/math/gen-libm-test.pl +++ b/math/gen-libm-test.pl @@ -558,9 +558,11 @@ sub parse_ulps { sub clean_up_number { my ($number) = @_; - # Remove trailing zeros - $number =~ s/0+$//; - $number =~ s/\.$//; + # Remove trailing zeros after the decimal point + if ($number =~ /\./) { + $number =~ s/0+$//; + $number =~ s/\.$//; + } return $number; } diff --git a/misc/error.c b/misc/error.c index 66a8ccb501..aca435d995 100644 --- a/misc/error.c +++ b/misc/error.c @@ -1,5 +1,5 @@ /* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1990-1998, 2000-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -224,7 +224,10 @@ error_tail (int status, int errnum, const char *message, va_list args) { /* The string cannot be converted. */ if (use_malloc) - free (wmessage); + { + free (wmessage); + use_malloc = false; + } wmessage = (wchar_t *) L"???"; } @@ -382,14 +385,13 @@ error_at_line (status, errnum, file_name, line_number, message, va_alist) #endif } - if (file_name != NULL) - { #if _LIBC - __fxprintf (NULL, "%s:%d: ", file_name, line_number); + __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); #else - fprintf (stderr, "%s:%d: ", file_name, line_number); + fprintf (stderr, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); #endif - } #ifdef VA_START VA_START (args, message); diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 6450e42574..fe6e5c06c3 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,54 @@ +2006-08-14 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/posix_opt.h + (_POSIX_THREAD_PRIO_PROTECT): Define to 200112L. + * descr.h (struct priority_protection_data): New type. + (struct pthread): Add tpp field. + * pthreadP.h (PTHREAD_MUTEX_PP_NORMAL_NP, + PTHREAD_MUTEX_PP_RECURSIVE_NP, PTHREAD_MUTEX_PP_ERRORCHECK_NP, + PTHREAD_MUTEX_PP_ADAPTIVE_NP): New enum values. + * pthread_mutex_init.c (__pthread_mutex_init): Handle non-robust + TPP mutexes. + * pthread_mutex_lock.c (__pthread_mutex_lock): Handle TPP mutexes. + * pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. + * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise. + * pthread_mutex_unlock.c (__pthread_mutex_unlock_usercnt): Likewise. + * tpp.c: New file. + * pthread_setschedparam.c (__pthread_setschedparam): Handle priority + boosted by TPP. + * pthread_setschedprio.c (pthread_setschedprio): Likewise. + * pthread_mutexattr_getprioceiling.c + (pthread_mutexattr_getprioceiling): If ceiling is 0, ensure it is + in the SCHED_FIFO priority range. + * pthread_mutexattr_setprioceiling.c + (pthread_mutexattr_setprioceiling): Fix prioceiling validation. + * pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): Fail + if mutex is not TPP. Ceiling is now in __data.__lock. + * pthread_mutex_setprioceiling.c: Include stdbool.h. + (pthread_mutex_setprioceiling): Fix prioceiling validation. Ceiling + is now in __data.__lock. Add locking. + * pthread_create.c (__free_tcb): Free pd->tpp structure. + * Makefile (libpthread-routines): Add tpp. + (xtests): Add tst-mutexpp1, tst-mutexpp6 and tst-mutexpp10. + * tst-tpp.h: New file. + * tst-mutexpp1.c: New file. + * tst-mutexpp6.c: New file. + * tst-mutexpp10.c: New file. + * tst-mutex1.c (TEST_FUNCTION): Don't redefine if already defined. + * tst-mutex6.c (TEST_FUNCTION): Likewise. + +2006-08-12 Ulrich Drepper <drepper@redhat.com> + + [BZ #2843] + * pthread_join.c (pthread_join): Account for self being canceled + when checking for deadlocks. + * tst-join5.c: Cleanups. Allow to be used in tst-join6. + (tf1): Don't print anything after pthread_join returns, this would be + another cancellation point. + (tf2): Likewise. + * tst-join6.c: New file. + * Makefile (tests): Add tst-join6. + 2006-08-03 Ulrich Drepper <drepper@redhat.com> [BZ #2892] diff --git a/nptl/Makefile b/nptl/Makefile index 3a72d3707e..c0c09e52fe 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -224,7 +224,7 @@ tests = tst-typesizes \ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ tst-raise1 \ - tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 \ + tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \ tst-detach1 \ tst-eintr1 tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 \ tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 tst-tsd5 \ diff --git a/nptl/descr.h b/nptl/descr.h index 607aa9fcdb..7acd2f4f22 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -111,6 +111,14 @@ struct robust_list_head }; +/* Data strcture used to handle thread priority protection. */ +struct priority_protection_data +{ + int priomax; + unsigned int priomap[]; +}; + + /* Thread descriptor data structure. */ struct pthread { @@ -343,6 +351,9 @@ struct pthread /* This is what the user specified and what we will report. */ size_t reported_guardsize; + /* Thread Priority Protection data. */ + struct priority_protection_data *tpp; + /* Resolver state. */ struct __res_state res; diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index dc98bb19c0..503e99b2b4 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -86,17 +86,31 @@ enum = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP, PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP, - PTHREAD_MUTEX_PRIO_PROTECT_NP = 64 + PTHREAD_MUTEX_PRIO_PROTECT_NP = 64, + PTHREAD_MUTEX_PP_NORMAL_NP + = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_NORMAL, + PTHREAD_MUTEX_PP_RECURSIVE_NP + = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_PP_ERRORCHECK_NP + = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_PP_ADAPTIVE_NP + = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ADAPTIVE_NP }; -#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 16 -#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0x00ff0000 + +/* Ceiling in __data.__lock. __data.__lock is signed, so don't + use the MSB bit in there, but in the mask also include that bit, + so that the compiler can optimize & PTHREAD_MUTEX_PRIO_CEILING_MASK + masking if the value is then shifted down by + PTHREAD_MUTEX_PRIO_CEILING_SHIFT. */ +#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 19 +#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0xfff80000 /* Flags in mutex attr. */ #define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28 #define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000 -#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 16 -#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00ff0000 +#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 12 +#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00fff000 #define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000 #define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000 #define PTHREAD_MUTEXATTR_FLAG_BITS \ @@ -151,6 +165,14 @@ extern unsigned int __nptl_nthreads attribute_hidden; extern int __set_robust_list_avail attribute_hidden; #endif +/* Thread Priority Protection. */ +extern int __sched_fifo_min_prio attribute_hidden; +extern int __sched_fifo_max_prio attribute_hidden; +extern void __init_sched_fifo_prio (void) attribute_hidden; +extern int __pthread_tpp_change_priority (int prev_prio, int new_prio) + attribute_hidden; +extern int __pthread_current_priority (void) attribute_hidden; + /* The library can run in debugging mode where it performs a lot more tests. */ extern int __pthread_debug attribute_hidden; diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index c1ac199bb9..315722643b 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -206,6 +206,15 @@ __free_tcb (struct pthread *pd) running thread is gone. */ abort (); + /* Free TPP data. */ + if (__builtin_expect (pd->tpp != NULL, 0)) + { + struct priority_protection_data *tpp = pd->tpp; + + pd->tpp = NULL; + free (tpp); + } + /* Queue the stack memory block for reuse and exit the process. The kernel will signal via writing to the address returned by QUEUE-STACK when the stack is available. */ diff --git a/nptl/pthread_join.c b/nptl/pthread_join.c index 70dc81a023..c88d85b52f 100644 --- a/nptl/pthread_join.c +++ b/nptl/pthread_join.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -27,7 +27,11 @@ static void cleanup (void *arg) { - *(void **) arg = NULL; + /* If we already changed the waiter ID, reset it. The call cannot + fail for any reason but the thread not having done that yet so + there is no reason for a loop. */ + atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL, + THREAD_SELF); } @@ -36,7 +40,6 @@ pthread_join (threadid, thread_return) pthread_t threadid; void **thread_return; { - struct pthread *self; struct pthread *pd = (struct pthread *) threadid; /* Make sure the descriptor is valid. */ @@ -49,12 +52,23 @@ pthread_join (threadid, thread_return) /* We cannot wait for the thread. */ return EINVAL; - self = THREAD_SELF; - if (pd == self - || (self->joinid == pd - && (pd->cancelhandling - & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK - | TERMINATED_BITMASK)) == 0)) + struct pthread *self = THREAD_SELF; + int result = 0; + + /* During the wait we change to asynchronous cancellation. If we + are canceled the thread we are waiting for must be marked as + un-wait-ed for again. */ + pthread_cleanup_push (cleanup, &pd->joinid); + + /* Switch to asynchronous cancellation. */ + int oldtype = CANCEL_ASYNC (); + + if ((pd == self + || (self->joinid == pd + && (pd->cancelhandling + & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK + | TERMINATED_BITMASK)) == 0)) + && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling)) /* This is a deadlock situation. The threads are waiting for each other to finish. Note that this is a "may" error. To be 100% sure we catch this error we would have to lock the data @@ -62,28 +76,17 @@ pthread_join (threadid, thread_return) two threads are really caught in this situation they will deadlock. It is the programmer's problem to figure this out. */ - return EDEADLK; - + result = EDEADLK; /* Wait for the thread to finish. If it is already locked something is wrong. There can only be one waiter. */ - if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, - self, - NULL), 0)) + else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid, + self, + NULL), 0)) /* There is already somebody waiting for the thread. */ - return EINVAL; - - - /* During the wait we change to asynchronous cancellation. If we - are cancelled the thread we are waiting for must be marked as - un-wait-ed for again. */ - pthread_cleanup_push (cleanup, &pd->joinid); - - /* Switch to asynchronous cancellation. */ - int oldtype = CANCEL_ASYNC (); - - - /* Wait for the child. */ - lll_wait_tid (pd->tid); + result = EINVAL; + else + /* Wait for the child. */ + lll_wait_tid (pd->tid); /* Restore cancellation mode. */ @@ -93,16 +96,19 @@ pthread_join (threadid, thread_return) pthread_cleanup_pop (0); - /* We mark the thread as terminated and as joined. */ - pd->tid = -1; + if (__builtin_expect (result == 0, 1)) + { + /* We mark the thread as terminated and as joined. */ + pd->tid = -1; - /* Store the return value if the caller is interested. */ - if (thread_return != NULL) - *thread_return = pd->result; + /* Store the return value if the caller is interested. */ + if (thread_return != NULL) + *thread_return = pd->result; - /* Free the TCB. */ - __free_tcb (pd); + /* Free the TCB. */ + __free_tcb (pd); + } - return 0; + return result; } diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c index 4d1bc28431..1ce5eaebef 100644 --- a/nptl/pthread_mutex_getprioceiling.c +++ b/nptl/pthread_mutex_getprioceiling.c @@ -18,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <errno.h> #include <pthreadP.h> @@ -26,7 +27,11 @@ pthread_mutex_getprioceiling (mutex, prioceiling) const pthread_mutex_t *mutex; int *prioceiling; { - *prioceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK) + if (__builtin_expect ((mutex->__data.__kind + & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0)) + return EINVAL; + + *prioceiling = (mutex->__data.__lock & PTHREAD_MUTEX_PRIO_CEILING_MASK) >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; return 0; diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c index 6ceca86052..96f1fb00f8 100644 --- a/nptl/pthread_mutex_init.c +++ b/nptl/pthread_mutex_init.c @@ -46,7 +46,6 @@ __pthread_mutex_init (mutex, mutexattr) imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr; /* Sanity checks. */ - // XXX For now we don't support priority protected mutexes. switch (__builtin_expect (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK, PTHREAD_PRIO_NONE @@ -72,7 +71,10 @@ __pthread_mutex_init (mutex, mutexattr) break; default: - return ENOTSUP; + /* XXX: For now we don't support robust priority protected mutexes. */ + if (imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) + return ENOTSUP; + break; } /* Clear the whole variable. */ @@ -100,15 +102,18 @@ __pthread_mutex_init (mutex, mutexattr) case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; - if (PTHREAD_MUTEX_PRIO_CEILING_MASK - == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) - mutex->__data.__kind |= (imutexattr->mutexkind - & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK); - else - mutex->__data.__kind |= ((imutexattr->mutexkind - & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) - >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT) - << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + + int ceiling = (imutexattr->mutexkind + & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) + >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT; + if (! ceiling) + { + if (__sched_fifo_min_prio == -1) + __init_sched_fifo_prio (); + if (ceiling < __sched_fifo_min_prio) + ceiling = __sched_fifo_min_prio; + } + mutex->__data.__lock = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; break; default: diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index a19c907695..52cc47f4cc 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -335,6 +335,90 @@ __pthread_mutex_lock (mutex) } break; + case PTHREAD_MUTEX_PP_RECURSIVE_NP: + case PTHREAD_MUTEX_PP_ERRORCHECK_NP: + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + return EDEADLK; + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + int oldprio = -1, ceilval; + do + { + int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) + >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + + if (__pthread_current_priority () > ceiling) + { + if (oldprio != -1) + __pthread_tpp_change_priority (oldprio, -1); + return EINVAL; + } + + retval = __pthread_tpp_change_priority (oldprio, ceiling); + if (retval) + return retval; + + ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + oldprio = ceiling; + + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, +#ifdef NO_INCR + ceilval | 2, +#else + ceilval | 1, +#endif + ceilval); + + if (oldval == ceilval) + break; + + do + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, + ceilval | 1); + + if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) + break; + + if (oldval != ceilval) + lll_futex_wait (&mutex->__data.__lock, ceilval | 2); + } + while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, ceilval) + != ceilval); + } + while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval); + + assert (mutex->__data.__owner == 0); + mutex->__data.__count = 1; + } + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c index 3271f8833a..cd13d1c14c 100644 --- a/nptl/pthread_mutex_setprioceiling.c +++ b/nptl/pthread_mutex_setprioceiling.c @@ -18,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <stdbool.h> #include <errno.h> #include <pthreadP.h> @@ -33,23 +34,83 @@ pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling) if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) return EINVAL; - if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0)) + if (__sched_fifo_min_prio == -1) + __init_sched_fifo_prio (); + + if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0) + || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0) + || __builtin_expect ((prioceiling + & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK + >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT)) + != prioceiling, 0)) return EINVAL; - /* XXX This needs to lock with TID, but shouldn't obey priority protect - protocol. */ - /* lll_xxx_mutex_lock (mutex->__data.__lock); */ + /* Check whether we already hold the mutex. */ + bool locked = false; + if (mutex->__data.__owner == THREAD_GETMEM (THREAD_SELF, tid)) + { + if (mutex->__data.__kind == PTHREAD_MUTEX_PP_ERRORCHECK_NP) + return EDEADLK; + + if (mutex->__data.__kind == PTHREAD_MUTEX_PP_RECURSIVE_NP) + locked = true; + } + + int oldval = mutex->__data.__lock; + if (! locked) + do + { + /* Need to lock the mutex, but without obeying the priority + protect protocol. */ + int ceilval = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK); + + oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 1, ceilval); + if (oldval == ceilval) + break; + + do + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, + ceilval | 1); + + if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) + break; + + if (oldval != ceilval) + lll_futex_wait (&mutex->__data.__lock, ceilval | 2); + } + while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, ceilval) + != ceilval); + + if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) + continue; + } + while (0); + + int oldprio = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) + >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + if (locked) + { + int ret = __pthread_tpp_change_priority (oldprio, prioceiling); + if (ret) + return ret; + } if (old_ceiling != NULL) - *old_ceiling = (mutex->__data.__kind & PTHREAD_MUTEX_PRIO_CEILING_MASK) - >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + *old_ceiling = oldprio; - int newkind = (mutex->__data.__kind & ~PTHREAD_MUTEX_PRIO_CEILING_MASK); - mutex->__data.__kind = newkind + int newlock = 0; + if (locked) + newlock = (mutex->__data.__lock & ~PTHREAD_MUTEX_PRIO_CEILING_MASK); + mutex->__data.__lock = newlock | (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT); + atomic_full_barrier (); - /* XXX This needs to unlock the above special kind of lock. */ - /* lll_xxx_mutex_unlock (mutex->__data.__lock); */ + lll_futex_wake (&mutex->__data.__lock, INT_MAX); return 0; } diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index dcff4f81a8..c8e6b8507a 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -340,6 +340,119 @@ pthread_mutex_timedlock (mutex, abstime) } break; + case PTHREAD_MUTEX_PP_RECURSIVE_NP: + case PTHREAD_MUTEX_PP_ERRORCHECK_NP: + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + return EDEADLK; + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + int oldprio = -1, ceilval; + do + { + int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) + >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + + if (__pthread_current_priority () > ceiling) + { + result = EINVAL; + failpp: + if (oldprio != -1) + __pthread_tpp_change_priority (oldprio, -1); + return result; + } + + result = __pthread_tpp_change_priority (oldprio, ceiling); + if (result) + return result; + + ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + oldprio = ceiling; + + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 1, ceilval); + + if (oldval == ceilval) + break; + + do + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, + ceilval | 1); + + if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) + break; + + if (oldval != ceilval) + { + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + { + result = EINVAL; + goto failpp; + } + + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) __gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + { + result = ETIMEDOUT; + goto failpp; + } + + lll_futex_timed_wait (&mutex->__data.__lock, + ceilval | 2, &rt); + } + } + while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 2, ceilval) + != ceilval); + } + while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval); + + assert (mutex->__data.__owner == 0); + mutex->__data.__count = 1; + } + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index f3a18569a1..94d519233b 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -297,6 +297,79 @@ __pthread_mutex_trylock (mutex) return 0; } + case PTHREAD_MUTEX_PP_RECURSIVE_NP: + case PTHREAD_MUTEX_PP_ERRORCHECK_NP: + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { + int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + + /* Check whether we already hold the mutex. */ + if (mutex->__data.__owner == id) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + return EDEADLK; + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { + /* Just bump the counter. */ + if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) + /* Overflow of the counter. */ + return EAGAIN; + + ++mutex->__data.__count; + + return 0; + } + } + + int oldprio = -1, ceilval; + do + { + int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) + >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + + if (__pthread_current_priority () > ceiling) + { + if (oldprio != -1) + __pthread_tpp_change_priority (oldprio, -1); + return EINVAL; + } + + int retval = __pthread_tpp_change_priority (oldprio, ceiling); + if (retval) + return retval; + + ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + oldprio = ceiling; + + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + ceilval | 1, ceilval); + + if (oldval == ceilval) + break; + } + while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval); + + if (oldval != ceilval) + { + __pthread_tpp_change_priority (oldprio, -1); + break; + } + + assert (mutex->__data.__owner == 0); + /* Record the ownership. */ + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + mutex->__data.__count = 1; + + return 0; + } + break; + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c index 2b5064fbac..33919d60af 100644 --- a/nptl/pthread_mutex_unlock.c +++ b/nptl/pthread_mutex_unlock.c @@ -202,6 +202,49 @@ __pthread_mutex_unlock_usercnt (mutex, decr) THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); break; + case PTHREAD_MUTEX_PP_RECURSIVE_NP: + /* Recursive mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) + return EPERM; + + if (--mutex->__data.__count != 0) + /* We still hold the mutex. */ + return 0; + goto pp; + + case PTHREAD_MUTEX_PP_ERRORCHECK_NP: + /* Error checking mutex. */ + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) + || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0) + return EPERM; + /* FALLTHROUGH */ + + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + /* Always reset the owner field. */ + pp: + mutex->__data.__owner = 0; + + if (decr) + /* One less user. */ + --mutex->__data.__nusers; + + /* Unlock. */ + int newval, oldval; + do + { + oldval = mutex->__data.__lock; + newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK; + } + while (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, + newval, oldval)); + + if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1) + lll_futex_wake (&mutex->__data.__lock, 1); + + int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; + return __pthread_tpp_change_priority (oldprio, -1); + default: /* Correct code cannot set any other type. */ return EINVAL; diff --git a/nptl/pthread_mutexattr_getprioceiling.c b/nptl/pthread_mutexattr_getprioceiling.c index da1beabf46..792e9a43d6 100644 --- a/nptl/pthread_mutexattr_getprioceiling.c +++ b/nptl/pthread_mutexattr_getprioceiling.c @@ -27,11 +27,22 @@ pthread_mutexattr_getprioceiling (attr, prioceiling) int *prioceiling; { const struct pthread_mutexattr *iattr; + int ceiling; iattr = (const struct pthread_mutexattr *) attr; - *prioceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) - >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT); + ceiling = ((iattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) + >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT); + + if (! ceiling) + { + if (__sched_fifo_min_prio == -1) + __init_sched_fifo_prio (); + if (ceiling < __sched_fifo_min_prio) + ceiling = __sched_fifo_min_prio; + } + + *prioceiling = ceiling; return 0; } diff --git a/nptl/pthread_mutexattr_setprioceiling.c b/nptl/pthread_mutexattr_setprioceiling.c index 6c15b46833..9b7874f739 100644 --- a/nptl/pthread_mutexattr_setprioceiling.c +++ b/nptl/pthread_mutexattr_setprioceiling.c @@ -27,7 +27,15 @@ pthread_mutexattr_setprioceiling (attr, prioceiling) pthread_mutexattr_t *attr; int prioceiling; { - if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0)) + if (__sched_fifo_min_prio == -1) + __init_sched_fifo_prio (); + + if (__builtin_expect (prioceiling < __sched_fifo_min_prio, 0) + || __builtin_expect (prioceiling > __sched_fifo_max_prio, 0) + || __builtin_expect ((prioceiling + & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK + >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT)) + != prioceiling, 0)) return EINVAL; struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr; diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c index 5889cc98a9..30ac6b3e89 100644 --- a/nptl/pthread_setschedparam.c +++ b/nptl/pthread_setschedparam.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -45,6 +45,19 @@ __pthread_setschedparam (threadid, policy, param) lll_lock (pd->lock); + struct sched_param p; + const struct sched_param *orig_param = param; + + /* If the thread should have higher priority because of some + PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority. */ + if (__builtin_expect (pd->tpp != NULL, 0) + && pd->tpp->priomax > param->sched_priority) + { + p = *param; + p.sched_priority = pd->tpp->priomax; + param = &p; + } + /* Try to set the scheduler information. */ if (__builtin_expect (__sched_setscheduler (pd->tid, policy, param) == -1, 0)) @@ -54,7 +67,7 @@ __pthread_setschedparam (threadid, policy, param) /* We succeeded changing the kernel information. Reflect this change in the thread descriptor. */ pd->schedpolicy = policy; - memcpy (&pd->schedparam, param, sizeof (struct sched_param)); + memcpy (&pd->schedparam, orig_param, sizeof (struct sched_param)); pd->flags |= ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET; } diff --git a/nptl/pthread_setschedprio.c b/nptl/pthread_setschedprio.c index 063f5232f5..4a71f6c7b3 100644 --- a/nptl/pthread_setschedprio.c +++ b/nptl/pthread_setschedprio.c @@ -47,6 +47,11 @@ pthread_setschedprio (threadid, prio) lll_lock (pd->lock); + /* If the thread should have higher priority because of some + PTHREAD_PRIO_PROTECT mutexes it holds, adjust the priority. */ + if (__builtin_expect (pd->tpp != NULL, 0) && pd->tpp->priomax > prio) + param.sched_priority = pd->tpp->priomax; + /* Try to set the scheduler information. */ if (__builtin_expect (sched_setparam (pd->tid, ¶m) == -1, 0)) result = errno; @@ -54,6 +59,7 @@ pthread_setschedprio (threadid, prio) { /* We succeeded changing the kernel information. Reflect this change in the thread descriptor. */ + param.sched_priority = prio; memcpy (&pd->schedparam, ¶m, sizeof (struct sched_param)); pd->flags |= ATTR_FLAG_SCHED_SET; } diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h index d8eced1f22..40160c54de 100644 --- a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -82,6 +82,10 @@ /* We support priority inheritence. */ #define _POSIX_THREAD_PRIO_INHERIT 200112L +/* We support priority protection, though only for non-robust + mutexes. */ +#define _POSIX_THREAD_PRIO_PROTECT 200112L + /* We support POSIX.1b semaphores. */ #define _POSIX_SEMAPHORES 200112L @@ -174,7 +178,4 @@ /* Typed memory objects are not available. */ #define _POSIX_TYPED_MEMORY_OBJECTS -1 -/* No support for priority protection so far. */ -#define _POSIX_THREAD_PRIO_PROTECT -1 - #endif /* posix_opt.h */ diff --git a/nptl/tpp.c b/nptl/tpp.c new file mode 100644 index 0000000000..367dd8162a --- /dev/null +++ b/nptl/tpp.c @@ -0,0 +1,172 @@ +/* Thread Priority Protect helpers. + Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <atomic.h> +#include <errno.h> +#include <pthreadP.h> +#include <sched.h> +#include <stdlib.h> + + +int __sched_fifo_min_prio = -1; +int __sched_fifo_max_prio = -1; + +void +__init_sched_fifo_prio (void) +{ + __sched_fifo_max_prio = sched_get_priority_max (SCHED_FIFO); + atomic_write_barrier (); + __sched_fifo_min_prio = sched_get_priority_min (SCHED_FIFO); +} + +int +__pthread_tpp_change_priority (int previous_prio, int new_prio) +{ + struct pthread *self = THREAD_SELF; + struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp); + + if (tpp == NULL) + { + if (__sched_fifo_min_prio == -1) + __init_sched_fifo_prio (); + + size_t size = sizeof *tpp; + size += (__sched_fifo_max_prio - __sched_fifo_min_prio + 1) + * sizeof (tpp->priomap[0]); + tpp = calloc (size, 1); + if (tpp == NULL) + return ENOMEM; + tpp->priomax = __sched_fifo_min_prio - 1; + THREAD_SETMEM (self, tpp, tpp); + } + + assert (new_prio == -1 + || (new_prio >= __sched_fifo_min_prio + && new_prio <= __sched_fifo_max_prio)); + assert (previous_prio == -1 + || (previous_prio >= __sched_fifo_min_prio + && previous_prio <= __sched_fifo_max_prio)); + + int priomax = tpp->priomax; + int newpriomax = priomax; + if (new_prio != -1) + { + if (tpp->priomap[new_prio - __sched_fifo_min_prio] + 1 == 0) + return EAGAIN; + ++tpp->priomap[new_prio - __sched_fifo_min_prio]; + if (new_prio > priomax) + newpriomax = new_prio; + } + + if (previous_prio != -1) + { + if (--tpp->priomap[previous_prio - __sched_fifo_min_prio] == 0 + && priomax == previous_prio + && previous_prio > new_prio) + { + int i; + for (i = previous_prio - 1; i >= __sched_fifo_min_prio; --i) + if (tpp->priomap[i - __sched_fifo_min_prio]) + break; + newpriomax = i; + } + } + + if (priomax == newpriomax) + return 0; + + lll_lock (self->lock); + + tpp->priomax = newpriomax; + + int result = 0; + + if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) + { + if (__sched_getparam (self->tid, &self->schedparam) != 0) + result = errno; + else + self->flags |= ATTR_FLAG_SCHED_SET; + } + + if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) + { + self->schedpolicy = __sched_getscheduler (self->tid); + if (self->schedpolicy == -1) + result = errno; + else + self->flags |= ATTR_FLAG_POLICY_SET; + } + + if (result == 0) + { + struct sched_param sp = self->schedparam; + if (sp.sched_priority < newpriomax || sp.sched_priority < priomax) + { + if (sp.sched_priority < newpriomax) + sp.sched_priority = newpriomax; + + if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0) + result = errno; + } + } + + lll_unlock (self->lock); + + return result; +} + +int +__pthread_current_priority (void) +{ + struct pthread *self = THREAD_SELF; + if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) + == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) + return self->schedparam.sched_priority; + + int result = 0; + + lll_lock (self->lock); + + if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) + { + if (__sched_getparam (self->tid, &self->schedparam) != 0) + result = -1; + else + self->flags |= ATTR_FLAG_SCHED_SET; + } + + if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) + { + self->schedpolicy = __sched_getscheduler (self->tid); + if (self->schedpolicy == -1) + result = -1; + else + self->flags |= ATTR_FLAG_POLICY_SET; + } + + if (result != -1) + result = self->schedparam.sched_priority; + + lll_unlock (self->lock); + + return result; +} diff --git a/nptl/tst-join5.c b/nptl/tst-join5.c index 589fac6b5f..db005f5b71 100644 --- a/nptl/tst-join5.c +++ b/nptl/tst-join5.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -21,120 +21,187 @@ #include <pthread.h> #include <stdio.h> #include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + + +#define wait_code() \ + do { \ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 }; \ + while (syscall (__NR_nanosleep, &ts, &ts) < 0) \ + /* nothing */; \ + } while (0) + + +#ifdef WAIT_IN_CHILD +static pthread_barrier_t b; +#endif static void * tf1 (void *arg) { - pthread_join ((pthread_t) arg, NULL); +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } - puts ("1st join returned"); + wait_code (); +#endif - return (void *) 1l; + pthread_join ((pthread_t) arg, NULL); + + exit (42); } static void * tf2 (void *arg) { - pthread_join ((pthread_t) arg, NULL); +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } - puts ("2nd join returned"); + wait_code (); +#endif + pthread_join ((pthread_t) arg, NULL); - return (void *) 1l; + exit (43); } static int do_test (void) { +#ifdef WAIT_IN_CHILD + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } +#endif + pthread_t th; int err = pthread_join (pthread_self (), NULL); if (err == 0) { puts ("1st circular join succeeded"); - exit (1); + return 1; } if (err != EDEADLK) { printf ("1st circular join %d, not EDEADLK\n", err); - exit (1); + return 1; } if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0) { puts ("1st create failed"); - exit (1); + return 1; } +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + if (pthread_cancel (th) != 0) { puts ("cannot cancel 1st thread"); - exit (1); + return 1; + } + +#ifdef WAIT_IN_CHILD + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + return 1; } +#endif void *r; err = pthread_join (th, &r); if (err != 0) { printf ("cannot join 1st thread: %d\n", err); - exit (1); + return 1; } if (r != PTHREAD_CANCELED) { puts ("1st thread not canceled"); - exit (1); + return 1; } err = pthread_join (pthread_self (), NULL); if (err == 0) { puts ("2nd circular join succeeded"); - exit (1); + return 1; } if (err != EDEADLK) { printf ("2nd circular join %d, not EDEADLK\n", err); - exit (1); + return 1; } if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0) { puts ("2nd create failed"); - exit (1); + return 1; } +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + if (pthread_cancel (th) != 0) { puts ("cannot cancel 2nd thread"); - exit (1); + return 1; } +#ifdef WAIT_IN_CHILD + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + return 1; + } +#endif + if (pthread_join (th, &r) != 0) { puts ("cannot join 2nd thread"); - exit (1); + return 1; } if (r != PTHREAD_CANCELED) { puts ("2nd thread not canceled"); - exit (1); + return 1; } err = pthread_join (pthread_self (), NULL); if (err == 0) { - puts ("2nd circular join succeeded"); - exit (1); + puts ("3rd circular join succeeded"); + return 1; } if (err != EDEADLK) { - printf ("2nd circular join %d, not EDEADLK\n", err); - exit (1); + printf ("3rd circular join %d, not EDEADLK\n", err); + return 1; } - exit (0); + return 0; } #define TEST_FUNCTION do_test () diff --git a/nptl/tst-join6.c b/nptl/tst-join6.c new file mode 100644 index 0000000000..0c9e7c056b --- /dev/null +++ b/nptl/tst-join6.c @@ -0,0 +1,2 @@ +#define WAIT_IN_CHILD 1 +#include "tst-join5.c" diff --git a/nptl/tst-mutex1.c b/nptl/tst-mutex1.c index c3ef5b2b51..9453f04918 100644 --- a/nptl/tst-mutex1.c +++ b/nptl/tst-mutex1.c @@ -71,5 +71,7 @@ do_test (void) return 0; } -#define TEST_FUNCTION do_test () +#ifndef TEST_FUNCTION +# define TEST_FUNCTION do_test () +#endif #include "../test-skeleton.c" diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c index e5698c3eb0..de64bdb435 100644 --- a/nptl/tst-mutex6.c +++ b/nptl/tst-mutex6.c @@ -69,5 +69,7 @@ do_test (void) } #define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () +#ifndef TEST_FUNCTION +# define TEST_FUNCTION do_test () +#endif #include "../test-skeleton.c" diff --git a/nptl/tst-mutexpp1.c b/nptl/tst-mutexpp1.c new file mode 100644 index 0000000000..9b7d7fe263 --- /dev/null +++ b/nptl/tst-mutexpp1.c @@ -0,0 +1,45 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "tst-tpp.h" + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + init_tpp_test (); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } + + if (pthread_mutexattr_setprioceiling (&a, 6) != 0) + { + puts ("mutexattr_setprioceiling failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + +static int do_test (void); + +static int +do_test_wrapper (void) +{ + init_tpp_test (); + return do_test (); +} +#define TEST_FUNCTION do_test_wrapper () + +#define ATTR &a +#include "tst-mutex1.c" diff --git a/nptl/tst-mutexpp10.c b/nptl/tst-mutexpp10.c new file mode 100644 index 0000000000..78281a4d3b --- /dev/null +++ b/nptl/tst-mutexpp10.c @@ -0,0 +1,334 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <limits.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "tst-tpp.h" + +static int +do_test (void) +{ + int ret = 0; + + init_tpp_test (); + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma)) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_PROTECT)) + { + puts ("mutexattr_setprotocol failed"); + return 1; + } + + int prioceiling; + if (pthread_mutexattr_getprioceiling (&ma, &prioceiling)) + { + puts ("mutexattr_getprioceiling failed"); + return 1; + } + + if (prioceiling < fifo_min || prioceiling > fifo_max) + { + printf ("prioceiling %d not in %d..%d range\n", + prioceiling, fifo_min, fifo_max); + return 1; + } + + if (fifo_max < INT_MAX + && pthread_mutexattr_setprioceiling (&ma, fifo_max + 1) != EINVAL) + { + printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n", + fifo_max + 1); + return 1; + } + + if (fifo_min > 0 + && pthread_mutexattr_setprioceiling (&ma, fifo_min - 1) != EINVAL) + { + printf ("mutexattr_setprioceiling %d did not fail with EINVAL\n", + fifo_min - 1); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, fifo_min)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, fifo_max)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 6)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutexattr_getprioceiling (&ma, &prioceiling)) + { + puts ("mutexattr_getprioceiling failed"); + return 1; + } + + if (prioceiling != 6) + { + printf ("mutexattr_getprioceiling returned %d != 6\n", + prioceiling); + return 1; + } + + pthread_mutex_t m1, m2, m3; + int e = pthread_mutex_init (&m1, &ma); + if (e == ENOTSUP) + { + puts ("cannot support selected type of mutexes"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 8)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutex_init (&m2, &ma)) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_setprioceiling (&ma, 5)) + { + puts ("mutexattr_setprioceiling failed"); + return 1; + } + + if (pthread_mutex_init (&m3, &ma)) + { + puts ("mutex_init failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 4); + + if (pthread_mutex_lock (&m1) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 6); + + if (pthread_mutex_trylock (&m2) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_lock (&m3) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_unlock (&m2) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 6); + + if (pthread_mutex_unlock (&m1) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_lock (&m2) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 8); + + if (pthread_mutex_unlock (&m2) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_getprioceiling (&m1, &prioceiling)) + { + puts ("mutex_getprioceiling m1 failed"); + return 1; + } + else if (prioceiling != 6) + { + printf ("unexpected m1 prioceiling %d != 6\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m2, &prioceiling)) + { + puts ("mutex_getprioceiling m2 failed"); + return 1; + } + else if (prioceiling != 8) + { + printf ("unexpected m2 prioceiling %d != 8\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m3, &prioceiling)) + { + puts ("mutex_getprioceiling m3 failed"); + return 1; + } + else if (prioceiling != 5) + { + printf ("unexpected m3 prioceiling %d != 5\n", prioceiling); + return 1; + } + + if (pthread_mutex_setprioceiling (&m1, 7, &prioceiling)) + { + printf ("mutex_setprioceiling failed"); + return 1; + } + else if (prioceiling != 6) + { + printf ("unexpected m1 old prioceiling %d != 6\n", prioceiling); + return 1; + } + + if (pthread_mutex_getprioceiling (&m1, &prioceiling)) + { + puts ("mutex_getprioceiling m1 failed"); + return 1; + } + else if (prioceiling != 7) + { + printf ("unexpected m1 prioceiling %d != 7\n", prioceiling); + return 1; + } + + CHECK_TPP_PRIORITY (4, 5); + + if (pthread_mutex_unlock (&m3) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 4); + + if (pthread_mutex_trylock (&m1) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (4, 7); + + struct sched_param sp; + memset (&sp, 0, sizeof (sp)); + sp.sched_priority = 8; + if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp)) + { + puts ("cannot set scheduling params"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_unlock (&m1) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_lock (&m3) != EINVAL) + { + puts ("pthread_mutex_lock didn't fail with EINVAL"); + return 1; + } + + CHECK_TPP_PRIORITY (8, 8); + + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m3) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-mutexpp6.c b/nptl/tst-mutexpp6.c new file mode 100644 index 0000000000..2ddf6b45c6 --- /dev/null +++ b/nptl/tst-mutexpp6.c @@ -0,0 +1,45 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "tst-tpp.h" + +static pthread_mutexattr_t a; + +static void +prepare (void) +{ + init_tpp_test (); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_PROTECT) != 0) + { + puts ("mutexattr_setprotocol failed"); + exit (1); + } + + if (pthread_mutexattr_setprioceiling (&a, 6) != 0) + { + puts ("mutexattr_setprioceiling failed"); + exit (1); + } +} +#define PREPARE(argc, argv) prepare () + +static int do_test (void); + +static int +do_test_wrapper (void) +{ + init_tpp_test (); + return do_test (); +} +#define TEST_FUNCTION do_test_wrapper () + +#define ATTR &a +#include "tst-mutex6.c" diff --git a/nptl/tst-tpp.h b/nptl/tst-tpp.h new file mode 100644 index 0000000000..c5844b26dd --- /dev/null +++ b/nptl/tst-tpp.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> + +/* This test is Linux specific. */ +#define CHECK_TPP_PRIORITY(normal, boosted) \ + do \ + { \ + pid_t tid = syscall (__NR_gettid); \ + \ + struct sched_param cep_sp; \ + int cep_policy; \ + if (pthread_getschedparam (pthread_self (), &cep_policy, \ + &cep_sp) != 0) \ + { \ + puts ("getschedparam failed"); \ + ret = 1; \ + } \ + else if (cep_sp.sched_priority != (normal)) \ + { \ + printf ("unexpected priority %d != %d\n", \ + cep_sp.sched_priority, (normal)); \ + } \ + if (syscall (__NR_sched_getparam, tid, &cep_sp) == 0 \ + && cep_sp.sched_priority != (boosted)) \ + { \ + printf ("unexpected boosted priority %d != %d\n", \ + cep_sp.sched_priority, (boosted)); \ + ret = 1; \ + } \ + } \ + while (0) + +int fifo_min, fifo_max; + +void +init_tpp_test (void) +{ + fifo_min = sched_get_priority_min (SCHED_FIFO); + if (fifo_min < 0) + { + printf ("couldn't get min priority for SCHED_FIFO: %m\n"); + exit (1); + } + + fifo_max = sched_get_priority_max (SCHED_FIFO); + if (fifo_max < 0) + { + printf ("couldn't get max priority for SCHED_FIFO: %m\n"); + exit (1); + } + + if (fifo_min > 4 || fifo_max < 10) + { + printf ("%d..%d SCHED_FIFO priority interval not suitable for this test\n", + fifo_min, fifo_max); + exit (0); + } + + struct sched_param sp; + memset (&sp, 0, sizeof (sp)); + sp.sched_priority = 4; + int e = pthread_setschedparam (pthread_self (), SCHED_FIFO, &sp); + if (e != 0) + { + errno = e; + printf ("cannot set scheduling params: %m\n"); + exit (0); + } +} diff --git a/sysdeps/generic/stdint.h b/sysdeps/generic/stdint.h index c860030409..2c729ad2f1 100644 --- a/sysdeps/generic/stdint.h +++ b/sysdeps/generic/stdint.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 1997,1998,1999,2000,2001,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -297,8 +297,8 @@ typedef unsigned long long int uintmax_t; # endif /* Unsigned. */ -# define UINT8_C(c) c ## U -# define UINT16_C(c) c ## U +# define UINT8_C(c) c +# define UINT16_C(c) c # define UINT32_C(c) c ## U # if __WORDSIZE == 64 # define UINT64_C(c) c ## UL diff --git a/sysdeps/powerpc/powerpc32/dl-trampoline.S b/sysdeps/powerpc/powerpc32/dl-trampoline.S index 392c109d4c..6a158c3fff 100644 --- a/sysdeps/powerpc/powerpc32/dl-trampoline.S +++ b/sysdeps/powerpc/powerpc32/dl-trampoline.S @@ -40,8 +40,9 @@ _dl_runtime_resolve: mflr r0 # We also need to save some of the condition register fields stw r7,32(r1) - stw r0,68(r1) - cfi_offset (lr, 4) + # Don't clobber the caller's LRSAVE, it is needed by _mcount. + stw r0,48(r1) + cfi_offset (lr, -16) stw r8,36(r1) mfcr r0 stw r9,40(r1) @@ -51,7 +52,7 @@ _dl_runtime_resolve: # 'fixup' returns the address we want to branch to. mtctr r3 # Put the registers back... - lwz r0,68(r1) + lwz r0,48(r1) lwz r10,44(r1) lwz r9,40(r1) mtlr r0 @@ -128,8 +129,9 @@ _dl_prof_resolve: mflr r5 # We also need to save some of the condition register fields. stw r7,32(r1) - stw r5,324(r1) - cfi_offset (lr, 4) + # Don't clobber the caller's LRSAVE, it is needed by _mcount. + stw r5,308(r1) + cfi_offset (lr, -12) stw r8,36(r1) mfcr r0 stw r9,40(r1) @@ -154,7 +156,7 @@ _dl_prof_resolve: # 'fixup' returns the address we want to branch to. mtctr r3 # Put the registers back... - lwz r0,324(r1) + lwz r0,308(r1) lwz r10,44(r1) lwz r9,40(r1) mtlr r0 diff --git a/sysdeps/unix/clock_settime.c b/sysdeps/unix/clock_settime.c index 0194999b36..a93be6349b 100644 --- a/sysdeps/unix/clock_settime.c +++ b/sysdeps/unix/clock_settime.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1999-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -36,6 +36,43 @@ extern void __pthread_clock_settime (clockid_t clock_id, hp_timing_t offset) #endif +#if HP_TIMING_AVAIL +static int +hp_timing_settime (clockid_t clock_id, const struct timespec *tp) +{ + hp_timing_t tsc; + hp_timing_t usertime; + + /* First thing is to get the current time. */ + HP_TIMING_NOW (tsc); + + if (__builtin_expect (freq == 0, 0)) + { + /* This can only happen if we haven't initialized the `freq' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should lead + to the same result. */ + freq = __get_clockfreq (); + if (__builtin_expect (freq == 0, 0)) + /* Something went wrong. */ + return -1; + } + + /* Convert the user-provided time into CPU ticks. */ + usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull; + + /* Determine the offset and use it as the new base value. */ + if (clock_id == CLOCK_PROCESS_CPUTIME_ID + || __pthread_clock_settime == NULL) + GL(dl_cpuclock_offset) = tsc - usertime; + else + __pthread_clock_settime (clock_id, tsc - usertime); + + return 0; +} +#endif + + /* Set CLOCK to value TP. */ int clock_settime (clockid_t clock_id, const struct timespec *tp) @@ -70,55 +107,22 @@ clock_settime (clockid_t clock_id, const struct timespec *tp) #endif default: -#if HP_TIMING_AVAIL - if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) - != CLOCK_THREAD_CPUTIME_ID) +#ifdef SYSDEP_SETTIME_CPU + SYSDEP_SETTIME_CPU; #endif +#ifndef HANDLED_CPUTIME +# if HP_TIMING_AVAIL + if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID + || CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID) + retval = hp_timing_settime (clock_id, tp); + else +# endif { __set_errno (EINVAL); retval = -1; - break; } - -#if HP_TIMING_AVAIL - /* FALLTHROUGH. */ - case CLOCK_PROCESS_CPUTIME_ID: - { - hp_timing_t tsc; - hp_timing_t usertime; - - /* First thing is to get the current time. */ - HP_TIMING_NOW (tsc); - - if (__builtin_expect (freq == 0, 0)) - { - /* This can only happen if we haven't initialized the `freq' - variable yet. Do this now. We don't have to protect this - code against multiple execution since all of them should - lead to the same result. */ - freq = __get_clockfreq (); - if (__builtin_expect (freq == 0, 0)) - { - /* Something went wrong. */ - retval = -1; - break; - } - } - - /* Convert the user-provided time into CPU ticks. */ - usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull; - - /* Determine the offset and use it as the new base value. */ - if (clock_id == CLOCK_PROCESS_CPUTIME_ID - || __pthread_clock_settime == NULL) - GL(dl_cpuclock_offset) = tsc - usertime; - else - __pthread_clock_settime (clock_id, tsc - usertime); - - retval = 0; - } - break; #endif + break; } return retval; diff --git a/sysdeps/unix/nice.c b/sysdeps/unix/nice.c index 1dd57fa5c0..6e75b0327b 100644 --- a/sysdeps/unix/nice.c +++ b/sysdeps/unix/nice.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1992, 1996, 1997, 2001, 2002 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1996, 1997, 2001, 2002, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -47,9 +48,11 @@ nice (int incr) else if (prio >= PRIO_MAX) prio = PRIO_MAX - 1; result = setpriority (PRIO_PROCESS, 0, prio); - if (result != -1) - return getpriority (PRIO_PROCESS, 0); - else - return -1; - + if (result == -1) + { + if (errno == EACCES) + errno = EPERM; + return -1; + } + return getpriority (PRIO_PROCESS, 0); } diff --git a/sysdeps/unix/sysv/linux/clock_settime.c b/sysdeps/unix/sysv/linux/clock_settime.c index 31ba0225fb..731b7be7b8 100644 --- a/sysdeps/unix/sysv/linux/clock_settime.c +++ b/sysdeps/unix/sysv/linux/clock_settime.c @@ -16,10 +16,65 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <errno.h> #include <sysdep.h> +#include "kernel-posix-cpu-timers.h" #include <kernel-features.h> +#ifndef HAVE_CLOCK_GETTIME_VSYSCALL +# undef INTERNAL_VSYSCALL +# define INTERNAL_VSYSCALL INTERNAL_SYSCALL +# undef INLINE_VSYSCALL +# define INLINE_VSYSCALL INLINE_SYSCALL +#else +# include <bits/libc-vdso.h> +#endif + +#if __ASSUME_POSIX_CPU_TIMERS <= 0 && defined __NR_clock_settime +extern int __libc_missing_posix_timers attribute_hidden; +extern int __libc_missing_posix_cpu_timers attribute_hidden; + +static int +maybe_syscall_settime_cpu (clockid_t clock_id, const struct timespec *tp) +{ + int e = EINVAL; + + if (!__libc_missing_posix_cpu_timers) + { + INTERNAL_SYSCALL_DECL (err); + int r = INTERNAL_VSYSCALL (clock_settime, err, 2, clock_id, tp); + if (!INTERNAL_SYSCALL_ERROR_P (r, err)) + return 0; + + e = INTERNAL_SYSCALL_ERRNO (r, err); +# ifndef __ASSUME_POSIX_TIMERS + if (e == ENOSYS) + { + __libc_missing_posix_timers = 1; + __libc_missing_posix_cpu_timers = 1; + e = EINVAL; + } + else +# endif + { + if (e == EINVAL) + { + /* Check whether the kernel supports CPU clocks at all. + If not, record it for the future. */ + r = INTERNAL_VSYSCALL (clock_getres, err, 2, + MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), + NULL); + if (INTERNAL_SYSCALL_ERROR_P (r, err)) + __libc_missing_posix_cpu_timers = 1; + } + } + } + + return e; +} +#endif + #ifdef __ASSUME_POSIX_TIMERS /* This means the REALTIME clock is definitely supported in the @@ -73,4 +128,22 @@ extern int __libc_missing_posix_timers attribute_hidden; # define HANDLED_REALTIME 1 #endif +#if __ASSUME_POSIX_CPU_TIMERS > 0 +# define HANDLED_CPUTIME 1 +# define SYSDEP_SETTIME_CPU \ + retval = INLINE_SYSCALL (clock_settime, 2, clock_id, tp) +#elif defined __NR_clock_settime +# define SYSDEP_SETTIME_CPU \ + retval = maybe_syscall_settime_cpu (clock_id, tp); \ + if (retval == 0) \ + break; \ + if (retval != EINVAL || !__libc_missing_posix_cpu_timers) \ + { \ + __set_errno (retval); \ + retval = -1; \ + break; \ + } \ + do { } while (0) +#endif + #include <sysdeps/unix/clock_settime.c> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/pause.c b/sysdeps/unix/sysv/linux/sparc/sparc64/pause.c index 40fab28d47..2ec5bd39ad 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/pause.c +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/pause.c @@ -1,47 +1 @@ -/* pause -- suspend the process until a signal arrives. POSIX.1 version. - Copyright (C) 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include <errno.h> -#include <signal.h> -#include <unistd.h> -#include <sysdep-cancel.h> - -#include <sysdep.h> -#include <sys/syscall.h> -#include <bp-checks.h> - -/* Suspend the process until a signal arrives. - This always returns -1 and sets errno to EINTR. */ -int -__libc_pause (void) -{ - sigset_t set; - - __sigemptyset (&set); - INLINE_SYSCALL (rt_sigprocmask, 4, SIG_BLOCK, CHECK_SIGSET (NULL), - CHECK_SIGSET_NULL_OK (&set), _NSIG / 8); - - /* pause is a cancellation point, but so is sigsuspend. - So no need for anything special here. */ - - return __sigsuspend (&set); -} -weak_alias (__libc_pause, pause) - -LIBC_CANCEL_HANDLED (); /* sigsuspend handles our cancellation. */ +#include <sysdeps/posix/pause.c> |