summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/aio/aio.c23
-rw-r--r--src/exit/at_quick_exit.c2
-rw-r--r--src/exit/atexit.c7
-rw-r--r--src/include/stdlib.h6
-rw-r--r--src/internal/fork_impl.h19
-rw-r--r--src/internal/locale_impl.h2
-rw-r--r--src/internal/pthread_impl.h3
-rw-r--r--src/ldso/dlerror.c20
-rw-r--r--src/legacy/lutimes.c12
-rw-r--r--src/locale/dcngettext.c10
-rw-r--r--src/locale/freelocale.c5
-rw-r--r--src/locale/locale_map.c20
-rw-r--r--src/locale/newlocale.c32
-rw-r--r--src/locale/setlocale.c11
-rw-r--r--src/malloc/free.c6
-rw-r--r--src/malloc/libc_calloc.c4
-rw-r--r--src/malloc/lite_malloc.c19
-rw-r--r--src/malloc/mallocng/glue.h18
-rw-r--r--src/malloc/mallocng/malloc_usable_size.c1
-rw-r--r--src/malloc/oldmalloc/malloc.c23
-rw-r--r--src/malloc/realloc.c6
-rw-r--r--src/malloc/reallocarray.c13
-rw-r--r--src/math/arm/fabs.c2
-rw-r--r--src/math/arm/sqrt.c2
-rw-r--r--src/misc/ioctl.c18
-rw-r--r--src/misc/realpath.c159
-rw-r--r--src/misc/syslog.c2
-rw-r--r--src/multibyte/wcsnrtombs.c46
-rw-r--r--src/prng/random.c2
-rw-r--r--src/process/fork.c70
-rw-r--r--src/stdio/ofl.c2
-rw-r--r--src/string/strstr.c2
-rw-r--r--src/thread/pthread_attr_get.c2
-rw-r--r--src/thread/pthread_cond_timedwait.c2
-rw-r--r--src/thread/pthread_create.c25
-rw-r--r--src/thread/pthread_mutex_destroy.c6
-rw-r--r--src/thread/s390x/clone.s6
-rw-r--r--src/thread/s390x/syscall_cp.s2
-rw-r--r--src/thread/sem_open.c7
-rw-r--r--src/thread/vmlock.c2
-rw-r--r--src/time/__tz.c9
-rw-r--r--src/unistd/readlink.c11
-rw-r--r--src/unistd/readlinkat.c9
43 files changed, 523 insertions, 125 deletions
diff --git a/src/aio/aio.c b/src/aio/aio.c
index b488e3d6..a1a3e791 100644
--- a/src/aio/aio.c
+++ b/src/aio/aio.c
@@ -11,6 +11,11 @@
#include "pthread_impl.h"
#include "aio_impl.h"
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc __libc_realloc
+#define free __libc_free
+
/* The following is a threads-based implementation of AIO with minimal
* dependence on implementation details. Most synchronization is
* performed with pthread primitives, but atomics and futex operations
@@ -71,6 +76,10 @@ static struct aio_queue *****map;
static volatile int aio_fd_cnt;
volatile int __aio_fut;
+static size_t io_thread_stack_size;
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+
static struct aio_queue *__aio_get_queue(int fd, int need)
{
if (fd < 0) {
@@ -85,6 +94,10 @@ static struct aio_queue *__aio_get_queue(int fd, int need)
pthread_rwlock_unlock(&maplock);
if (fcntl(fd, F_GETFD) < 0) return 0;
pthread_rwlock_wrlock(&maplock);
+ if (!io_thread_stack_size) {
+ unsigned long val = __getauxval(AT_MINSIGSTKSZ);
+ io_thread_stack_size = MAX(MINSIGSTKSZ+2048, val+512);
+ }
if (!map) map = calloc(sizeof *map, (-1U/2+1)>>24);
if (!map) goto out;
if (!map[a]) map[a] = calloc(sizeof **map, 256);
@@ -260,15 +273,6 @@ static void *io_thread_func(void *ctx)
return 0;
}
-static size_t io_thread_stack_size = MINSIGSTKSZ+2048;
-static pthread_once_t init_stack_size_once;
-
-static void init_stack_size()
-{
- unsigned long val = __getauxval(AT_MINSIGSTKSZ);
- if (val > MINSIGSTKSZ) io_thread_stack_size = val + 512;
-}
-
static int submit(struct aiocb *cb, int op)
{
int ret = 0;
@@ -294,7 +298,6 @@ static int submit(struct aiocb *cb, int op)
else
pthread_attr_init(&a);
} else {
- pthread_once(&init_stack_size_once, init_stack_size);
pthread_attr_init(&a);
pthread_attr_setstacksize(&a, io_thread_stack_size);
pthread_attr_setguardsize(&a, 0);
diff --git a/src/exit/at_quick_exit.c b/src/exit/at_quick_exit.c
index d3ce6522..e4b5d78d 100644
--- a/src/exit/at_quick_exit.c
+++ b/src/exit/at_quick_exit.c
@@ -1,12 +1,14 @@
#include <stdlib.h>
#include "libc.h"
#include "lock.h"
+#include "fork_impl.h"
#define COUNT 32
static void (*funcs[COUNT])(void);
static int count;
static volatile int lock[1];
+volatile int *const __at_quick_exit_lockptr = lock;
void __funcs_on_quick_exit()
{
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
index 160d277a..854e9fdd 100644
--- a/src/exit/atexit.c
+++ b/src/exit/atexit.c
@@ -2,6 +2,12 @@
#include <stdint.h>
#include "libc.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc undef
+#define free undef
/* Ensure that at least 32 atexit handlers can be registered without malloc */
#define COUNT 32
@@ -15,6 +21,7 @@ static struct fl
static int slot;
static volatile int lock[1];
+volatile int *const __atexit_lockptr = lock;
void __funcs_on_exit()
{
diff --git a/src/include/stdlib.h b/src/include/stdlib.h
index d38a5417..e9da2015 100644
--- a/src/include/stdlib.h
+++ b/src/include/stdlib.h
@@ -9,4 +9,10 @@ hidden int __mkostemps(char *, int, int);
hidden int __ptsname_r(int, char *, size_t);
hidden char *__randname(char *);
+hidden void *__libc_malloc(size_t);
+hidden void *__libc_malloc_impl(size_t);
+hidden void *__libc_calloc(size_t, size_t);
+hidden void *__libc_realloc(void *, size_t);
+hidden void __libc_free(void *);
+
#endif
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h
new file mode 100644
index 00000000..5892c13b
--- /dev/null
+++ b/src/internal/fork_impl.h
@@ -0,0 +1,19 @@
+#include <features.h>
+
+extern hidden volatile int *const __at_quick_exit_lockptr;
+extern hidden volatile int *const __atexit_lockptr;
+extern hidden volatile int *const __dlerror_lockptr;
+extern hidden volatile int *const __gettext_lockptr;
+extern hidden volatile int *const __locale_lockptr;
+extern hidden volatile int *const __random_lockptr;
+extern hidden volatile int *const __sem_open_lockptr;
+extern hidden volatile int *const __stdio_ofl_lockptr;
+extern hidden volatile int *const __syslog_lockptr;
+extern hidden volatile int *const __timezone_lockptr;
+
+extern hidden volatile int *const __bump_lockptr;
+
+extern hidden volatile int *const __vmlock_lockptr;
+
+hidden void __malloc_atfork(int);
+hidden void __ldso_atfork(int);
diff --git a/src/internal/locale_impl.h b/src/internal/locale_impl.h
index 741a71c4..4431a92e 100644
--- a/src/internal/locale_impl.h
+++ b/src/internal/locale_impl.h
@@ -15,6 +15,8 @@ struct __locale_map {
const struct __locale_map *next;
};
+extern hidden volatile int __locale_lock[1];
+
extern hidden const struct __locale_map __c_dot_utf8;
extern hidden const struct __locale_struct __c_locale;
extern hidden const struct __locale_struct __c_dot_utf8_locale;
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index 1322a6a8..de2b9d8b 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -68,7 +68,8 @@ struct pthread {
};
enum {
- DT_EXITING = 0,
+ DT_EXITED = 0,
+ DT_EXITING,
DT_JOINABLE,
DT_DETACHED,
};
diff --git a/src/ldso/dlerror.c b/src/ldso/dlerror.c
index 3fcc7779..afe59253 100644
--- a/src/ldso/dlerror.c
+++ b/src/ldso/dlerror.c
@@ -4,6 +4,12 @@
#include "pthread_impl.h"
#include "dynlink.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc __libc_realloc
+#define free __libc_free
char *dlerror()
{
@@ -19,6 +25,7 @@ char *dlerror()
static volatile int freebuf_queue_lock[1];
static void **freebuf_queue;
+volatile int *const __dlerror_lockptr = freebuf_queue_lock;
void __dl_thread_cleanup(void)
{
@@ -35,13 +42,16 @@ void __dl_thread_cleanup(void)
hidden void __dl_vseterr(const char *fmt, va_list ap)
{
LOCK(freebuf_queue_lock);
- while (freebuf_queue) {
- void **p = freebuf_queue;
- freebuf_queue = *p;
- free(p);
- }
+ void **q = freebuf_queue;
+ freebuf_queue = 0;
UNLOCK(freebuf_queue_lock);
+ while (q) {
+ void **p = *q;
+ free(q);
+ q = p;
+ }
+
va_list ap2;
va_copy(ap2, ap);
pthread_t self = __pthread_self();
diff --git a/src/legacy/lutimes.c b/src/legacy/lutimes.c
index 2e5502d1..dd465923 100644
--- a/src/legacy/lutimes.c
+++ b/src/legacy/lutimes.c
@@ -6,9 +6,11 @@
int lutimes(const char *filename, const struct timeval tv[2])
{
struct timespec times[2];
- times[0].tv_sec = tv[0].tv_sec;
- times[0].tv_nsec = tv[0].tv_usec * 1000;
- times[1].tv_sec = tv[1].tv_sec;
- times[1].tv_nsec = tv[1].tv_usec * 1000;
- return utimensat(AT_FDCWD, filename, times, AT_SYMLINK_NOFOLLOW);
+ if (tv) {
+ times[0].tv_sec = tv[0].tv_sec;
+ times[0].tv_nsec = tv[0].tv_usec * 1000;
+ times[1].tv_sec = tv[1].tv_sec;
+ times[1].tv_nsec = tv[1].tv_usec * 1000;
+ }
+ return utimensat(AT_FDCWD, filename, tv ? times : 0, AT_SYMLINK_NOFOLLOW);
}
diff --git a/src/locale/dcngettext.c b/src/locale/dcngettext.c
index 4c304393..d1e6c6d1 100644
--- a/src/locale/dcngettext.c
+++ b/src/locale/dcngettext.c
@@ -10,6 +10,12 @@
#include "atomic.h"
#include "pleval.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc undef
+#define free undef
struct binding {
struct binding *next;
@@ -34,9 +40,11 @@ static char *gettextdir(const char *domainname, size_t *dirlen)
return 0;
}
+static volatile int lock[1];
+volatile int *const __gettext_lockptr = lock;
+
char *bindtextdomain(const char *domainname, const char *dirname)
{
- static volatile int lock[1];
struct binding *p, *q;
if (!domainname) return 0;
diff --git a/src/locale/freelocale.c b/src/locale/freelocale.c
index 802b8bfe..385d1206 100644
--- a/src/locale/freelocale.c
+++ b/src/locale/freelocale.c
@@ -1,6 +1,11 @@
#include <stdlib.h>
#include "locale_impl.h"
+#define malloc undef
+#define calloc undef
+#define realloc undef
+#define free __libc_free
+
void freelocale(locale_t l)
{
if (__loc_is_allocated(l)) free(l);
diff --git a/src/locale/locale_map.c b/src/locale/locale_map.c
index e7eede62..da61f7fc 100644
--- a/src/locale/locale_map.c
+++ b/src/locale/locale_map.c
@@ -1,9 +1,16 @@
#include <locale.h>
#include <string.h>
#include <sys/mman.h>
+#include <stdlib.h>
#include "locale_impl.h"
#include "libc.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
{
@@ -21,9 +28,11 @@ static const char envvars[][12] = {
"LC_MESSAGES",
};
+volatile int __locale_lock[1];
+volatile int *const __locale_lockptr = __locale_lock;
+
const struct __locale_map *__get_locale(int cat, const char *val)
{
- static volatile int lock[1];
static void *volatile loc_head;
const struct __locale_map *p;
struct __locale_map *new = 0;
@@ -54,14 +63,6 @@ const struct __locale_map *__get_locale(int cat, const char *val)
for (p=loc_head; p; p=p->next)
if (!strcmp(val, p->name)) return p;
- LOCK(lock);
-
- for (p=loc_head; p; p=p->next)
- if (!strcmp(val, p->name)) {
- UNLOCK(lock);
- return p;
- }
-
if (!libc.secure) path = getenv("MUSL_LOCPATH");
/* FIXME: add a default path? */
@@ -108,6 +109,5 @@ const struct __locale_map *__get_locale(int cat, const char *val)
* requested name was "C" or "POSIX". */
if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8;
- UNLOCK(lock);
return new;
}
diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c
index d20a8489..9ac3cd38 100644
--- a/src/locale/newlocale.c
+++ b/src/locale/newlocale.c
@@ -2,16 +2,15 @@
#include <string.h>
#include <pthread.h>
#include "locale_impl.h"
+#include "lock.h"
-static pthread_once_t default_locale_once;
-static struct __locale_struct default_locale, default_ctype_locale;
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
-static void default_locale_init(void)
-{
- for (int i=0; i<LC_ALL; i++)
- default_locale.cat[i] = __get_locale(i, "");
- default_ctype_locale.cat[LC_CTYPE] = default_locale.cat[LC_CTYPE];
-}
+static int default_locale_init_done;
+static struct __locale_struct default_locale, default_ctype_locale;
int __loc_is_allocated(locale_t loc)
{
@@ -19,7 +18,7 @@ int __loc_is_allocated(locale_t loc)
&& loc != &default_locale && loc != &default_ctype_locale;
}
-locale_t __newlocale(int mask, const char *name, locale_t loc)
+static locale_t do_newlocale(int mask, const char *name, locale_t loc)
{
struct __locale_struct tmp;
@@ -44,7 +43,12 @@ locale_t __newlocale(int mask, const char *name, locale_t loc)
/* And provide builtins for the initial default locale, and a
* variant of the C locale honoring the default locale's encoding. */
- pthread_once(&default_locale_once, default_locale_init);
+ if (!default_locale_init_done) {
+ for (int i=0; i<LC_ALL; i++)
+ default_locale.cat[i] = __get_locale(i, "");
+ default_ctype_locale.cat[LC_CTYPE] = default_locale.cat[LC_CTYPE];
+ default_locale_init_done = 1;
+ }
if (!memcmp(&tmp, &default_locale, sizeof tmp)) return &default_locale;
if (!memcmp(&tmp, &default_ctype_locale, sizeof tmp))
return &default_ctype_locale;
@@ -55,4 +59,12 @@ locale_t __newlocale(int mask, const char *name, locale_t loc)
return loc;
}
+locale_t __newlocale(int mask, const char *name, locale_t loc)
+{
+ LOCK(__locale_lock);
+ loc = do_newlocale(mask, name, loc);
+ UNLOCK(__locale_lock);
+ return loc;
+}
+
weak_alias(__newlocale, newlocale);
diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c
index 2bc7b500..360c4437 100644
--- a/src/locale/setlocale.c
+++ b/src/locale/setlocale.c
@@ -9,12 +9,11 @@ static char buf[LC_ALL*(LOCALE_NAME_MAX+1)];
char *setlocale(int cat, const char *name)
{
- static volatile int lock[1];
const struct __locale_map *lm;
if ((unsigned)cat > LC_ALL) return 0;
- LOCK(lock);
+ LOCK(__locale_lock);
/* For LC_ALL, setlocale is required to return a string which
* encodes the current setting for all categories. The format of
@@ -36,7 +35,7 @@ char *setlocale(int cat, const char *name)
}
lm = __get_locale(i, part);
if (lm == LOC_MAP_FAILED) {
- UNLOCK(lock);
+ UNLOCK(__locale_lock);
return 0;
}
tmp_locale.cat[i] = lm;
@@ -57,14 +56,14 @@ char *setlocale(int cat, const char *name)
s += l+1;
}
*--s = 0;
- UNLOCK(lock);
+ UNLOCK(__locale_lock);
return same==LC_ALL ? (char *)part : buf;
}
if (name) {
lm = __get_locale(cat, name);
if (lm == LOC_MAP_FAILED) {
- UNLOCK(lock);
+ UNLOCK(__locale_lock);
return 0;
}
libc.global_locale.cat[cat] = lm;
@@ -73,7 +72,7 @@ char *setlocale(int cat, const char *name)
}
char *ret = lm ? (char *)lm->name : "C";
- UNLOCK(lock);
+ UNLOCK(__locale_lock);
return ret;
}
diff --git a/src/malloc/free.c b/src/malloc/free.c
new file mode 100644
index 00000000..f17a952c
--- /dev/null
+++ b/src/malloc/free.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+void free(void *p)
+{
+ return __libc_free(p);
+}
diff --git a/src/malloc/libc_calloc.c b/src/malloc/libc_calloc.c
new file mode 100644
index 00000000..d25eabea
--- /dev/null
+++ b/src/malloc/libc_calloc.c
@@ -0,0 +1,4 @@
+#define calloc __libc_calloc
+#define malloc __libc_malloc
+
+#include "calloc.c"
diff --git a/src/malloc/lite_malloc.c b/src/malloc/lite_malloc.c
index f8931ba5..43a988fb 100644
--- a/src/malloc/lite_malloc.c
+++ b/src/malloc/lite_malloc.c
@@ -6,6 +6,7 @@
#include "libc.h"
#include "lock.h"
#include "syscall.h"
+#include "fork_impl.h"
#define ALIGN 16
@@ -31,10 +32,12 @@ static int traverses_stack_p(uintptr_t old, uintptr_t new)
return 0;
}
+static volatile int lock[1];
+volatile int *const __bump_lockptr = lock;
+
static void *__simple_malloc(size_t n)
{
static uintptr_t brk, cur, end;
- static volatile int lock[1];
static unsigned mmap_step;
size_t align=1;
void *p;
@@ -100,4 +103,16 @@ static void *__simple_malloc(size_t n)
return p;
}
-weak_alias(__simple_malloc, malloc);
+weak_alias(__simple_malloc, __libc_malloc_impl);
+
+void *__libc_malloc(size_t n)
+{
+ return __libc_malloc_impl(n);
+}
+
+static void *default_malloc(size_t n)
+{
+ return __libc_malloc_impl(n);
+}
+
+weak_alias(default_malloc, malloc);
diff --git a/src/malloc/mallocng/glue.h b/src/malloc/mallocng/glue.h
index 16acd1ea..151c48b8 100644
--- a/src/malloc/mallocng/glue.h
+++ b/src/malloc/mallocng/glue.h
@@ -20,6 +20,10 @@
#define is_allzero __malloc_allzerop
#define dump_heap __dump_heap
+#define malloc __libc_malloc_impl
+#define realloc __libc_realloc
+#define free __libc_free
+
#if USE_REAL_ASSERT
#include <assert.h>
#else
@@ -56,7 +60,8 @@ __attribute__((__visibility__("hidden")))
extern int __malloc_lock[1];
#define LOCK_OBJ_DEF \
-int __malloc_lock[1];
+int __malloc_lock[1]; \
+void __malloc_atfork(int who) { malloc_atfork(who); }
static inline void rdlock()
{
@@ -73,5 +78,16 @@ static inline void unlock()
static inline void upgradelock()
{
}
+static inline void resetlock()
+{
+ __malloc_lock[0] = 0;
+}
+
+static inline void malloc_atfork(int who)
+{
+ if (who<0) rdlock();
+ else if (who>0) resetlock();
+ else unlock();
+}
#endif
diff --git a/src/malloc/mallocng/malloc_usable_size.c b/src/malloc/mallocng/malloc_usable_size.c
index a440a4ea..ce6a960c 100644
--- a/src/malloc/mallocng/malloc_usable_size.c
+++ b/src/malloc/mallocng/malloc_usable_size.c
@@ -3,6 +3,7 @@
size_t malloc_usable_size(void *p)
{
+ if (!p) return 0;
struct meta *g = get_meta(p);
int idx = get_slot_index(p);
size_t stride = get_stride(g);
diff --git a/src/malloc/oldmalloc/malloc.c b/src/malloc/oldmalloc/malloc.c
index c0997ad8..53f5f959 100644
--- a/src/malloc/oldmalloc/malloc.c
+++ b/src/malloc/oldmalloc/malloc.c
@@ -9,6 +9,11 @@
#include "atomic.h"
#include "pthread_impl.h"
#include "malloc_impl.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define realloc __libc_realloc
+#define free __libc_free
#if defined(__GNUC__) && defined(__PIC__)
#define inline inline __attribute__((always_inline))
@@ -527,3 +532,21 @@ void __malloc_donate(char *start, char *end)
c->csize = n->psize = C_INUSE | (end-start);
__bin_chunk(c);
}
+
+void __malloc_atfork(int who)
+{
+ if (who<0) {
+ lock(mal.split_merge_lock);
+ for (int i=0; i<64; i++)
+ lock(mal.bins[i].lock);
+ } else if (!who) {
+ for (int i=0; i<64; i++)
+ unlock(mal.bins[i].lock);
+ unlock(mal.split_merge_lock);
+ } else {
+ for (int i=0; i<64; i++)
+ mal.bins[i].lock[0] = mal.bins[i].lock[1] = 0;
+ mal.split_merge_lock[1] = 0;
+ mal.split_merge_lock[0] = 0;
+ }
+}
diff --git a/src/malloc/realloc.c b/src/malloc/realloc.c
new file mode 100644
index 00000000..fb0e8b7c
--- /dev/null
+++ b/src/malloc/realloc.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+void *realloc(void *p, size_t n)
+{
+ return __libc_realloc(p, n);
+}
diff --git a/src/malloc/reallocarray.c b/src/malloc/reallocarray.c
new file mode 100644
index 00000000..4a6ebe46
--- /dev/null
+++ b/src/malloc/reallocarray.c
@@ -0,0 +1,13 @@
+#define _BSD_SOURCE
+#include <errno.h>
+#include <stdlib.h>
+
+void *reallocarray(void *ptr, size_t m, size_t n)
+{
+ if (n && m > -1 / n) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ return realloc(ptr, m * n);
+}
diff --git a/src/math/arm/fabs.c b/src/math/arm/fabs.c
index f890520a..6e1d367d 100644
--- a/src/math/arm/fabs.c
+++ b/src/math/arm/fabs.c
@@ -1,6 +1,6 @@
#include <math.h>
-#if __ARM_PCS_VFP
+#if __ARM_PCS_VFP && __ARM_FP&8
double fabs(double x)
{
diff --git a/src/math/arm/sqrt.c b/src/math/arm/sqrt.c
index 874af960..567e2e91 100644
--- a/src/math/arm/sqrt.c
+++ b/src/math/arm/sqrt.c
@@ -1,6 +1,6 @@
#include <math.h>
-#if __ARM_PCS_VFP || (__VFP_FP__ && !__SOFTFP__)
+#if (__ARM_PCS_VFP || (__VFP_FP__ && !__SOFTFP__)) && (__ARM_FP&8)
double sqrt(double x)
{
diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c
index 89477511..49282811 100644
--- a/src/misc/ioctl.c
+++ b/src/misc/ioctl.c
@@ -4,6 +4,7 @@
#include <time.h>
#include <sys/time.h>
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include "syscall.h"
@@ -28,6 +29,12 @@ struct ioctl_compat_map {
* number producing macros; only size of result is meaningful. */
#define new_misaligned(n) struct { int i; time_t t; char c[(n)-4]; }
+struct v4l2_event {
+ uint32_t a;
+ uint64_t b[8];
+ uint32_t c[2], ts[2], d[9];
+};
+
static const struct ioctl_compat_map compat_map[] = {
{ SIOCGSTAMP, SIOCGSTAMP_OLD, 8, R, 0, OFFS(0, 4) },
{ SIOCGSTAMPNS, SIOCGSTAMPNS_OLD, 8, R, 0, OFFS(0, 4) },
@@ -49,13 +56,14 @@ static const struct ioctl_compat_map compat_map[] = {
{ 0, 0, 8, WR, 1, OFFS(0,4) }, /* snd_pcm_mmap_control */
/* VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF, VIDIOC_PREPARE_BUF */
- { _IOWR('V', 9, new_misaligned(72)), _IOWR('V', 9, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 15, new_misaligned(72)), _IOWR('V', 15, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 17, new_misaligned(72)), _IOWR('V', 17, char[72]), 72, WR, 0, OFFS(20) },
- { _IOWR('V', 93, new_misaligned(72)), _IOWR('V', 93, char[72]), 72, WR, 0, OFFS(20) },
+ { _IOWR('V', 9, new_misaligned(68)), _IOWR('V', 9, char[68]), 68, WR, 1, OFFS(20, 24) },
+ { _IOWR('V', 15, new_misaligned(68)), _IOWR('V', 15, char[68]), 68, WR, 1, OFFS(20, 24) },
+ { _IOWR('V', 17, new_misaligned(68)), _IOWR('V', 17, char[68]), 68, WR, 1, OFFS(20, 24) },
+ { _IOWR('V', 93, new_misaligned(68)), _IOWR('V', 93, char[68]), 68, WR, 1, OFFS(20, 24) },
/* VIDIOC_DQEVENT */
- { _IOR('V', 89, new_misaligned(96)), _IOR('V', 89, char[96]), 96, R, 0, OFFS(76,80) },
+ { _IOR('V', 89, new_misaligned(120)), _IOR('V', 89, struct v4l2_event), sizeof(struct v4l2_event),
+ R, 0, OFFS(offsetof(struct v4l2_event, ts[0]), offsetof(struct v4l2_event, ts[1])) },
/* VIDIOC_OMAP3ISP_STAT_REQ */
{ _IOWR('V', 192+6, char[32]), _IOWR('V', 192+6, char[24]), 22, WR, 0, OFFS(0,4) },
diff --git a/src/misc/realpath.c b/src/misc/realpath.c
index d2708e59..db8b74dc 100644
--- a/src/misc/realpath.c
+++ b/src/misc/realpath.c
@@ -1,43 +1,156 @@
#include <stdlib.h>
#include <limits.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
-#include "syscall.h"
+
+static size_t slash_len(const char *s)
+{
+ const char *s0 = s;
+ while (*s == '/') s++;
+ return s-s0;
+}
char *realpath(const char *restrict filename, char *restrict resolved)
{
- int fd;
- ssize_t r;
- struct stat st1, st2;
- char buf[15+3*sizeof(int)];
- char tmp[PATH_MAX];
+ char stack[PATH_MAX+1];
+ char output[PATH_MAX];
+ size_t p, q, l, l0, cnt=0, nup=0;
+ int check_dir=0;
if (!filename) {
errno = EINVAL;
return 0;
}
+ l = strnlen(filename, sizeof stack);
+ if (!l) {
+ errno = ENOENT;
+ return 0;
+ }
+ if (l >= PATH_MAX) goto toolong;
+ p = sizeof stack - l - 1;
+ q = 0;
+ memcpy(stack+p, filename, l+1);
+
+ /* Main loop. Each iteration pops the next part from stack of
+ * remaining path components and consumes any slashes that follow.
+ * If not a link, it's moved to output; if a link, contents are
+ * pushed to the stack. */
+restart:
+ for (; ; p+=slash_len(stack+p)) {
+ /* If stack starts with /, the whole component is / or //
+ * and the output state must be reset. */
+ if (stack[p] == '/') {
+ check_dir=0;
+ nup=0;
+ q=0;
+ output[q++] = '/';
+ p++;
+ /* Initial // is special. */
+ if (stack[p] == '/' && stack[p+1] != '/')
+ output[q++] = '/';
+ continue;
+ }
+
+ char *z = __strchrnul(stack+p, '/');
+ l0 = l = z-(stack+p);
- fd = sys_open(filename, O_PATH|O_NONBLOCK|O_CLOEXEC);
- if (fd < 0) return 0;
- __procfdname(buf, fd);
+ if (!l && !check_dir) break;
- r = readlink(buf, tmp, sizeof tmp - 1);
- if (r < 0) goto err;
- tmp[r] = 0;
+ /* Skip any . component but preserve check_dir status. */
+ if (l==1 && stack[p]=='.') {
+ p += l;
+ continue;
+ }
- fstat(fd, &st1);
- r = stat(tmp, &st2);
- if (r<0 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
- if (!r) errno = ELOOP;
- goto err;
+ /* Copy next component onto output at least temporarily, to
+ * call readlink, but wait to advance output position until
+ * determining it's not a link. */
+ if (q && output[q-1] != '/') {
+ if (!p) goto toolong;
+ stack[--p] = '/';
+ l++;
+ }
+ if (q+l >= PATH_MAX) goto toolong;
+ memcpy(output+q, stack+p, l);
+ output[q+l] = 0;
+ p += l;
+
+ int up = 0;
+ if (l0==2 && stack[p-2]=='.' && stack[p-1]=='.') {
+ up = 1;
+ /* Any non-.. path components we could cancel start
+ * after nup repetitions of the 3-byte string "../";
+ * if there are none, accumulate .. components to
+ * later apply to cwd, if needed. */
+ if (q <= 3*nup) {
+ nup++;
+ q += l;
+ continue;
+ }
+ /* When previous components are already known to be
+ * directories, processing .. can skip readlink. */
+ if (!check_dir) goto skip_readlink;
+ }
+ ssize_t k = readlink(output, stack, p);
+ if (k==p) goto toolong;
+ if (!k) {
+ errno = ENOENT;
+ return 0;
+ }
+ if (k<0) {
+ if (errno != EINVAL) return 0;
+skip_readlink:
+ check_dir = 0;
+ if (up) {
+ while(q && output[q-1]!='/') q--;
+ if (q>1 && (q>2 || output[0]!='/')) q--;
+ continue;
+ }
+ if (l0) q += l;
+ check_dir = stack[p];
+ continue;
+ }
+ if (++cnt == SYMLOOP_MAX) {
+ errno = ELOOP;
+ return 0;
+ }
+
+ /* If link contents end in /, strip any slashes already on
+ * stack to avoid /->// or //->/// or spurious toolong. */
+ if (stack[k-1]=='/') while (stack[p]=='/') p++;
+ p -= k;
+ memmove(stack+p, stack, k);
+
+ /* Skip the stack advancement in case we have a new
+ * absolute base path. */
+ goto restart;
}
- __syscall(SYS_close, fd);
- return resolved ? strcpy(resolved, tmp) : strdup(tmp);
-err:
- __syscall(SYS_close, fd);
+ output[q] = 0;
+
+ if (output[0] != '/') {
+ if (!getcwd(stack, sizeof stack)) return 0;
+ l = strlen(stack);
+ /* Cancel any initial .. components. */
+ p = 0;
+ while (nup--) {
+ while(l>1 && stack[l-1]!='/') l--;
+ if (l>1) l--;
+ p += 2;
+ if (p<q) p++;
+ }
+ if (q-p && stack[l-1]!='/') stack[l++] = '/';
+ if (l + (q-p) + 1 >= PATH_MAX) goto toolong;
+ memmove(output + l, output + p, q - p + 1);
+ memcpy(output, stack, l);
+ q = l + q-p;
+ }
+
+ if (resolved) return memcpy(resolved, output, q+1);
+ else return strdup(output);
+
+toolong:
+ errno = ENAMETOOLONG;
return 0;
}
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
index 13d4b0a6..7dc0c1be 100644
--- a/src/misc/syslog.c
+++ b/src/misc/syslog.c
@@ -10,6 +10,7 @@
#include <errno.h>
#include <fcntl.h>
#include "lock.h"
+#include "fork_impl.h"
static volatile int lock[1];
static char log_ident[32];
@@ -17,6 +18,7 @@ static int log_opt;
static int log_facility = LOG_USER;
static int log_mask = 0xff;
static int log_fd = -1;
+volatile int *const __syslog_lockptr = lock;
int setlogmask(int maskpri)
{
diff --git a/src/multibyte/wcsnrtombs.c b/src/multibyte/wcsnrtombs.c
index 676932b5..95e25e70 100644
--- a/src/multibyte/wcsnrtombs.c
+++ b/src/multibyte/wcsnrtombs.c
@@ -1,41 +1,33 @@
#include <wchar.h>
+#include <limits.h>
+#include <string.h>
size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict wcs, size_t wn, size_t n, mbstate_t *restrict st)
{
- size_t l, cnt=0, n2;
- char *s, buf[256];
const wchar_t *ws = *wcs;
- const wchar_t *tmp_ws;
-
- if (!dst) s = buf, n = sizeof buf;
- else s = dst;
-
- while ( ws && n && ( (n2=wn)>=n || n2>32 ) ) {
- if (n2>=n) n2=n;
- tmp_ws = ws;
- l = wcsrtombs(s, &ws, n2, 0);
- if (!(l+1)) {
- cnt = l;
- n = 0;
+ size_t cnt = 0;
+ if (!dst) n=0;
+ while (ws && wn) {
+ char tmp[MB_LEN_MAX];
+ size_t l = wcrtomb(n<MB_LEN_MAX ? tmp : dst, *ws, 0);
+ if (l==-1) {
+ cnt = -1;
break;
}
- if (s != buf) {
- s += l;
+ if (dst) {
+ if (n<MB_LEN_MAX) {
+ if (l>n) break;
+ memcpy(dst, tmp, l);
+ }
+ dst += l;
n -= l;
}
- wn = ws ? wn - (ws - tmp_ws) : 0;
- cnt += l;
- }
- if (ws) while (n && wn) {
- l = wcrtomb(s, *ws, 0);
- if ((l+1)<=1) {
- if (!l) ws = 0;
- else cnt = l;
+ if (!*ws) {
+ ws = 0;
break;
}
- ws++; wn--;
- /* safe - this loop runs fewer than sizeof(buf) times */
- s+=l; n-=l;
+ ws++;
+ wn--;
cnt += l;
}
if (dst) *wcs = ws;
diff --git a/src/prng/random.c b/src/prng/random.c
index 633a17f6..d3780fa7 100644
--- a/src/prng/random.c
+++ b/src/prng/random.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdint.h>
#include "lock.h"
+#include "fork_impl.h"
/*
this code uses the same lagged fibonacci generator as the
@@ -23,6 +24,7 @@ static int i = 3;
static int j = 0;
static uint32_t *x = init+1;
static volatile int lock[1];
+volatile int *const __random_lockptr = lock;
static uint32_t lcg31(uint32_t x) {
return (1103515245*x + 12345) & 0x7fffffff;
diff --git a/src/process/fork.c b/src/process/fork.c
index 8d34a9c4..54bc2892 100644
--- a/src/process/fork.c
+++ b/src/process/fork.c
@@ -1,15 +1,85 @@
#include <unistd.h>
#include <errno.h>
#include "libc.h"
+#include "lock.h"
+#include "pthread_impl.h"
+#include "fork_impl.h"
+
+static volatile int *const dummy_lockptr = 0;
+
+weak_alias(dummy_lockptr, __at_quick_exit_lockptr);
+weak_alias(dummy_lockptr, __atexit_lockptr);
+weak_alias(dummy_lockptr, __dlerror_lockptr);
+weak_alias(dummy_lockptr, __gettext_lockptr);
+weak_alias(dummy_lockptr, __locale_lockptr);
+weak_alias(dummy_lockptr, __random_lockptr);
+weak_alias(dummy_lockptr, __sem_open_lockptr);
+weak_alias(dummy_lockptr, __stdio_ofl_lockptr);
+weak_alias(dummy_lockptr, __syslog_lockptr);
+weak_alias(dummy_lockptr, __timezone_lockptr);
+weak_alias(dummy_lockptr, __bump_lockptr);
+
+weak_alias(dummy_lockptr, __vmlock_lockptr);
+
+static volatile int *const *const atfork_locks[] = {
+ &__at_quick_exit_lockptr,
+ &__atexit_lockptr,
+ &__dlerror_lockptr,
+ &__gettext_lockptr,
+ &__locale_lockptr,
+ &__random_lockptr,
+ &__sem_open_lockptr,
+ &__stdio_ofl_lockptr,
+ &__syslog_lockptr,
+ &__timezone_lockptr,
+ &__bump_lockptr,
+};
static void dummy(int x) { }
weak_alias(dummy, __fork_handler);
+weak_alias(dummy, __malloc_atfork);
+weak_alias(dummy, __ldso_atfork);
+
+static void dummy_0(void) { }
+weak_alias(dummy_0, __tl_lock);
+weak_alias(dummy_0, __tl_unlock);
pid_t fork(void)
{
+ sigset_t set;
__fork_handler(-1);
+ __block_app_sigs(&set);
+ int need_locks = libc.need_locks > 0;
+ if (need_locks) {
+ __ldso_atfork(-1);
+ __inhibit_ptc();
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
+ if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
+ __malloc_atfork(-1);
+ __tl_lock();
+ }
+ pthread_t self=__pthread_self(), next=self->next;
pid_t ret = _Fork();
int errno_save = errno;
+ if (need_locks) {
+ if (!ret) {
+ for (pthread_t td=next; td!=self; td=td->next)
+ td->tid = -1;
+ if (__vmlock_lockptr) {
+ __vmlock_lockptr[0] = 0;
+ __vmlock_lockptr[1] = 0;
+ }
+ }
+ __tl_unlock();
+ __malloc_atfork(!ret);
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
+ if (*atfork_locks[i])
+ if (ret) UNLOCK(*atfork_locks[i]);
+ else **atfork_locks[i] = 0;
+ __release_ptc();
+ __ldso_atfork(!ret);
+ }
+ __restore_sigs(&set);
__fork_handler(!ret);
if (ret<0) errno = errno_save;
return ret;
diff --git a/src/stdio/ofl.c b/src/stdio/ofl.c
index f2d3215a..aad3d171 100644
--- a/src/stdio/ofl.c
+++ b/src/stdio/ofl.c
@@ -1,8 +1,10 @@
#include "stdio_impl.h"
#include "lock.h"
+#include "fork_impl.h"
static FILE *ofl_head;
static volatile int ofl_lock[1];
+volatile int *const __stdio_ofl_lockptr = ofl_lock;
FILE **__ofl_lock()
{
diff --git a/src/string/strstr.c b/src/string/strstr.c
index 43a0207a..96657bc2 100644
--- a/src/string/strstr.c
+++ b/src/string/strstr.c
@@ -96,7 +96,7 @@ static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
for (;;) {
/* Update incremental end-of-haystack pointer */
if (z-h < l) {
- /* Fast estimate for MIN(l,63) */
+ /* Fast estimate for MAX(l,63) */
size_t grow = l | 63;
const unsigned char *z2 = memchr(z, 0, grow);
if (z2) {
diff --git a/src/thread/pthread_attr_get.c b/src/thread/pthread_attr_get.c
index 4aa5afdb..f12ff442 100644
--- a/src/thread/pthread_attr_get.c
+++ b/src/thread/pthread_attr_get.c
@@ -70,7 +70,7 @@ int pthread_condattr_getpshared(const pthread_condattr_t *restrict a, int *restr
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict a, int *restrict protocol)
{
- *protocol = PTHREAD_PRIO_NONE;
+ *protocol = a->__attr / 8U % 2;
return 0;
}
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict a, int *restrict pshared)
diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
index a0cd4904..6b761455 100644
--- a/src/thread/pthread_cond_timedwait.c
+++ b/src/thread/pthread_cond_timedwait.c
@@ -155,7 +155,7 @@ relock:
int val = m->_m_lock;
if (val>0) a_cas(&m->_m_lock, val, val|0x80000000);
unlock_requeue(&node.prev->barrier, &m->_m_lock, m->_m_type & (8|128));
- } else if (!!(m->_m_type & 8)) {
+ } else if (!(m->_m_type & 8)) {
a_dec(&m->_m_waiters);
}
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index 55744155..6f187ee8 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -69,12 +69,25 @@ _Noreturn void __pthread_exit(void *result)
__pthread_tsd_run_dtors();
+ __block_app_sigs(&set);
+
+ /* This atomic potentially competes with a concurrent pthread_detach
+ * call; the loser is responsible for freeing thread resources. */
+ int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
+
+ if (state==DT_DETACHED && self->map_base) {
+ /* Since __unmapself bypasses the normal munmap code path,
+ * explicitly wait for vmlock holders first. This must be
+ * done before any locks are taken, to avoid lock ordering
+ * issues that could lead to deadlock. */
+ __vm_wait();
+ }
+
/* Access to target the exiting thread with syscalls that use
* its kernel tid is controlled by killlock. For detached threads,
* any use past this point would have undefined behavior, but for
* joinable threads it's a valid usage that must be handled.
* Signals must be blocked since pthread_kill must be AS-safe. */
- __block_app_sigs(&set);
LOCK(self->killlock);
/* The thread list lock must be AS-safe, and thus depends on
@@ -87,6 +100,7 @@ _Noreturn void __pthread_exit(void *result)
if (self->next == self) {
__tl_unlock();
UNLOCK(self->killlock);
+ self->detach_state = state;
__restore_sigs(&set);
exit(0);
}
@@ -125,10 +139,6 @@ _Noreturn void __pthread_exit(void *result)
self->prev->next = self->next;
self->prev = self->next = self;
- /* This atomic potentially competes with a concurrent pthread_detach
- * call; the loser is responsible for freeing thread resources. */
- int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
-
if (state==DT_DETACHED && self->map_base) {
/* Detached threads must block even implementation-internal
* signals, since they will not have a stack in their last
@@ -140,16 +150,13 @@ _Noreturn void __pthread_exit(void *result)
if (self->robust_list.off)
__syscall(SYS_set_robust_list, 0, 3*sizeof(long));
- /* Since __unmapself bypasses the normal munmap code path,
- * explicitly wait for vmlock holders first. */
- __vm_wait();
-
/* The following call unmaps the thread's stack mapping
* and then exits without touching the stack. */
__unmapself(self->map_base, self->map_size);
}
/* Wake any joiner. */
+ a_store(&self->detach_state, DT_EXITED);
__wake(&self->detach_state, 1, 1);
/* After the kernel thread exits, its tid may be reused. Clear it
diff --git a/src/thread/pthread_mutex_destroy.c b/src/thread/pthread_mutex_destroy.c
index 6d49e689..8d1bf77b 100644
--- a/src/thread/pthread_mutex_destroy.c
+++ b/src/thread/pthread_mutex_destroy.c
@@ -1,6 +1,10 @@
-#include <pthread.h>
+#include "pthread_impl.h"
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
+ /* If the mutex being destroyed is process-shared and has nontrivial
+ * type (tracking ownership), it might be in the pending slot of a
+ * robust_list; wait for quiescence. */
+ if (mutex->_m_type > 128) __vm_wait();
return 0;
}
diff --git a/src/thread/s390x/clone.s b/src/thread/s390x/clone.s
index 577748ea..2125f20b 100644
--- a/src/thread/s390x/clone.s
+++ b/src/thread/s390x/clone.s
@@ -17,6 +17,9 @@ __clone:
# if (!tid) syscall(SYS_exit, a(d));
# return tid;
+ # preserve call-saved register used as syscall arg
+ stg %r6, 48(%r15)
+
# create initial stack frame for new thread
nill %r3, 0xfff8
aghi %r3, -160
@@ -35,6 +38,9 @@ __clone:
lg %r6, 160(%r15)
svc 120
+ # restore call-saved register
+ lg %r6, 48(%r15)
+
# if error or if we're the parent, return
ltgr %r2, %r2
bnzr %r14
diff --git a/src/thread/s390x/syscall_cp.s b/src/thread/s390x/syscall_cp.s
index c1da40de..d094cbf5 100644
--- a/src/thread/s390x/syscall_cp.s
+++ b/src/thread/s390x/syscall_cp.s
@@ -14,6 +14,7 @@ __cp_begin:
icm %r2, 15, 0(%r2)
jne __cp_cancel
+ stg %r6, 48(%r15)
stg %r7, 56(%r15)
lgr %r1, %r3
lgr %r2, %r4
@@ -26,6 +27,7 @@ __cp_begin:
__cp_end:
lg %r7, 56(%r15)
+ lg %r6, 48(%r15)
br %r14
__cp_cancel:
diff --git a/src/thread/sem_open.c b/src/thread/sem_open.c
index 6fb0c5b2..0ad29de9 100644
--- a/src/thread/sem_open.c
+++ b/src/thread/sem_open.c
@@ -12,6 +12,12 @@
#include <stdlib.h>
#include <pthread.h>
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc undef
+#define free undef
static struct {
ino_t ino;
@@ -19,6 +25,7 @@ static struct {
int refcnt;
} *semtab;
static volatile int lock[1];
+volatile int *const __sem_open_lockptr = lock;
#define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK)
diff --git a/src/thread/vmlock.c b/src/thread/vmlock.c
index 75f3cb76..fa0a8e3c 100644
--- a/src/thread/vmlock.c
+++ b/src/thread/vmlock.c
@@ -1,6 +1,8 @@
#include "pthread_impl.h"
+#include "fork_impl.h"
static volatile int vmlock[2];
+volatile int *const __vmlock_lockptr = vmlock;
void __vm_wait()
{
diff --git a/src/time/__tz.c b/src/time/__tz.c
index 49a7371e..09a6317e 100644
--- a/src/time/__tz.c
+++ b/src/time/__tz.c
@@ -6,6 +6,12 @@
#include <sys/mman.h>
#include "libc.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
long __timezone = 0;
int __daylight = 0;
@@ -30,6 +36,7 @@ static char *old_tz = old_tz_buf;
static size_t old_tz_size = sizeof old_tz_buf;
static volatile int lock[1];
+volatile int *const __timezone_lockptr = lock;
static int getint(const char **p)
{
@@ -178,7 +185,7 @@ static void do_tzset()
zi = map;
if (map) {
int scale = 2;
- if (sizeof(time_t) > 4 && map[4]=='2') {
+ if (map[4]!='1') {
size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
trans = zi+skip+44+44;
scale++;
diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c
index a152d524..32f4537f 100644
--- a/src/unistd/readlink.c
+++ b/src/unistd/readlink.c
@@ -4,9 +4,16 @@
ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
{
+ char dummy[1];
+ if (!bufsize) {
+ buf = dummy;
+ bufsize = 1;
+ }
#ifdef SYS_readlink
- return syscall(SYS_readlink, path, buf, bufsize);
+ int r = __syscall(SYS_readlink, path, buf, bufsize);
#else
- return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
+ int r = __syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
#endif
+ if (buf == dummy && r > 0) r = 0;
+ return __syscall_ret(r);
}
diff --git a/src/unistd/readlinkat.c b/src/unistd/readlinkat.c
index 9af45cd5..f79d3d14 100644
--- a/src/unistd/readlinkat.c
+++ b/src/unistd/readlinkat.c
@@ -3,5 +3,12 @@
ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf, size_t bufsize)
{
- return syscall(SYS_readlinkat, fd, path, buf, bufsize);
+ char dummy[1];
+ if (!bufsize) {
+ buf = dummy;
+ bufsize = 1;
+ }
+ int r = __syscall(SYS_readlinkat, fd, path, buf, bufsize);
+ if (buf == dummy && r > 0) r = 0;
+ return __syscall_ret(r);
}