Fix lowlevel locks
authorDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Wed, 20 Aug 2008 01:04:25 +0000 (21:04 -0400)
committerDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Wed, 20 Aug 2008 01:37:21 +0000 (21:37 -0400)
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/bits/libc-lock.h
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/bits/stdio-lock.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/lowlevellock.h
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/register-atfork.c
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/unregister-atfork.c

index 1b4e010..9a4fd1f 100644 (file)
@@ -1,5 +1,5 @@
-/* libc-internal interface for mutex locks.  NPTL version.
-e  Copyright (C) 1996-2003, 2005, 2007, 2008 Free Software Foundation, Inc.
+/* libc-internal interface for mutex locks.  OpenSolaris NPTL version.
+   Copyright (C) 1996-2003, 2005, 2007, 2008 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    OpenSolaris bits contributed by David Bartley
     <dtbartle@csclub.uwaterloo.ca>, 2008.
diff --git a/nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/bits/stdio-lock.h b/nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/bits/stdio-lock.h
new file mode 100644 (file)
index 0000000..3407171
--- /dev/null
@@ -0,0 +1,67 @@
+/* Thread package specific definitions of stream lock type.  Generic version.
+   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_STDIO_LOCK_H
+#define _BITS_STDIO_LOCK_H 1
+
+#include <bits/libc-lock.h>
+
+__libc_lock_define_recursive (typedef, _IO_lock_t)
+
+/* We need recursive (counting) mutexes.  */
+#ifdef _LIBC_LOCK_RECURSIVE_INITIALIZER
+# define _IO_lock_initializer _LIBC_LOCK_RECURSIVE_INITIALIZER
+#elif _IO_MTSAFE_IO
+ #error libio needs recursive mutexes for _IO_MTSAFE_IO
+#endif
+
+#define _IO_lock_init(_name)   __libc_lock_init_recursive (_name)
+#define _IO_lock_fini(_name)   __libc_lock_fini_recursive (_name)
+#define _IO_lock_lock(_name)   __libc_lock_lock_recursive (_name)
+#define _IO_lock_trylock(_name)        __libc_lock_trylock_recursive (_name)
+#define _IO_lock_unlock(_name) __libc_lock_unlock_recursive (_name)
+
+
+#define _IO_cleanup_region_start(_fct, _fp) \
+  __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp)
+#define _IO_cleanup_region_start_noarg(_fct) \
+  __libc_cleanup_region_start (1, _fct, NULL)
+#define _IO_cleanup_region_end(_doit) \
+  __libc_cleanup_region_end (_doit)
+
+#if defined _LIBC && !defined NOT_IN_libc
+# define _IO_acquire_lock(_fp) \
+  { \
+  _IO_FILE *_IO_acquire_lock_file = _fp; \
+  __libc_cleanup_region_start (1, (void (*) (void *)) _IO_acquire_lock_fct, &_IO_acquire_lock_file); \
+  _IO_flockfile (_IO_acquire_lock_file)
+
+# define _IO_acquire_lock_clear_flags2(_fp) \
+  { \
+  _IO_FILE *_IO_acquire_lock_file = _fp; \
+  __libc_cleanup_region_start (1, (void (*) (void *)) _IO_acquire_lock_clear_flags2_fct, &_IO_acquire_lock_file); \
+  _IO_flockfile (_IO_acquire_lock_file)
+
+# define _IO_release_lock(_fp) \
+  __libc_cleanup_region_end (1); \
+   }
+   
+#endif
+
+#endif /* bits/stdio-lock.h */
index ba36ede..fb9bf3f 100644 (file)
@@ -3,29 +3,27 @@
 
 #include <stddef.h>
 #include <inline-syscall.h>
+#include <pthread.h>
 
-/* XXX: lll_define is used by desr.h so we can't use bits/libc-lock.h */
 #define lll_define(class, futex) \
-    class pthread_mutex_t futex;
-
-#include <bits/libc-lock.h>
+    class pthread_mutex_t futex
 
 #define LLL_LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
 
 #define lll_define_initialized(class, futex) \
-    __libc_lock_define_initialized (class, futex)
+    class pthread_mutex_t futex = PTHREAD_MUTEX_INITIALIZER
 
 #define lll_init(futex) \
-    __libc_lock_init (futex)
+    __pthread_mutex_init (&(futex), NULL)
 
 #define lll_lock(futex, private) \
-    __libc_lock_lock (futex)
+    __pthread_mutex_lock (&(futex))
 
 #define lll_trylock(futex) \
-    __libc_lock_trylock (futex)
+    __pthread_mutex_trylock (&(futex))
 
 #define lll_unlock(futex, private) \
-    __libc_lock_unlock (futex)
+    __pthread_mutex_unlock (&(futex))
 
 DECLARE_INLINE_SYSCALL (int, lwp_wait, pthread_t tid, pthread_t *departed);
 
index 50331dd..7304574 100644 (file)
@@ -1 +1,137 @@
-#include <nptl/sysdeps/unix/sysv/linux/register-atfork.c>
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fork.h>
+#include <pthreadP.h>
+#include <bits/libc-lock.h>
+
+
+/* Lock to protect allocation and deallocation of fork handlers.  */
+__libc_lock_define_initialized (, __fork_lock);
+
+
+/* Number of pre-allocated handler entries.  */
+#define NHANDLER 48
+
+/* Memory pool for fork handler structures.  */
+static struct fork_handler_pool
+{
+  struct fork_handler_pool *next;
+  struct fork_handler mem[NHANDLER];
+} fork_handler_pool;
+
+
+static struct fork_handler *
+fork_handler_alloc (void)
+{
+  struct fork_handler_pool *runp = &fork_handler_pool;
+  struct fork_handler *result = NULL;
+  unsigned int i;
+
+  do
+    {
+      /* Search for an empty entry.  */
+      for (i = 0; i < NHANDLER; ++i)
+       if (runp->mem[i].refcntr == 0)
+         goto found;
+    }
+  while ((runp = runp->next) != NULL);
+
+  /* We have to allocate a new entry.  */
+  runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
+  if (runp != NULL)
+    {
+      /* Enqueue the new memory pool into the list.  */
+      runp->next = fork_handler_pool.next;
+      fork_handler_pool.next = runp;
+
+      /* We use the last entry on the page.  This means when we start
+        searching from the front the next time we will find the first
+        entry unused.  */
+      i = NHANDLER - 1;
+
+    found:
+      result = &runp->mem[i];
+      result->refcntr = 1;
+      result->need_signal = 0;
+    }
+
+  return result;
+}
+
+
+int
+__register_atfork (prepare, parent, child, dso_handle)
+     void (*prepare) (void);
+     void (*parent) (void);
+     void (*child) (void);
+     void *dso_handle;
+{
+  /* Get the lock to not conflict with other allocations.  */
+  __libc_lock_lock (__fork_lock);
+
+  struct fork_handler *newp = fork_handler_alloc ();
+
+  if (newp != NULL)
+    {
+      /* Initialize the new record.  */
+      newp->prepare_handler = prepare;
+      newp->parent_handler = parent;
+      newp->child_handler = child;
+      newp->dso_handle = dso_handle;
+
+      newp->next = __fork_handlers;
+      __fork_handlers = newp;
+    }
+
+  /* Release the lock.  */
+  __libc_lock_unlock (__fork_lock);
+
+  return newp == NULL ? ENOMEM : 0;
+}
+libc_hidden_def (__register_atfork)
+
+
+libc_freeres_fn (free_mem)
+{
+  /* Get the lock to not conflict with running forks.  */
+  __libc_lock_lock (__fork_lock);
+
+  /* No more fork handlers.  */
+  __fork_handlers = NULL;
+
+  /* Free eventually alloated memory blocks for the object pool.  */
+  struct fork_handler_pool *runp = fork_handler_pool.next;
+
+  memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool));
+
+  /* Release the lock.  */
+  __libc_lock_unlock (__fork_lock);
+
+  /* We can free the memory after releasing the lock.  */
+  while (runp != NULL)
+    {
+      struct fork_handler_pool *oldp = runp;
+      runp = runp->next;
+      free (oldp);
+    }
+}
index 696dda0..600a31e 100644 (file)
@@ -1 +1,116 @@
-#include <nptl/sysdeps/unix/sysv/linux/unregister-atfork.c>
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <fork.h>
+#include <atomic.h>
+#include <pthreadP.h>
+#include <bits/libc-lock.h>
+
+
+void
+__unregister_atfork (dso_handle)
+     void *dso_handle;
+{
+  /* Check whether there is any entry in the list which we have to
+     remove.  It is likely that this is not the case so don't bother
+     getting the lock.
+
+     We do not worry about other threads adding entries for this DSO
+     right this moment.  If this happens this is a race and we can do
+     whatever we please.  The program will crash anyway seen.  */
+  struct fork_handler *runp = __fork_handlers;
+  struct fork_handler *lastp = NULL;
+
+  while (runp != NULL)
+    if (runp->dso_handle == dso_handle)
+      break;
+    else
+      {
+       lastp = runp;
+       runp = runp->next;
+      }
+
+  if (runp == NULL)
+    /* Nothing to do.  */
+    return;
+
+  /* Get the lock to not conflict with additions or deletions.  Note
+     that there couldn't have been another thread deleting something.
+     The __unregister_atfork function is only called from the
+     dlclose() code which itself serializes the operations.  */
+  __libc_lock_lock (__fork_lock);
+
+  /* We have to create a new list with all the entries we don't remove.  */
+  struct deleted_handler
+  {
+    struct fork_handler *handler;
+    struct deleted_handler *next;
+  } *deleted = NULL;
+
+  /* Remove the entries for the DSO which is unloaded from the list.
+     It's a single linked list so readers are.  */
+  do
+    {
+      if (runp->dso_handle == dso_handle)
+       {
+         if (lastp == NULL)
+           __fork_handlers = runp->next;
+         else
+           lastp->next = runp->next;
+
+         /* We cannot overwrite the ->next element now.  Put the deleted
+            entries in a separate list.  */
+         struct deleted_handler *newp = alloca (sizeof (*newp));
+         newp->handler = runp;
+         newp->next = deleted;
+         deleted = newp;
+       }
+      else
+       lastp = runp;
+
+      runp = runp->next;
+    }
+  while (runp != NULL);
+
+  /* Release the lock.  */
+  __libc_lock_unlock (__fork_lock);
+
+  /* Walk the list of all entries which have to be deleted.  */
+  while (deleted != NULL)
+    {
+      /* We need to be informed by possible current users.  */
+      deleted->handler->need_signal = 1;
+      /* Make sure this gets written out first.  */
+      atomic_write_barrier ();
+
+      /* Decrement the reference counter.  If it does not reach zero
+        wait for the last user.  */
+      atomic_decrement (&deleted->handler->refcntr);
+      unsigned int val;
+      while ((val = deleted->handler->refcntr) != 0)
+        ; // TODO
+#if 0 // TODO
+       lll_futex_wait (&deleted->handler->refcntr, val);
+#endif
+
+      deleted = deleted->next;
+    }
+}