xml/libxml2libs/src/libxml2/libxml2_threads.c
changeset 0 e35f40988205
equal deleted inserted replaced
-1:000000000000 0:e35f40988205
       
     1 /**
       
     2  * libxml2_threads.c: set of generic threading related routines
       
     3  *
       
     4  * See Copyright for the status of this software.
       
     5  *
       
     6  * Gary Pennington <Gary.Pennington@uk.sun.com>
       
     7  * daniel@veillard.com
       
     8  * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
       
     9  */
       
    10 #define IN_LIBXML
       
    11 #include "xmlenglibxml.h"
       
    12 
       
    13 #include <string.h>
       
    14 
       
    15 #include <stdapis/libxml2/libxml2_globals.h>
       
    16 
       
    17 #ifdef HAVE_SYS_TYPES_H
       
    18 #include <sys/types.h>
       
    19 #endif
       
    20 
       
    21 #ifdef HAVE_UNISTD_H
       
    22 #include <unistd.h>
       
    23 #endif
       
    24 
       
    25 #ifdef HAVE_STDLIB_H
       
    26 #include <stdlib.h>
       
    27 #endif
       
    28 
       
    29 #ifdef HAVE_PTHREAD_H
       
    30 #include <pthread.h>
       
    31 #endif
       
    32 
       
    33 
       
    34 /* #define DEBUG_THREADS */
       
    35 
       
    36 /*
       
    37  * 
       
    38  *       
       
    39  *       
       
    40  */
       
    41 
       
    42 /*
       
    43  * xmlMutex are a simple mutual exception locks
       
    44  */
       
    45 struct _xmlMutex {
       
    46 #ifdef HAVE_PTHREAD_H
       
    47     pthread_mutex_t lock;
       
    48 #else
       
    49     int empty;
       
    50 #endif
       
    51 };
       
    52 
       
    53 /*
       
    54  * xmlRMutex are reentrant mutual exception locks
       
    55  */
       
    56 struct _xmlRMutex {
       
    57 #ifdef HAVE_PTHREAD_H
       
    58     pthread_mutex_t lock;
       
    59     unsigned int    held;
       
    60     unsigned int    waiters;
       
    61     pthread_t       tid;
       
    62     pthread_cond_t  cv;
       
    63 #else
       
    64     int empty;
       
    65 #endif
       
    66 };
       
    67 /*
       
    68  * This module still has some internal static data.
       
    69  *   - xmlLibraryLock a global lock
       
    70  *   - globalkey used for per-thread data
       
    71  */
       
    72 
       
    73 #ifdef HAVE_PTHREAD_H
       
    74 static pthread_key_t    globalkey;
       
    75 static pthread_t        mainthread;
       
    76 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
       
    77 #endif
       
    78 
       
    79 #ifdef LIBXML_THREAD_ENABLED
       
    80 static void xmlOnceInit(void);
       
    81 #endif
       
    82 
       
    83 /**
       
    84  * xmlNewMutex:
       
    85  *
       
    86  * xmlNewMutex() is used to allocate a libxml2 token struct for use in
       
    87  * synchronizing access to data.
       
    88  *
       
    89  * Returns a new simple mutex pointer or NULL in case of error
       
    90  *
       
    91  * OOM: possible --> NULL is returned (OOM flag is NOT SET)
       
    92  */
       
    93 XMLPUBFUNEXPORT xmlMutexPtr
       
    94 xmlNewMutex(void)
       
    95 {
       
    96     xmlMutexPtr tok;
       
    97 
       
    98     if ((tok = (xmlMutexPtr)malloc(sizeof(xmlMutex))) == NULL)
       
    99         return (NULL);
       
   100 #ifdef HAVE_PTHREAD_H
       
   101     pthread_mutex_init(&tok->lock, NULL);
       
   102 #endif
       
   103     return (tok);
       
   104 }
       
   105 
       
   106 /**
       
   107  * xmlFreeMutex:
       
   108  * @param tok the simple mutex
       
   109  *
       
   110  * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
       
   111  * struct.
       
   112  */
       
   113 XMLPUBFUNEXPORT void
       
   114 xmlFreeMutex(xmlMutexPtr tok)
       
   115 {
       
   116     if (tok == NULL) return;
       
   117 
       
   118 #ifdef HAVE_PTHREAD_H
       
   119     pthread_mutex_destroy(&tok->lock);
       
   120 #endif
       
   121     free(tok);
       
   122 }
       
   123 
       
   124 /**
       
   125  * xmlMutexLock:
       
   126  * @param tok the simple mutex
       
   127  *
       
   128  * xmlMutexLock() is used to lock a libxml2 token.
       
   129  */
       
   130 XMLPUBFUNEXPORT void
       
   131 xmlMutexLock(xmlMutexPtr tok)
       
   132 {
       
   133     if (tok == NULL)
       
   134         return;
       
   135 #ifdef HAVE_PTHREAD_H
       
   136     pthread_mutex_lock(&tok->lock);
       
   137 #endif
       
   138 
       
   139 }
       
   140 
       
   141 /**
       
   142  * xmlMutexUnlock:
       
   143  * @param tok the simple mutex
       
   144  *
       
   145  * xmlMutexUnlock() is used to unlock a libxml2 token.
       
   146  */
       
   147 XMLPUBFUNEXPORT void
       
   148 xmlMutexUnlock(xmlMutexPtr tok)
       
   149 {
       
   150     if (tok == NULL)
       
   151         return;
       
   152 #ifdef HAVE_PTHREAD_H
       
   153     pthread_mutex_unlock(&tok->lock);
       
   154 #endif
       
   155 }
       
   156 
       
   157 /**
       
   158  * xmlNewRMutex:
       
   159  *
       
   160  * xmlRNewMutex() is used to allocate a reentrant mutex for use in
       
   161  * synchronizing access to data. token_r is a re-entrant lock and thus useful
       
   162  * for synchronizing access to data structures that may be manipulated in a
       
   163  * recursive fashion.
       
   164  *
       
   165  * Returns the new reentrant mutex pointer or NULL in case of error
       
   166  */
       
   167 XMLPUBFUNEXPORT xmlRMutexPtr
       
   168 xmlNewRMutex(void)
       
   169 {
       
   170     xmlRMutexPtr tok;
       
   171 
       
   172     if ((tok = (xmlRMutexPtr)malloc(sizeof(xmlRMutex))) == NULL)
       
   173         return (NULL);
       
   174 #ifdef HAVE_PTHREAD_H
       
   175     pthread_mutex_init(&tok->lock, NULL);
       
   176     tok->held = 0;
       
   177     tok->waiters = 0;
       
   178     pthread_cond_init(&tok->cv, NULL);
       
   179 #endif
       
   180     return (tok);
       
   181 }
       
   182 
       
   183 #ifndef XMLENGINE_EXCLUDE_UNUSED
       
   184 /**
       
   185  * xmlFreeRMutex:
       
   186  * @param tok the reentrant mutex
       
   187  *
       
   188  * xmlRFreeMutex() is used to reclaim resources associated with a
       
   189  * reentrant mutex.
       
   190  */
       
   191 void
       
   192 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
       
   193 {
       
   194 #ifdef HAVE_PTHREAD_H
       
   195     pthread_mutex_destroy(&tok->lock);
       
   196 #endif
       
   197     free(tok);
       
   198 }
       
   199 #endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */
       
   200 
       
   201 /**
       
   202  * xmlRMutexLock:
       
   203  * @param tok the reentrant mutex
       
   204  *
       
   205  * xmlRMutexLock() is used to lock a libxml2 token_r.
       
   206  */
       
   207 XMLPUBFUNEXPORT void
       
   208 xmlRMutexLock(xmlRMutexPtr tok)
       
   209 {
       
   210     if (tok == NULL)
       
   211         return;
       
   212 #ifdef HAVE_PTHREAD_H
       
   213     pthread_mutex_lock(&tok->lock);
       
   214     if (tok->held) {
       
   215         if (pthread_equal(tok->tid, pthread_self())) {
       
   216             tok->held++;
       
   217             pthread_mutex_unlock(&tok->lock);
       
   218             return;
       
   219         } else {
       
   220             tok->waiters++;
       
   221             while (tok->held)
       
   222                 pthread_cond_wait(&tok->cv, &tok->lock);
       
   223             tok->waiters--;
       
   224         }
       
   225     }
       
   226     tok->tid = pthread_self();
       
   227     tok->held = 1;
       
   228     pthread_mutex_unlock(&tok->lock);
       
   229 #endif
       
   230 }
       
   231 
       
   232 /**
       
   233  * xmlRMutexUnlock:
       
   234  * @param tok the reentrant mutex
       
   235  *
       
   236  * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
       
   237  */
       
   238 XMLPUBFUNEXPORT void
       
   239 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
       
   240 {
       
   241     if (tok == NULL)
       
   242         return;
       
   243 #ifdef HAVE_PTHREAD_H
       
   244     pthread_mutex_lock(&tok->lock);
       
   245     tok->held--;
       
   246     if (tok->held == 0) {
       
   247         if (tok->waiters)
       
   248             pthread_cond_signal(&tok->cv);
       
   249         tok->tid = 0;
       
   250     }
       
   251     pthread_mutex_unlock(&tok->lock);
       
   252 #endif
       
   253 }
       
   254 
       
   255 /*************************************************************************
       
   256  *                                                                       *
       
   257  *          Per thread global state handling                             *
       
   258  *                                                                       *
       
   259  ************************************************************************/
       
   260 
       
   261 #ifdef LIBXML_THREAD_ENABLED
       
   262 /**
       
   263  * xmlFreeGlobalState:
       
   264  * @param state a thread global state
       
   265  *
       
   266  * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
       
   267  * global state. It is is used here to reclaim memory resources.
       
   268  */
       
   269 static void
       
   270 xmlFreeGlobalState(void *state)
       
   271 {
       
   272     free(state);
       
   273 }
       
   274 /**
       
   275  * xmlNewGlobalState:
       
   276  *
       
   277  * xmlNewGlobalState() allocates a global state. This structure is used to
       
   278  * hold all data for use by a thread when supporting backwards compatibility
       
   279  * of libxml2 to pre-thread-safe behaviour.
       
   280  *
       
   281  * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
       
   282  */
       
   283 static xmlGlobalStatePtr
       
   284 xmlNewGlobalState(void)
       
   285 {
       
   286     xmlGlobalState *gs;
       
   287 
       
   288     gs = malloc(sizeof(xmlGlobalState));
       
   289     if (gs == NULL)
       
   290         return(NULL);
       
   291 
       
   292     memset(gs, 0, sizeof(xmlGlobalState));
       
   293     xmlInitializeGlobalState(gs);
       
   294     return (gs);
       
   295 }
       
   296 
       
   297 #endif /* LIBXML_THREAD_ENABLED */
       
   298 
       
   299 
       
   300 /************************************************************************
       
   301  *                                                                      *
       
   302  *          Library wide thread interfaces                              *
       
   303  *                                                                      *
       
   304  ************************************************************************/
       
   305 
       
   306 /**
       
   307  * xmlGetThreadId:
       
   308  *
       
   309  * xmlGetThreadId() find the current thread ID number
       
   310  *
       
   311  * Returns the current thread ID number
       
   312  */
       
   313 XMLPUBFUNEXPORT int
       
   314 xmlGetThreadId(void)
       
   315 {
       
   316 #ifdef HAVE_PTHREAD_H
       
   317     return((int) pthread_self());
       
   318 #else
       
   319     return((int) 0);
       
   320 #endif
       
   321 }
       
   322 
       
   323 /**
       
   324  * xmlIsMainThread:
       
   325  *
       
   326  * xmlIsMainThread() check whether the current thread is the main thread.
       
   327  *
       
   328  * Returns 1 if the current thread is the main thread, 0 otherwise
       
   329  */
       
   330 XMLPUBFUNEXPORT int
       
   331 xmlIsMainThread(void)
       
   332 {
       
   333 #ifdef HAVE_PTHREAD_H
       
   334     pthread_once(&once_control, xmlOnceInit);
       
   335 #endif
       
   336 
       
   337 #ifdef DEBUG_THREADS
       
   338     xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
       
   339 #endif
       
   340 #ifdef HAVE_PTHREAD_H
       
   341     return(mainthread == pthread_self());
       
   342 #else
       
   343     return(1);
       
   344 #endif
       
   345 }
       
   346 
       
   347 /**
       
   348  * xmlLockLibrary:
       
   349  *
       
   350  * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
       
   351  * library.
       
   352  */
       
   353 XMLPUBFUNEXPORT void
       
   354 xmlLockLibrary(void)
       
   355 {
       
   356 #ifdef DEBUG_THREADS
       
   357     xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
       
   358 #endif
       
   359     xmlRMutexLock(xmlLibraryLock);
       
   360 }
       
   361 
       
   362 /**
       
   363  * xmlUnlockLibrary:
       
   364  *
       
   365  * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
       
   366  * library.
       
   367  */
       
   368 XMLPUBFUNEXPORT void
       
   369 xmlUnlockLibrary(void)
       
   370 {
       
   371 #ifdef DEBUG_THREADS
       
   372     xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
       
   373 #endif
       
   374     xmlRMutexUnlock(xmlLibraryLock);
       
   375 }
       
   376 
       
   377 /**
       
   378  * xmlInitThreads:
       
   379  *
       
   380  * xmlInitThreads() is used to to initialize all the thread related
       
   381  * data of the libxml2 library.
       
   382  */
       
   383 XMLPUBFUNEXPORT void
       
   384 xmlInitThreads(void)
       
   385 {
       
   386 #ifdef DEBUG_THREADS
       
   387     xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
       
   388 #endif
       
   389 }
       
   390 
       
   391 /**
       
   392  * xmlCleanupThreads:
       
   393  *
       
   394  * xmlCleanupThreads() is used to to cleanup all the thread related
       
   395  * data of the libxml2 library once processing has ended.
       
   396  */
       
   397 XMLPUBFUNEXPORT void
       
   398 xmlCleanupThreads(void)
       
   399 {
       
   400 #ifdef DEBUG_THREADS
       
   401     xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
       
   402 #endif
       
   403 }
       
   404 
       
   405 #ifdef LIBXML_THREAD_ENABLED
       
   406 /**
       
   407  * xmlOnceInit
       
   408  *
       
   409  * xmlOnceInit() is used to initialize the value of mainthread for use
       
   410  * in other routines. This function should only be called using
       
   411  * pthread_once() in association with the once_control variable to ensure
       
   412  * that the function is only called once. See man pthread_once for more
       
   413  * details.
       
   414  */
       
   415 static void
       
   416 xmlOnceInit(void) {
       
   417 #ifdef HAVE_PTHREAD_H
       
   418     (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
       
   419     mainthread = pthread_self();
       
   420 #endif
       
   421 
       
   422 }
       
   423 
       
   424 #endif