+2003-10-24 Thomas Pfaff <tpfaff@gmx.net>
+
+ Rename native_mutex to fast_mutex throughout.
+ Rename pthread_key::save_key_to_buffer to
+ pthread_key::_fixup_before_fork throughout.
+ Rename pthread_key::recreate_key_from_buffer to
+ pthread_key::_fixup_after_fork throughout.
+
+ * thread.cc (native_mutex::init): Remove.
+ (native_mutex::lock): Ditto.
+ (native_mutex::unlock): Ditto.
+ (pthread::push_cleanup_handler): InterlockedExchangePointer
+ is not needed here.
+ (pthread_rwlock::pthread_rwlock): Initialize readers list mutex.
+ (pthread_rwlock::add_reader): Add reader via List_insert.
+ (pthread_rwlock::lookup_reader): Lock list while walking through.
+ (pthread_cond::init): Locking the init mutex is now void.
+ (pthread_rwlock::init): Ditto.
+ (pthread_mutex::init): Ditto.
+ * thread.h: Include security.h.
+ (fast_mutex): New class. Replacement for native_mutex.
+ (List_insert): New template function.
+ (List_remove): Ditto.
+ (List::List): Initialize synchronising mutex.
+ (List::fixup_after_fork): New method.
+ (List::insert): Add node via List_insert.
+ (List::remove): Remove node via List_remove.
+ (List::pop): Remove.
+ (List::for_each): Lock list while walking through.
+ (List::mx_init): New method.
+ (pthread_mutex::fixup_after_fork): Fixup mutex list after fork.
+ (pthread::fixup_after_fork): Ditto.
+ (pthread_conds::fixup_after_fork): Ditto.
+ (pthread_rwlock::fixup_after_fork): Ditto.
+ (semaphore::fixup_after_fork): Ditto.
+ (pthread_rwlock::readers_mx): New member.
+
2003-10-24 Brian Ford <ford@vss.fsi.com>
* fhandler.cc (fhandler_base::fcntl): Don't clobber O_APPEND when
return _r->_winsup;
}
-bool
-native_mutex::init ()
-{
- theHandle = CreateMutex (&sec_none_nih, FALSE, NULL);
- if (!theHandle)
- {
- debug_printf ("CreateMutex failed. %E");
- return false;
- }
- return true;
-}
-
-bool
-native_mutex::lock ()
-{
- DWORD waitResult = WaitForSingleObject (theHandle, INFINITE);
- if (waitResult != WAIT_OBJECT_0)
- {
- system_printf ("Received unexpected wait result %d on handle %p, %E", waitResult, theHandle);
- return false;
- }
- return true;
-}
-
-void
-native_mutex::unlock ()
-{
- if (!ReleaseMutex (theHandle))
- system_printf ("Received a unexpected result releasing mutex. %E");
-}
-
inline LPCRITICAL_SECTION
ResourceLocks::Lock (int _resid)
{
// TODO: do it?
api_fatal ("Attempt to push a cleanup handler across threads");
handler->next = cleanup_stack;
- InterlockedExchangePointer (&cleanup_stack, handler);
+ cleanup_stack = handler;
}
void
List<pthread_cond> pthread_cond::conds;
/* This is used for cond creation protection within a single process only */
-native_mutex NO_COPY pthread_cond::cond_initialization_lock;
+fast_mutex NO_COPY pthread_cond::cond_initialization_lock;
/* We can only be called once.
TODO: (no rush) use a non copied memory section to
List<pthread_rwlock> pthread_rwlock::rwlocks;
/* This is used for rwlock creation protection within a single process only */
-native_mutex NO_COPY pthread_rwlock::rwlock_initialization_lock;
+fast_mutex NO_COPY pthread_rwlock::rwlock_initialization_lock;
/* We can only be called once.
TODO: (no rush) use a non copied memory section to
pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) :
verifyable_object (PTHREAD_RWLOCK_MAGIC),
shared (0), waiting_readers (0), waiting_writers (0), writer (NULL),
- readers (NULL), mtx (NULL), cond_readers (NULL), cond_writers (NULL),
+ readers (NULL), readers_mx (), mtx (NULL), cond_readers (NULL), cond_writers (NULL),
next (NULL)
{
pthread_mutex *verifyable_mutex_obj = &mtx;
pthread_cond *verifyable_cond_obj;
+ if (!readers_mx.init ())
+ {
+ thread_printf ("Internal rwlock synchronisation mutex is not valid. this %p", this);
+ magic = 0;
+ return;
+ }
+
if (attr)
if (attr->shared != PTHREAD_PROCESS_PRIVATE)
{
void
pthread_rwlock::add_reader (struct RWLOCK_READER *rd)
{
- rd->next = (struct RWLOCK_READER *)
- InterlockedExchangePointer (&readers, rd);
+ List_insert (readers_mx, readers, rd);
}
void
pthread_rwlock::remove_reader (struct RWLOCK_READER *rd)
{
- if (readers == rd)
- InterlockedExchangePointer (&readers, rd->next);
- else
- {
- struct RWLOCK_READER *temp = readers;
- while (temp->next && temp->next != rd)
- temp = temp->next;
- /* but there may be a race between the loop above and this statement */
- InterlockedExchangePointer (&temp->next, rd->next);
- }
+ List_remove (readers_mx, readers, rd);
}
struct pthread_rwlock::RWLOCK_READER *
pthread_rwlock::lookup_reader (pthread_t thread)
{
- struct RWLOCK_READER *temp = readers;
+ readers_mx.lock ();
+
+ struct RWLOCK_READER *cur = readers;
- while (temp && temp->thread != thread)
- temp = temp->next;
+ while (cur && cur->thread != thread)
+ cur = cur->next;
- return temp;
+ readers_mx.unlock ();
+
+ return cur;
}
void
waiting_readers = 0;
waiting_writers = 0;
+ if (!readers_mx.init ())
+ api_fatal ("pthread_rwlock::_fixup_after_fork () failed to recreate mutex");
+
/* Unlock eventually locked mutex */
mtx.unlock ();
/*
}
void
-pthread_key::save_key_to_buffer ()
+pthread_key::_fixup_before_fork ()
{
fork_buf = get ();
}
void
-pthread_key::recreate_key_from_buffer ()
+pthread_key::_fixup_after_fork ()
{
tls_index = TlsAlloc ();
if (tls_index == TLS_OUT_OF_INDEXES)
List<pthread_mutex> pthread_mutex::mutexes;
/* This is used for mutex creation protection within a single process only */
-native_mutex NO_COPY pthread_mutex::mutex_initialization_lock;
+fast_mutex NO_COPY pthread_mutex::mutex_initialization_lock;
/* We can only be called once.
TODO: (no rush) use a non copied memory section to
{
if (attr && !pthread_condattr::is_good_object (attr))
return EINVAL;
- if (!cond_initialization_lock.lock ())
- return EINVAL;
+
+ cond_initialization_lock.lock ();
if (!is_good_initializer_or_bad_object (cond))
{
{
if (attr && !pthread_rwlockattr::is_good_object (attr))
return EINVAL;
- if (!rwlock_initialization_lock.lock ())
- return EINVAL;
+
+ rwlock_initialization_lock.lock ();
if (!is_good_initializer_or_bad_object (rwlock))
{
{
if (attr && !pthread_mutexattr::is_good_object (attr) || check_valid_pointer (mutex))
return EINVAL;
- if (!mutex_initialization_lock.lock ())
- return EINVAL;
+
+ mutex_initialization_lock.lock ();
if (!is_good_initializer_or_bad_object (mutex))
{
#include <signal.h>
#include <pwd.h>
#include <grp.h>
+#include <security.h>
#define _NOMNTENT_FUNCS
#include <mntent.h>
#endif
}
-class native_mutex
+class fast_mutex
{
public:
- bool init ();
- bool lock ();
- void unlock ();
+ fast_mutex () :
+ lock_counter (0), win32_obj_id (0)
+ {
+ }
+
+ ~fast_mutex ()
+ {
+ if(win32_obj_id)
+ CloseHandle (win32_obj_id);
+ }
+
+ bool init ()
+ {
+ win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
+ if (!win32_obj_id)
+ {
+ debug_printf ("CreateSemaphore failed. %E");
+ return false;
+ }
+ return true;
+ }
+
+ void lock ()
+ {
+ if (InterlockedIncrement ((long *)&lock_counter) != 1)
+ WaitForSingleObject (win32_obj_id, INFINITE);
+ }
+
+ void unlock ()
+ {
+ if (InterlockedDecrement ((long *)&lock_counter))
+ ::ReleaseSemaphore (win32_obj_id, 1, NULL);
+ }
+
private:
- HANDLE theHandle;
+ unsigned long lock_counter;
+ HANDLE win32_obj_id;
};
class per_process;
verifyable_object_state verifyable_object_isvalid (void const *, long);
verifyable_object_state verifyable_object_isvalid (void const *, long, void *);
-template <class list_node> class List {
-public:
+template <class list_node> inline void
+List_insert (fast_mutex &mx, list_node *&head, list_node *node)
+{
+ if (!node)
+ return;
+ mx.lock ();
+ node->next = head;
+ head = node;
+ mx.unlock ();
+}
+
+template <class list_node> inline void
+List_remove (fast_mutex &mx, list_node *&head, list_node *node)
+{
+ if (!node)
+ return;
+ mx.lock ();
+ if (node == head)
+ head = head->next;
+ else if (head)
+ {
+ list_node *cur = head;
+
+ while (cur->next && node != cur->next)
+ cur = cur->next;
+ if (node == cur->next)
+ cur->next = cur->next->next;
+ }
+ mx.unlock ();
+}
+
+
+template <class list_node> class List
+{
+ public:
List() : head(NULL)
{
+ mx_init ();
}
- void insert (list_node *node)
+ ~List()
{
- if (!node)
- return;
- node->next = (list_node *) InterlockedExchangePointer (&head, node);
}
- list_node *remove ( list_node *node)
+ void fixup_after_fork ()
{
- if (!node || !head)
- return NULL;
- if (node == head)
- return pop ();
+ mx_init ();
+ }
- list_node *result_prev = head;
- while (result_prev && result_prev->next && !(node == result_prev->next))
- result_prev = result_prev->next;
- if (result_prev)
- return (list_node *)InterlockedExchangePointer (&result_prev->next, result_prev->next->next);
- return NULL;
+ void insert (list_node *node)
+ {
+ List_insert (mx, head, node);
}
- list_node *pop ()
+ void remove (list_node *node)
{
- return (list_node *) InterlockedExchangePointer (&head, head->next);
+ List_remove (mx, head, node);
}
- /* poor mans generic programming. */
void for_each (void (list_node::*callback) ())
{
- list_node *node = head;
- while (node)
+ mx.lock ();
+ list_node *cur = head;
+ while (cur)
{
- (node->*callback) ();
- node = node->next;
+ (cur->*callback) ();
+ cur = cur->next;
}
+ mx.unlock ();
}
protected:
+ void mx_init ()
+ {
+ if (!mx.init ())
+ api_fatal ("Could not create mutex for list synchronisation.");
+ }
+
+ fast_mutex mx;
list_node *head;
};
pthread_key (void (*)(void *));
~pthread_key ();
- static void fixup_before_fork()
+ static void fixup_before_fork ()
{
- keys.for_each (&pthread_key::save_key_to_buffer);
+ keys.for_each (&pthread_key::_fixup_before_fork);
}
- static void fixup_after_fork()
+ static void fixup_after_fork ()
{
- keys.for_each (&pthread_key::recreate_key_from_buffer);
+ keys.fixup_after_fork ();
+ keys.for_each (&pthread_key::_fixup_after_fork);
}
static void run_all_destructors ()
class pthread_key *next;
private:
static List<pthread_key> keys;
- void save_key_to_buffer ();
- void recreate_key_from_buffer ();
+ void _fixup_before_fork ();
+ void _fixup_after_fork ();
void (*destructor) (void *);
void run_destructor ();
void *fork_buf;
class pthread_mutex * next;
static void fixup_after_fork ()
{
+ mutexes.fixup_after_fork ();
mutexes.for_each (&pthread_mutex::_fixup_after_fork);
}
void _fixup_after_fork ();
static List<pthread_mutex> mutexes;
- static native_mutex mutex_initialization_lock;
+ static fast_mutex mutex_initialization_lock;
};
#define WAIT_CANCELED (WAIT_OBJECT_0 + 1)
class pthread *next;
static void fixup_after_fork ()
{
+ threads.fixup_after_fork ();
threads.for_each (&pthread::_fixup_after_fork);
}
class pthread_cond * next;
static void fixup_after_fork ()
{
+ conds.fixup_after_fork ();
conds.for_each (&pthread_cond::_fixup_after_fork);
}
void _fixup_after_fork ();
static List<pthread_cond> conds;
- static native_mutex cond_initialization_lock;
+ static fast_mutex cond_initialization_lock;
};
class pthread_rwlockattr:public verifyable_object
struct RWLOCK_READER *next;
pthread_t thread;
} *readers;
+ fast_mutex readers_mx;
int rdlock ();
int tryrdlock ();
class pthread_rwlock * next;
static void fixup_after_fork ()
{
+ rwlocks.fixup_after_fork ();
rwlocks.for_each (&pthread_rwlock::_fixup_after_fork);
}
void _fixup_after_fork ();
- static native_mutex rwlock_initialization_lock;
+ static fast_mutex rwlock_initialization_lock;
};
class pthread_once
class semaphore * next;
static void fixup_after_fork ()
{
+ semaphores.fixup_after_fork ();
semaphores.for_each (&semaphore::_fixup_after_fork);
}