bug-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC/base] GSAllocateMutexAt()


From: David Ayers
Subject: [RFC/base] GSAllocateMutexAt()
Date: Wed, 05 May 2004 19:53:34 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113

Hello everyone,

I'm hoping to flush a couple of my local changes back to -base(add) in the coming days. As they will introduce new API, I'd like to give everyone a quick chance to object or constructively criticize. These will mostly be focused on GSObjCRuntime and it utilities. I've tried to take care that most of the API is +load and thread safe. I've done some testing with both -base and -baseadd/Cocoa.

To start off I'm adding:

void GSAllocateMutexAt(objc_mutex_t *location)

This function provided an API to initialize a mutex safely in +load (without triggering any unrelated objc initialization like NSObject/NSLock) even in a multithreaded environment. Currently this patch assumes that NeXT_RUNTIME uses pthreads.h. If anyone is using GNUstep with a NeXT_RUNTIME that uses a different threading library please let me know.

Cheers,
David

Index: Headers/Additions/GNUstepBase/GSObjCRuntime.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/core/base/Headers/Additions/GNUstepBase/GSObjCRuntime.h,v
retrieving revision 1.3
diff -u -r1.3 GSObjCRuntime.h
--- Headers/Additions/GNUstepBase/GSObjCRuntime.h       10 Sep 2003 09:29:39 
-0000      1.3
+++ Headers/Additions/GNUstepBase/GSObjCRuntime.h       5 May 2004 17:50:03 
-0000
@@ -468,6 +468,31 @@
 GS_EXPORT void *
 GSAutoreleasedBuffer(unsigned size);
 
+/**
+ * Allocate a new objc_mutex_t and store it in the location
+ * pointed to by request.  A mutex is only created if the value
+ * pointed to by request is NULL.  This function is thread safe
+ * in the sense that multiple threads my call this function with the same
+ * value of request and only one will actually set the mutex.
+ * It is the users responsibility that no one else attempts to set
+ * the mutex pointed to.  This function should be
+ * used with objc_mutex_t variables which were statically initialized
+ * to NULL like:
+ * <example>
+ * void function (void)
+ * {
+ *   static objc_mutex_t my_lock = NULL;
+ *   if (my_lock == NULL)
+ *     GSAllocateMutexAt(&my_lock);
+ *   objc_mutex_lock(my_lock);
+ *   do_work ();
+ *   objc_mutex_unlock(my_lock);
+ * }
+ * </example>
+ */
+GS_EXPORT void
+GSAllocateMutexAt(objc_mutex_t *request);
+
 /** Returns a system error message on a variety of systems
  */
 GS_EXPORT const char *
Index: Headers/Additions/GNUstepBase/objc-gnu2next.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/core/base/Headers/Additions/GNUstepBase/objc-gnu2next.h,v
retrieving revision 1.1
diff -u -r1.1 objc-gnu2next.h
--- Headers/Additions/GNUstepBase/objc-gnu2next.h       31 Jul 2003 23:49:29 
-0000      1.1
+++ Headers/Additions/GNUstepBase/objc-gnu2next.h       5 May 2004 17:50:04 
-0000
@@ -36,8 +36,8 @@
 #include <ctype.h>
 #include <stdio.h>
 
-/* Disable builtin functions for gcc < 3.x since it triggers a bad bug (even 
some 3.x versions may have this
-   bug) */
+/* Disable builtin functions for gcc < 3.x since it triggers a bad bug 
+   (even some 3.x versions may have this bug).  */
 #if __GNUC__ < 3
 #define __builtin_apply(a,b,c) 0
 #define __builtin_apply_args() 0
@@ -191,6 +191,16 @@
 extern void *(*_objc_realloc)(void *, size_t);
 extern void *(*_objc_calloc)(size_t, size_t);
 extern void (*_objc_free)(void *);
+
+
+/* threading functions */
+typedef void *objc_mutex_t;
+
+objc_mutex_t objc_mutex_allocate (void);
+int objc_mutex_deallocate (objc_mutex_t mutex);
+int objc_mutex_lock (objc_mutex_t mutex);
+int objc_mutex_unlock (objc_mutex_t mutex);
+int objc_mutex_trylock (objc_mutex_t mutex);
 
 /* encoding functions */
 extern int objc_sizeof_type(const char* type);
