glib/libgthread/src/gthread-posix.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* GLIB - Library of useful routines for C programming
       
     2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       
     3  *
       
     4  * gthread.c: posix thread system implementation
       
     5  * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
       
     6  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Lesser General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Lesser General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Lesser General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 
       
    24 /*
       
    25  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
       
    26  * file for a list of people on the GLib Team.  See the ChangeLog
       
    27  * files for a list of changes.  These files are distributed with
       
    28  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
       
    29  */
       
    30 
       
    31 /* 
       
    32  * MT safe
       
    33  */
       
    34 
       
    35 #include <config.h>
       
    36 
       
    37 #include <pthread.h>
       
    38 #include <errno.h>
       
    39 #include <stdlib.h>
       
    40 #ifdef HAVE_SYS_TIME_H
       
    41 # include <sys/time.h>
       
    42 #endif
       
    43 #ifdef HAVE_UNISTD_H
       
    44 # include <unistd.h>
       
    45 #endif
       
    46 
       
    47 #ifdef HAVE_SCHED_H
       
    48 #include <sched.h>
       
    49 #endif
       
    50 
       
    51 #define posix_check_err(err, name) G_STMT_START{			\
       
    52   int error = (err); 							\
       
    53   if (error)	 		 		 			\
       
    54     g_error ("file %s: line %d (%s): error '%s' during '%s'",		\
       
    55            __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,			\
       
    56            g_strerror (error), name);					\
       
    57   }G_STMT_END
       
    58 
       
    59 #define posix_check_cmd(cmd) posix_check_err (posix_error (cmd), #cmd)
       
    60 
       
    61 #ifdef G_ENABLE_DEBUG
       
    62 #if EMULATOR
       
    63 PLS(posix_check_cmd_prio_warned,gthread_posix,gboolean)
       
    64 #define posix_check_cmd_prio_warned (*FUNCTION_NAME(posix_check_cmd_prio_warned,gthread_posix)())
       
    65 #else
       
    66 static gboolean posix_check_cmd_prio_warned = FALSE;
       
    67 #endif /* EMULATOR */
       
    68 # define posix_check_cmd_prio(cmd) G_STMT_START{			\
       
    69     int err = posix_error (cmd);					\
       
    70     if (err == EPERM)		 		 			\
       
    71       { 	 			 				\
       
    72         if (!posix_check_cmd_prio_warned) 		 		\
       
    73           { 	 				 			\
       
    74             posix_check_cmd_prio_warned = TRUE;		 		\
       
    75             g_warning ("Priorities can only be changed " 		\
       
    76                         "(resp. increased) by root."); 			\
       
    77           }			 					\
       
    78       }			 						\
       
    79     else  		 						\
       
    80       posix_check_err (err, #cmd);					\
       
    81      }G_STMT_END
       
    82 #else /* G_ENABLE_DEBUG */
       
    83 # define posix_check_cmd_prio(cmd) G_STMT_START{			\
       
    84     int err = posix_error (cmd);					\
       
    85     if (err != EPERM)		 		 			\
       
    86       posix_check_err (err, #cmd);					\
       
    87      }G_STMT_END
       
    88 #endif /* G_ENABLE_DEBUG */
       
    89 
       
    90 #if defined(G_THREADS_IMPL_POSIX)
       
    91 # define posix_error(what) (what)
       
    92 # define mutexattr_default NULL
       
    93 # define condattr_default NULL
       
    94 #elif defined(G_THREADS_IMPL_DCE)
       
    95 # define posix_error(what) ((what) == -1 ? errno : 0)
       
    96 # define pthread_key_create(a, b) pthread_keycreate (a, b)
       
    97 # define pthread_attr_init(a) pthread_attr_create (a)
       
    98 # define pthread_attr_destroy(a) pthread_attr_delete (a)
       
    99 # define pthread_create(a, b, c, d) pthread_create (a, *b, c, d) 
       
   100 # define mutexattr_default (pthread_mutexattr_default)
       
   101 # define condattr_default (pthread_condattr_default)
       
   102 #else /* neither G_THREADS_IMPL_POSIX nor G_THREADS_IMPL_DCE are defined */
       
   103 # error This should not happen. Contact the GLib team.
       
   104 #endif
       
   105 
       
   106 #if defined (POSIX_MIN_PRIORITY) && defined (POSIX_MAX_PRIORITY)
       
   107 # define HAVE_PRIORITIES 1
       
   108 #if EMULATOR
       
   109 
       
   110 PLS(priority_normal_value,gthread_posix,gint)
       
   111 #define priority_normal_value (*FUNCTION_NAME(priority_normal_value,gthread_posix)())
       
   112 
       
   113 #else
       
   114 
       
   115 static gint priority_normal_value;
       
   116 
       
   117 #endif /* EMULATOR */
       
   118 # ifdef __FreeBSD__
       
   119    /* FreeBSD threads use different priority values from the POSIX_
       
   120     * defines so we just set them here. The corresponding macros
       
   121     * PTHREAD_MIN_PRIORITY and PTHREAD_MAX_PRIORITY are implied to be
       
   122     * exported by the docs, but they aren't.
       
   123     */
       
   124 #  define PRIORITY_LOW_VALUE      0
       
   125 #  define PRIORITY_URGENT_VALUE   31
       
   126 # else /* !__FreeBSD__ */
       
   127 #  define PRIORITY_LOW_VALUE      POSIX_MIN_PRIORITY
       
   128 #  define PRIORITY_URGENT_VALUE   POSIX_MAX_PRIORITY
       
   129 # endif /* !__FreeBSD__ */
       
   130 # define PRIORITY_NORMAL_VALUE    priority_normal_value
       
   131 #endif /* POSIX_MIN_PRIORITY && POSIX_MAX_PRIORITY */
       
   132 
       
   133 #if EMULATOR
       
   134 
       
   135 PLS(g_thread_min_stack_size ,gthread_posix,gulong)
       
   136 #define g_thread_min_stack_size  (*FUNCTION_NAME(g_thread_min_stack_size ,gthread_posix)())
       
   137 
       
   138 #else
       
   139 
       
   140 static gulong g_thread_min_stack_size = 0;
       
   141 
       
   142 #endif /* EMULATOR */
       
   143 #define G_MUTEX_SIZE (sizeof (pthread_mutex_t))
       
   144 
       
   145 #if defined(_SC_THREAD_STACK_MIN) || defined (HAVE_PRIORITIES)
       
   146 #define HAVE_G_THREAD_IMPL_INIT
       
   147 static void 
       
   148 g_thread_impl_init(void)
       
   149 {
       
   150 #ifdef _SC_THREAD_STACK_MIN
       
   151   g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
       
   152 #endif /* _SC_THREAD_STACK_MIN */
       
   153 #ifdef HAVE_PRIORITIES
       
   154 # ifdef G_THREADS_IMPL_POSIX
       
   155   {
       
   156     struct sched_param sched;
       
   157     int policy;
       
   158     posix_check_cmd (pthread_getschedparam (pthread_self(), &policy, &sched));
       
   159     priority_normal_value = sched.sched_priority;
       
   160   }
       
   161 # else /* G_THREADS_IMPL_DCE */
       
   162   posix_check_cmd (priority_normal_value = 
       
   163 		   pthread_getprio (*(pthread_t*)thread, 
       
   164 				    g_thread_priority_map [priority]));
       
   165 # endif
       
   166 #endif /* HAVE_PRIORITIES */
       
   167 
       
   168 }
       
   169 #endif /* _SC_THREAD_STACK_MIN || HAVE_PRIORITIES */
       
   170 
       
   171 static GMutex *
       
   172 g_mutex_new_posix_impl (void)
       
   173 {
       
   174   GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
       
   175   posix_check_cmd (pthread_mutex_init ((pthread_mutex_t *) result, 
       
   176 				       mutexattr_default));
       
   177   return result;  
       
   178 }
       
   179 
       
   180 static void
       
   181 g_mutex_free_posix_impl (GMutex * mutex)
       
   182 {
       
   183   posix_check_cmd (pthread_mutex_destroy ((pthread_mutex_t *) mutex));
       
   184   g_free (mutex);
       
   185 }
       
   186 
       
   187 /* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
       
   188    functions from gmem.c and gmessages.c; */
       
   189 
       
   190 /* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
       
   191    signature and semantic are right, but without error check then!!!!,
       
   192    we might want to change this therefore. */
       
   193 
       
   194 static gboolean
       
   195 g_mutex_trylock_posix_impl (GMutex * mutex)
       
   196 {
       
   197   int result;
       
   198 
       
   199   result = pthread_mutex_trylock ((pthread_mutex_t *) mutex);
       
   200 
       
   201 #ifdef G_THREADS_IMPL_POSIX
       
   202   if (result == EBUSY)
       
   203     return FALSE;
       
   204 #else /* G_THREADS_IMPL_DCE */
       
   205   if (result == 0)
       
   206     return FALSE;
       
   207 #endif
       
   208 
       
   209   posix_check_err (posix_error (result), "pthread_mutex_trylock");
       
   210   return TRUE;
       
   211 }
       
   212 
       
   213 static GCond *
       
   214 g_cond_new_posix_impl (void)
       
   215 {
       
   216   GCond *result = (GCond *) g_new (pthread_cond_t, 1);
       
   217   posix_check_cmd (pthread_cond_init ((pthread_cond_t *) result, 
       
   218 				      condattr_default));
       
   219   return result;
       
   220 }
       
   221 
       
   222 /* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
       
   223    can be taken directly, as signature and semantic are right, but
       
   224    without error check then!!!!, we might want to change this
       
   225    therfore. */
       
   226 
       
   227 #define G_NSEC_PER_SEC 1000000000
       
   228 
       
   229 static gboolean
       
   230 g_cond_timed_wait_posix_impl (GCond * cond,
       
   231 			      GMutex * entered_mutex,
       
   232 			      GTimeVal * abs_time)
       
   233 {
       
   234   int result;
       
   235   struct timespec end_time;
       
   236   gboolean timed_out;
       
   237 
       
   238   g_return_val_if_fail (cond != NULL, FALSE);
       
   239   g_return_val_if_fail (entered_mutex != NULL, FALSE);
       
   240 
       
   241   if (!abs_time)
       
   242     {
       
   243       g_cond_wait (cond, entered_mutex);
       
   244       return TRUE;
       
   245     }
       
   246 
       
   247   end_time.tv_sec = abs_time->tv_sec;
       
   248   end_time.tv_nsec = abs_time->tv_usec * (G_NSEC_PER_SEC / G_USEC_PER_SEC);
       
   249 
       
   250   g_return_val_if_fail (end_time.tv_nsec < G_NSEC_PER_SEC, TRUE);
       
   251 
       
   252   result = pthread_cond_timedwait ((pthread_cond_t *) cond,
       
   253 				   (pthread_mutex_t *) entered_mutex,
       
   254 				   &end_time);
       
   255 
       
   256 #ifdef G_THREADS_IMPL_POSIX
       
   257   timed_out = (result == ETIMEDOUT);
       
   258 #else /* G_THREADS_IMPL_DCE */
       
   259   timed_out = (result == -1) && (errno == EAGAIN);
       
   260 #endif
       
   261 
       
   262   if (!timed_out)
       
   263     posix_check_err (posix_error (result), "pthread_cond_timedwait");
       
   264   return !timed_out;
       
   265 }
       
   266 
       
   267 static void
       
   268 g_cond_free_posix_impl (GCond * cond)
       
   269 {
       
   270   posix_check_cmd (pthread_cond_destroy ((pthread_cond_t *) cond));
       
   271   g_free (cond);
       
   272 }
       
   273 
       
   274 static GPrivate *
       
   275 g_private_new_posix_impl (GDestroyNotify destructor)
       
   276 {
       
   277   GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
       
   278   posix_check_cmd (pthread_key_create ((pthread_key_t *) result, destructor));
       
   279   return result;
       
   280 }
       
   281 
       
   282 /* NOTE: the functions g_private_get and g_private_set may not use
       
   283    functions from gmem.c and gmessages.c */
       
   284 
       
   285 static void
       
   286 g_private_set_posix_impl (GPrivate * private_key, gpointer value)
       
   287 {
       
   288   if (!private_key)
       
   289     return;
       
   290   pthread_setspecific (*(pthread_key_t *) private_key, value);
       
   291 }
       
   292 
       
   293 static gpointer
       
   294 g_private_get_posix_impl (GPrivate * private_key)
       
   295 {
       
   296   if (!private_key)
       
   297     return NULL;
       
   298 #ifdef G_THREADS_IMPL_POSIX
       
   299   return pthread_getspecific (*(pthread_key_t *) private_key);
       
   300 #else /* G_THREADS_IMPL_DCE */
       
   301   {
       
   302     void* data;
       
   303     posix_check_cmd (pthread_getspecific (*(pthread_key_t *) private_key, 
       
   304 					  &data));
       
   305     return data;
       
   306   }
       
   307 #endif
       
   308 }
       
   309 
       
   310 static void
       
   311 g_thread_create_posix_impl (GThreadFunc thread_func, 
       
   312 			    gpointer arg, 
       
   313 			    gulong stack_size,
       
   314 			    gboolean joinable,
       
   315 			    gboolean bound,
       
   316 			    GThreadPriority priority,
       
   317 			    gpointer thread,
       
   318 			    GError **error)
       
   319 {
       
   320   pthread_attr_t attr;
       
   321   gint ret;
       
   322 
       
   323   g_return_if_fail (thread_func);
       
   324   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
       
   325   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
       
   326 
       
   327   posix_check_cmd (pthread_attr_init (&attr));
       
   328   
       
   329 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
       
   330   if (stack_size)
       
   331     {
       
   332       stack_size = MAX (g_thread_min_stack_size, stack_size);
       
   333       /* No error check here, because some systems can't do it and
       
   334        * we simply don't want threads to fail because of that. */
       
   335       pthread_attr_setstacksize (&attr, stack_size);
       
   336     }
       
   337 #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
       
   338 
       
   339 #ifdef PTHREAD_SCOPE_SYSTEM
       
   340   if (bound)
       
   341     /* No error check here, because some systems can't do it and we
       
   342      * simply don't want threads to fail because of that. */
       
   343     pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
       
   344 #endif /* PTHREAD_SCOPE_SYSTEM */
       
   345 
       
   346 #ifdef G_THREADS_IMPL_POSIX
       
   347   posix_check_cmd (pthread_attr_setdetachstate (&attr,
       
   348           joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
       
   349 #endif /* G_THREADS_IMPL_POSIX */
       
   350   
       
   351 #ifdef HAVE_PRIORITIES
       
   352 # ifdef G_THREADS_IMPL_POSIX
       
   353   {
       
   354     struct sched_param sched;
       
   355     posix_check_cmd (pthread_attr_getschedparam (&attr, &sched));
       
   356     sched.sched_priority = g_thread_priority_map [priority];
       
   357     posix_check_cmd_prio (pthread_attr_setschedparam (&attr, &sched));
       
   358   }
       
   359 # else /* G_THREADS_IMPL_DCE */
       
   360   posix_check_cmd_prio 
       
   361     (pthread_attr_setprio (&attr, g_thread_priority_map [priority]));
       
   362 # endif /* G_THREADS_IMPL_DCE */
       
   363 #endif /* HAVE_PRIORITIES */
       
   364   ret = posix_error (pthread_create (thread, &attr, 
       
   365 				     (void* (*)(void*))thread_func, arg));
       
   366 
       
   367   posix_check_cmd (pthread_attr_destroy (&attr));
       
   368 
       
   369   if (ret == EAGAIN)
       
   370     {
       
   371       g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, 
       
   372 		   "Error creating thread: %s", g_strerror (ret));
       
   373       return;
       
   374     }
       
   375 
       
   376   posix_check_err (ret, "pthread_create");
       
   377 
       
   378 #ifdef G_THREADS_IMPL_DCE
       
   379   if (!joinable)
       
   380     posix_check_cmd (pthread_detach (thread));
       
   381 #endif /* G_THREADS_IMPL_DCE */
       
   382 }
       
   383 
       
   384 static void 
       
   385 g_thread_yield_posix_impl (void)
       
   386 {
       
   387   POSIX_YIELD_FUNC;
       
   388 }
       
   389 
       
   390 static void
       
   391 g_thread_join_posix_impl (gpointer thread)
       
   392 {     
       
   393   gpointer ignore;
       
   394   posix_check_cmd (pthread_join (*(pthread_t*)thread, &ignore));
       
   395 }
       
   396 
       
   397 static void 
       
   398 g_thread_exit_posix_impl (void) 
       
   399 {
       
   400   pthread_exit (NULL);
       
   401 }
       
   402 
       
   403 static void
       
   404 g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
       
   405 {
       
   406   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
       
   407   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
       
   408 #ifdef HAVE_PRIORITIES
       
   409 # ifdef G_THREADS_IMPL_POSIX
       
   410   {
       
   411     struct sched_param sched;
       
   412     int policy;
       
   413     posix_check_cmd (pthread_getschedparam (*(pthread_t*)thread, &policy, 
       
   414 					    &sched));
       
   415     sched.sched_priority = g_thread_priority_map [priority];
       
   416     posix_check_cmd_prio (pthread_setschedparam (*(pthread_t*)thread, policy, 
       
   417 						 &sched));
       
   418   }
       
   419 # else /* G_THREADS_IMPL_DCE */
       
   420   posix_check_cmd_prio (pthread_setprio (*(pthread_t*)thread, 
       
   421 					 g_thread_priority_map [priority]));
       
   422 # endif
       
   423 #endif /* HAVE_PRIORITIES */
       
   424 }
       
   425 
       
   426 static void
       
   427 g_thread_self_posix_impl (gpointer thread)
       
   428 {
       
   429   *(pthread_t*)thread = pthread_self();
       
   430 }
       
   431 
       
   432 static gboolean
       
   433 g_thread_equal_posix_impl (gpointer thread1, gpointer thread2)
       
   434 {
       
   435   return (pthread_equal (*(pthread_t*)thread1, *(pthread_t*)thread2) != 0);
       
   436 }
       
   437 
       
   438 #if EMULATOR
       
   439 
       
   440 PLS(g_thread_functions_for_glib_use_default ,gthread_posix,GThreadFunctions)
       
   441 #define g_thread_functions_for_glib_use_default   (*FUNCTION_NAME(g_thread_functions_for_glib_use_default ,gthread_posix)())
       
   442 
       
   443 const GThreadFunctions temp_g_thread_functions_for_glib_use_default =
       
   444 {
       
   445   g_mutex_new_posix_impl,
       
   446   (void (*)(GMutex *)) pthread_mutex_lock,
       
   447   g_mutex_trylock_posix_impl,
       
   448   (void (*)(GMutex *)) pthread_mutex_unlock,
       
   449   g_mutex_free_posix_impl,
       
   450   g_cond_new_posix_impl,
       
   451   (void (*)(GCond *)) pthread_cond_signal,
       
   452   (void (*)(GCond *)) pthread_cond_broadcast,
       
   453   (void (*)(GCond *, GMutex *)) pthread_cond_wait,
       
   454   g_cond_timed_wait_posix_impl,
       
   455   g_cond_free_posix_impl,
       
   456   g_private_new_posix_impl,
       
   457   g_private_get_posix_impl,
       
   458   g_private_set_posix_impl,
       
   459   g_thread_create_posix_impl,
       
   460   g_thread_yield_posix_impl,
       
   461   g_thread_join_posix_impl,
       
   462   g_thread_exit_posix_impl,
       
   463   g_thread_set_priority_posix_impl,
       
   464   g_thread_self_posix_impl,
       
   465   g_thread_equal_posix_impl
       
   466 };
       
   467 
       
   468 
       
   469 #else
       
   470 
       
   471  static const GThreadFunctions g_thread_functions_for_glib_use_default =
       
   472 {
       
   473   g_mutex_new_posix_impl,
       
   474   (void (*)(GMutex *)) pthread_mutex_lock,
       
   475   g_mutex_trylock_posix_impl,
       
   476   (void (*)(GMutex *)) pthread_mutex_unlock,
       
   477   g_mutex_free_posix_impl,
       
   478   g_cond_new_posix_impl,
       
   479   (void (*)(GCond *)) pthread_cond_signal,
       
   480   (void (*)(GCond *)) pthread_cond_broadcast,
       
   481   (void (*)(GCond *, GMutex *)) pthread_cond_wait,
       
   482   g_cond_timed_wait_posix_impl,
       
   483   g_cond_free_posix_impl,
       
   484   g_private_new_posix_impl,
       
   485   g_private_get_posix_impl,
       
   486   g_private_set_posix_impl,
       
   487   g_thread_create_posix_impl,
       
   488   g_thread_yield_posix_impl,
       
   489   g_thread_join_posix_impl,
       
   490   g_thread_exit_posix_impl,
       
   491   g_thread_set_priority_posix_impl,
       
   492   g_thread_self_posix_impl,
       
   493   g_thread_equal_posix_impl
       
   494 };
       
   495 
       
   496 #endif /* EMULATOR */