+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.
-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.
* Support for priority inheritance mutexes added by Jakub Jelinek and
Ulrich Drepper.
+* Support for priority protected mutexes added by Jakub Jelinek.
+
\f
Version 2.4
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
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.
--- /dev/null
+#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"
--- /dev/null
+#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"
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);
-/* 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
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;
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 */
{
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)
}
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);
- 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;
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;
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;
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;
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;
-/* 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
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;
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
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 */
{
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));
}
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);
return c;
}
+
_IO_wint_t
_IO_wstr_underflow (fp)
_IO_FILE *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;
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);
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);
-/* 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.
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;
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;
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;
{
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++)
* (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;
++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));
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);
+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]
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 \
--- /dev/null
+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
"<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>";/
"<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)
-/* 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.
{
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;
}
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;
}
/* 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
{
/* The string cannot be converted. */
if (use_malloc)
- free (wmessage);
+ {
+ free (wmessage);
+ use_malloc = false;
+ }
wmessage = (wchar_t *) L"???";
}
#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);
+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]
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 \
};
+/* Data strcture used to handle thread priority protection. */
+struct priority_protection_data
+{
+ int priomax;
+ unsigned int priomap[];
+};
+
+
/* Thread descriptor data structure. */
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;
= 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 \
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;
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. */
-/* 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.
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);
}
pthread_t threadid;
void **thread_return;
{
- struct pthread *self;
struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */
/* 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
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. */
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;
}
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <errno.h>
#include <pthreadP.h>
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;
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
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. */
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:
}
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;
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <stdbool.h>
#include <errno.h>
#include <pthreadP.h>
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;
}
}
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;
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;
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;
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;
}
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;
-/* 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.
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))
/* 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;
}
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;
{
/* 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;
}
/* 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
/* 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 */
--- /dev/null
+/* 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;
+}
-/* 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.
#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 ()
--- /dev/null
+#define WAIT_IN_CHILD 1
+#include "tst-join5.c"
return 0;
}
-#define TEST_FUNCTION do_test ()
+#ifndef TEST_FUNCTION
+# define TEST_FUNCTION do_test ()
+#endif
#include "../test-skeleton.c"
}
#define EXPECTED_SIGNAL SIGALRM
-#define TEST_FUNCTION do_test ()
+#ifndef TEST_FUNCTION
+# define TEST_FUNCTION do_test ()
+#endif
#include "../test-skeleton.c"
--- /dev/null
+#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"
--- /dev/null
+/* 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"
--- /dev/null
+#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"
--- /dev/null
+/* 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);
+ }
+}
-/* 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
# 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
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)
# '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
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)
# '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
-/* 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
#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)
#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;
-/* 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
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);
}
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
# 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>
-/* 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>