Index: Source/Additions/GSNextRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSNextRuntime.m,v
retrieving revision 1.4
diff -u -r1.4 GSNextRuntime.m
--- Source/Additions/GSNextRuntime.m    31 Jul 2003 23:49:32 -0000      1.4
+++ Source/Additions/GSNextRuntime.m    5 May 2004 17:50:04 -0000
@@ -593,3 +593,59 @@
   return temp;
 }
 
+/*
+ * Functions for threading support.
+ */
+
+/* This currently assumes that the NeXT Runtime is using pthreads
+   as the underlying thread support.  This is true for 'modern' NeXT
+   Runtime implementations but it may not be for older versions.  */
+
+#include <pthread.h>
+
+objc_mutex_t
+objc_mutex_allocate(void)
+{
+  pthread_mutex_t *p;
+  p = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
+  if (pthread_mutex_init(p, NULL) != 0)
+    {
+      abort();
+    }
+  return (objc_mutex_t)p;
+}
+
+int
+objc_mutex_deallocate(objc_mutex_t mutex)
+{
+  int ret;
+  pthread_mutex_t *p = (pthread_mutex_t *)mutex;
+  ret = pthread_mutex_destroy(p);
+  if (ret == 0)
+    {
+      free(p);
+    }
+  return ret;
+}
+
+int
+objc_mutex_lock(objc_mutex_t mutex)
+{
+  pthread_mutex_t *p = (pthread_mutex_t *)mutex;
+  return pthread_mutex_lock(p);  
+}
+
+int
+objc_mutex_unlock (objc_mutex_t mutex)
+{
+  pthread_mutex_t *p = (pthread_mutex_t *)mutex;
+  return pthread_mutex_unlock(p);  
+}
+
+int
+objc_mutex_trylock (objc_mutex_t mutex)
+{
+  pthread_mutex_t *p = (pthread_mutex_t *)mutex;
+  return pthread_mutex_trylock(p);  
+}
+
Index: Source/Additions/GSObjCRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSObjCRuntime.m,v
retrieving revision 1.32
diff -u -r1.32 GSObjCRuntime.m
--- Source/Additions/GSObjCRuntime.m    15 Jan 2004 04:07:08 -0000      1.32
+++ Source/Additions/GSObjCRuntime.m    5 May 2004 17:50:04 -0000
@@ -59,6 +59,59 @@
 @end
 #endif
 
+static objc_mutex_t local_lock = NULL;
+
+/* This class it intended soley for thread safe / +load safe
+   initialization of the local lock.
+   It's a root class so it won't trigger the initialization
+   of any other class.  */
+@interface _GSObjCRuntimeInitializer /* Root Class */
+{
+  Class isa;
+}
++ (Class)class;
+@end
+@implementation _GSObjCRuntimeInitializer
++ (void)initialize
+{
+  if (local_lock == NULL)
+    {
+      local_lock = objc_mutex_allocate();
+    }
+}
++ (Class)class
+{
+  return self;
+}
+@end
+
+void
+GSAllocateMutexAt(objc_mutex_t *request)
+{
+  if (request == NULL)
+    {
+      /* This could be called very early in process 
+        initialization so many things may not have 
+        been setup correctly yet.  */
+      fprintf(stderr, 
+             "Error: GSAllocateMutexAt() called with NULL pointer.\n");
+      abort();
+    }
+
+  if (local_lock == NULL)
+    {
+      /* Initialize in a thread safe way.  */
+      [_GSObjCRuntimeInitializer class];
+    }
+
+  objc_mutex_lock(local_lock);
+  if (*request == NULL)
+    {
+      *request = objc_mutex_allocate();
+    }
+  objc_mutex_unlock(local_lock);
+}
+
 /**  Deprecated ... use GSObjCFindVariable() */
 BOOL
 GSFindInstanceVariable(id obj, const char *name,

reply via email to

[Prev in Thread] Current Thread [Next in Thread]