Back to index

php5  5.3.10
TSRM.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | Thread Safe Resource Manager                                         |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
00006    | This source file is subject to the TSRM license, that is bundled     |
00007    | with this package in the file LICENSE                                |
00008    +----------------------------------------------------------------------+
00009    | Authors:  Zeev Suraski <zeev@zend.com>                               |
00010    +----------------------------------------------------------------------+
00011 */
00012 
00013 #include "TSRM.h"
00014 
00015 #ifdef ZTS
00016 
00017 #include <stdio.h>
00018 
00019 #if HAVE_STDARG_H
00020 #include <stdarg.h>
00021 #endif
00022 
00023 typedef struct _tsrm_tls_entry tsrm_tls_entry;
00024 
00025 struct _tsrm_tls_entry {
00026        void **storage;
00027        int count;
00028        THREAD_T thread_id;
00029        tsrm_tls_entry *next;
00030 };
00031 
00032 
00033 typedef struct {
00034        size_t size;
00035        ts_allocate_ctor ctor;
00036        ts_allocate_dtor dtor;
00037        int done;
00038 } tsrm_resource_type;
00039 
00040 
00041 /* The memory manager table */
00042 static tsrm_tls_entry       **tsrm_tls_table=NULL;
00043 static int                         tsrm_tls_table_size;
00044 static ts_rsrc_id           id_count;
00045 
00046 /* The resource sizes table */
00047 static tsrm_resource_type   *resource_types_table=NULL;
00048 static int                                resource_types_table_size;
00049 
00050 
00051 static MUTEX_T tsmm_mutex;  /* thread-safe memory manager mutex */
00052 
00053 /* New thread handlers */
00054 static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler;
00055 static tsrm_thread_end_func_t tsrm_new_thread_end_handler;
00056 
00057 /* Debug support */
00058 int tsrm_error(int level, const char *format, ...);
00059 
00060 /* Read a resource from a thread's resource storage */
00061 static int tsrm_error_level;
00062 static FILE *tsrm_error_file;
00063 
00064 #if TSRM_DEBUG
00065 #define TSRM_ERROR(args) tsrm_error args
00066 #define TSRM_SAFE_RETURN_RSRC(array, offset, range)                                                                                                                            \
00067        {                                                                                                                                                                                                          \
00068               int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset);                                                                                                   \
00069                                                                                                                                                                                                                   \
00070               if (offset==0) {                                                                                                                                                                      \
00071                      return &array;                                                                                                                                                                        \
00072               } else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) {                                                                                \
00073                      TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X",           \
00074                                           unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset]));                       \
00075                      return array[unshuffled_offset];                                                                                                                                 \
00076               } else {                                                                                                                                                                                     \
00077                      TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)",                                                       \
00078                                           unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1)));    \
00079                      return NULL;                                                                                                                                                                   \
00080               }                                                                                                                                                                                                   \
00081        }
00082 #else
00083 #define TSRM_ERROR(args)
00084 #define TSRM_SAFE_RETURN_RSRC(array, offset, range)            \
00085        if (offset==0) {                                                             \
00086               return &array;                                                               \
00087        } else {                                                                            \
00088               return array[TSRM_UNSHUFFLE_RSRC_ID(offset)];    \
00089        }
00090 #endif
00091 
00092 #if defined(PTHREADS)
00093 /* Thread local storage */
00094 static pthread_key_t tls_key;
00095 # define tsrm_tls_set(what)        pthread_setspecific(tls_key, (void*)(what))
00096 # define tsrm_tls_get()                   pthread_getspecific(tls_key)
00097 
00098 #elif defined(TSRM_ST)
00099 static int tls_key;
00100 # define tsrm_tls_set(what)        st_thread_setspecific(tls_key, (void*)(what))
00101 # define tsrm_tls_get()                   st_thread_getspecific(tls_key)
00102 
00103 #elif defined(TSRM_WIN32)
00104 static DWORD tls_key;
00105 # define tsrm_tls_set(what)        TlsSetValue(tls_key, (void*)(what))
00106 # define tsrm_tls_get()                   TlsGetValue(tls_key)
00107 
00108 #elif defined(BETHREADS)
00109 static int32 tls_key;
00110 # define tsrm_tls_set(what)        tls_set(tls_key, (void*)(what))
00111 # define tsrm_tls_get()                   (tsrm_tls_entry*)tls_get(tls_key)
00112 
00113 #else
00114 # define tsrm_tls_set(what)
00115 # define tsrm_tls_get()                   NULL
00116 # warning tsrm_set_interpreter_context is probably broken on this platform
00117 #endif
00118 
00119 /* Startup TSRM (call once for the entire process) */
00120 TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename)
00121 {
00122 #if defined(GNUPTH)
00123        pth_init();
00124 #elif defined(PTHREADS)
00125        pthread_key_create( &tls_key, 0 );
00126 #elif defined(TSRM_ST)
00127        st_init();
00128        st_key_create(&tls_key, 0);
00129 #elif defined(TSRM_WIN32)
00130        tls_key = TlsAlloc();
00131 #elif defined(BETHREADS)
00132        tls_key = tls_allocate();
00133 #endif
00134 
00135        tsrm_error_file = stderr;
00136        tsrm_error_set(debug_level, debug_filename);
00137        tsrm_tls_table_size = expected_threads;
00138 
00139        tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
00140        if (!tsrm_tls_table) {
00141               TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
00142               return 0;
00143        }
00144        id_count=0;
00145 
00146        resource_types_table_size = expected_resources;
00147        resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
00148        if (!resource_types_table) {
00149               TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
00150               free(tsrm_tls_table);
00151               tsrm_tls_table = NULL;
00152               return 0;
00153        }
00154 
00155        tsmm_mutex = tsrm_mutex_alloc();
00156 
00157        tsrm_new_thread_begin_handler = tsrm_new_thread_end_handler = NULL;
00158 
00159        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
00160        return 1;
00161 }
00162 
00163 
00164 /* Shutdown TSRM (call once for the entire process) */
00165 TSRM_API void tsrm_shutdown(void)
00166 {
00167        int i;
00168 
00169        if (tsrm_tls_table) {
00170               for (i=0; i<tsrm_tls_table_size; i++) {
00171                      tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
00172 
00173                      while (p) {
00174                             int j;
00175 
00176                             next_p = p->next;
00177                             for (j=0; j<p->count; j++) {
00178                                    if (p->storage[j]) {
00179                                           if (resource_types_table && !resource_types_table[j].done && resource_types_table[j].dtor) {
00180                                                  resource_types_table[j].dtor(p->storage[j], &p->storage);
00181                                           }
00182                                           free(p->storage[j]);
00183                                    }
00184                             }
00185                             free(p->storage);
00186                             free(p);
00187                             p = next_p;
00188                      }
00189               }
00190               free(tsrm_tls_table);
00191               tsrm_tls_table = NULL;
00192        }
00193        if (resource_types_table) {
00194               free(resource_types_table);
00195               resource_types_table=NULL;
00196        }
00197        tsrm_mutex_free(tsmm_mutex);
00198        tsmm_mutex = NULL;
00199        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
00200        if (tsrm_error_file!=stderr) {
00201               fclose(tsrm_error_file);
00202        }
00203 #if defined(GNUPTH)
00204        pth_kill();
00205 #elif defined(PTHREADS)
00206        pthread_setspecific(tls_key, 0);
00207        pthread_key_delete(tls_key);
00208 #elif defined(TSRM_WIN32)
00209        TlsFree(tls_key);
00210 #endif
00211 }
00212 
00213 
00214 /* allocates a new thread-safe-resource id */
00215 TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
00216 {
00217        int i;
00218 
00219        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
00220 
00221        tsrm_mutex_lock(tsmm_mutex);
00222 
00223        /* obtain a resource id */
00224        *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
00225        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
00226 
00227        /* store the new resource type in the resource sizes table */
00228        if (resource_types_table_size < id_count) {
00229               resource_types_table = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
00230               if (!resource_types_table) {
00231                      tsrm_mutex_unlock(tsmm_mutex);
00232                      TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
00233                      *rsrc_id = 0;
00234                      return 0;
00235               }
00236               resource_types_table_size = id_count;
00237        }
00238        resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
00239        resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
00240        resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
00241        resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
00242 
00243        /* enlarge the arrays for the already active threads */
00244        for (i=0; i<tsrm_tls_table_size; i++) {
00245               tsrm_tls_entry *p = tsrm_tls_table[i];
00246 
00247               while (p) {
00248                      if (p->count < id_count) {
00249                             int j;
00250 
00251                             p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
00252                             for (j=p->count; j<id_count; j++) {
00253                                    p->storage[j] = (void *) malloc(resource_types_table[j].size);
00254                                    if (resource_types_table[j].ctor) {
00255                                           resource_types_table[j].ctor(p->storage[j], &p->storage);
00256                                    }
00257                             }
00258                             p->count = id_count;
00259                      }
00260                      p = p->next;
00261               }
00262        }
00263        tsrm_mutex_unlock(tsmm_mutex);
00264 
00265        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
00266        return *rsrc_id;
00267 }
00268 
00269 
00270 static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
00271 {
00272        int i;
00273 
00274        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
00275        (*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
00276        (*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
00277        (*thread_resources_ptr)->count = id_count;
00278        (*thread_resources_ptr)->thread_id = thread_id;
00279        (*thread_resources_ptr)->next = NULL;
00280 
00281        /* Set thread local storage to this new thread resources structure */
00282        tsrm_tls_set(*thread_resources_ptr);
00283 
00284        if (tsrm_new_thread_begin_handler) {
00285               tsrm_new_thread_begin_handler(thread_id, &((*thread_resources_ptr)->storage));
00286        }
00287        for (i=0; i<id_count; i++) {
00288               if (resource_types_table[i].done) {
00289                      (*thread_resources_ptr)->storage[i] = NULL;
00290               } else
00291               {
00292                      (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
00293                      if (resource_types_table[i].ctor) {
00294                             resource_types_table[i].ctor((*thread_resources_ptr)->storage[i], &(*thread_resources_ptr)->storage);
00295                      }
00296               }
00297        }
00298 
00299        if (tsrm_new_thread_end_handler) {
00300               tsrm_new_thread_end_handler(thread_id, &((*thread_resources_ptr)->storage));
00301        }
00302 
00303        tsrm_mutex_unlock(tsmm_mutex);
00304 }
00305 
00306 
00307 /* fetches the requested resource for the current thread */
00308 TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
00309 {
00310        THREAD_T thread_id;
00311        int hash_value;
00312        tsrm_tls_entry *thread_resources;
00313 
00314 #ifdef NETWARE
00315        /* The below if loop is added for NetWare to fix an abend while unloading PHP
00316         * when an Apache unload command is issued on the system console.
00317         * While exiting from PHP, at the end for some reason, this function is called
00318         * with tsrm_tls_table = NULL. When this happened, the server abends when
00319         * tsrm_tls_table is accessed since it is NULL.
00320         */
00321        if(tsrm_tls_table) {
00322 #endif
00323        if (!th_id) {
00324               /* Fast path for looking up the resources for the current
00325                * thread. Its used by just about every call to
00326                * ts_resource_ex(). This avoids the need for a mutex lock
00327                * and our hashtable lookup.
00328                */
00329               thread_resources = tsrm_tls_get();
00330 
00331               if (thread_resources) {
00332                      TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
00333                      /* Read a specific resource from the thread's resources.
00334                       * This is called outside of a mutex, so have to be aware about external
00335                       * changes to the structure as we read it.
00336                       */
00337                      TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
00338               }
00339               thread_id = tsrm_thread_id();
00340        } else {
00341               thread_id = *th_id;
00342        }
00343 
00344        TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
00345        tsrm_mutex_lock(tsmm_mutex);
00346 
00347        hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
00348        thread_resources = tsrm_tls_table[hash_value];
00349 
00350        if (!thread_resources) {
00351               allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
00352               return ts_resource_ex(id, &thread_id);
00353        } else {
00354                do {
00355                      if (thread_resources->thread_id == thread_id) {
00356                             break;
00357                      }
00358                      if (thread_resources->next) {
00359                             thread_resources = thread_resources->next;
00360                      } else {
00361                             allocate_new_resource(&thread_resources->next, thread_id);
00362                             return ts_resource_ex(id, &thread_id);
00363                             /*
00364                              * thread_resources = thread_resources->next;
00365                              * break;
00366                              */
00367                      }
00368                } while (thread_resources);
00369        }
00370        tsrm_mutex_unlock(tsmm_mutex);
00371        /* Read a specific resource from the thread's resources.
00372         * This is called outside of a mutex, so have to be aware about external
00373         * changes to the structure as we read it.
00374         */
00375        TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
00376 #ifdef NETWARE
00377        }      /* if(tsrm_tls_table) */
00378 #endif
00379 }
00380 
00381 /* frees an interpreter context.  You are responsible for making sure that
00382  * it is not linked into the TSRM hash, and not marked as the current interpreter */
00383 void tsrm_free_interpreter_context(void *context)
00384 {
00385        tsrm_tls_entry *next, *thread_resources = (tsrm_tls_entry*)context;
00386        int i;
00387 
00388        while (thread_resources) {
00389               next = thread_resources->next;
00390 
00391               for (i=0; i<thread_resources->count; i++) {
00392                      if (resource_types_table[i].dtor) {
00393                             resource_types_table[i].dtor(thread_resources->storage[i], &thread_resources->storage);
00394                      }
00395               }
00396               for (i=0; i<thread_resources->count; i++) {
00397                      free(thread_resources->storage[i]);
00398               }
00399               free(thread_resources->storage);
00400               free(thread_resources);
00401               thread_resources = next;
00402        }
00403 }
00404 
00405 void *tsrm_set_interpreter_context(void *new_ctx)
00406 {
00407        tsrm_tls_entry *current;
00408 
00409        current = tsrm_tls_get();
00410 
00411        /* TODO: unlink current from the global linked list, and replace it
00412         * it with the new context, protected by mutex where/if appropriate */
00413 
00414        /* Set thread local storage to this new thread resources structure */
00415        tsrm_tls_set(new_ctx);
00416 
00417        /* return old context, so caller can restore it when they're done */
00418        return current;
00419 }
00420 
00421 
00422 /* allocates a new interpreter context */
00423 void *tsrm_new_interpreter_context(void)
00424 {
00425        tsrm_tls_entry *new_ctx, *current;
00426        THREAD_T thread_id;
00427 
00428        thread_id = tsrm_thread_id();
00429        tsrm_mutex_lock(tsmm_mutex);
00430 
00431        current = tsrm_tls_get();
00432 
00433        allocate_new_resource(&new_ctx, thread_id);
00434        
00435        /* switch back to the context that was in use prior to our creation
00436         * of the new one */
00437        return tsrm_set_interpreter_context(current);
00438 }
00439 
00440 
00441 /* frees all resources allocated for the current thread */
00442 void ts_free_thread(void)
00443 {
00444        tsrm_tls_entry *thread_resources;
00445        int i;
00446        THREAD_T thread_id = tsrm_thread_id();
00447        int hash_value;
00448        tsrm_tls_entry *last=NULL;
00449 
00450        tsrm_mutex_lock(tsmm_mutex);
00451        hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
00452        thread_resources = tsrm_tls_table[hash_value];
00453 
00454        while (thread_resources) {
00455               if (thread_resources->thread_id == thread_id) {
00456                      for (i=0; i<thread_resources->count; i++) {
00457                             if (resource_types_table[i].dtor) {
00458                                    resource_types_table[i].dtor(thread_resources->storage[i], &thread_resources->storage);
00459                             }
00460                      }
00461                      for (i=0; i<thread_resources->count; i++) {
00462                             free(thread_resources->storage[i]);
00463                      }
00464                      free(thread_resources->storage);
00465                      if (last) {
00466                             last->next = thread_resources->next;
00467                      } else {
00468                             tsrm_tls_table[hash_value] = thread_resources->next;
00469                      }
00470                      tsrm_tls_set(0);
00471                      free(thread_resources);
00472                      break;
00473               }
00474               if (thread_resources->next) {
00475                      last = thread_resources;
00476               }
00477               thread_resources = thread_resources->next;
00478        }
00479        tsrm_mutex_unlock(tsmm_mutex);
00480 }
00481 
00482 
00483 /* frees all resources allocated for all threads except current */
00484 void ts_free_worker_threads(void)
00485 {
00486        tsrm_tls_entry *thread_resources;
00487        int i;
00488        THREAD_T thread_id = tsrm_thread_id();
00489        int hash_value;
00490        tsrm_tls_entry *last=NULL;
00491 
00492        tsrm_mutex_lock(tsmm_mutex);
00493        hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
00494        thread_resources = tsrm_tls_table[hash_value];
00495 
00496        while (thread_resources) {
00497               if (thread_resources->thread_id != thread_id) {
00498                      for (i=0; i<thread_resources->count; i++) {
00499                             if (resource_types_table[i].dtor) {
00500                                    resource_types_table[i].dtor(thread_resources->storage[i], &thread_resources->storage);
00501                             }
00502                      }
00503                      for (i=0; i<thread_resources->count; i++) {
00504                             free(thread_resources->storage[i]);
00505                      }
00506                      free(thread_resources->storage);
00507                      if (last) {
00508                             last->next = thread_resources->next;
00509                      } else {
00510                             tsrm_tls_table[hash_value] = thread_resources->next;
00511                      }
00512                      free(thread_resources);
00513                      if (last) {
00514                             thread_resources = last->next;
00515                      } else {
00516                             thread_resources = tsrm_tls_table[hash_value];
00517                      }
00518               } else {
00519                      if (thread_resources->next) {
00520                             last = thread_resources;
00521                      }
00522                      thread_resources = thread_resources->next;
00523               }
00524        }
00525        tsrm_mutex_unlock(tsmm_mutex);
00526 }
00527 
00528 
00529 /* deallocates all occurrences of a given id */
00530 void ts_free_id(ts_rsrc_id id)
00531 {
00532        int i;
00533        int j = TSRM_UNSHUFFLE_RSRC_ID(id);
00534 
00535        tsrm_mutex_lock(tsmm_mutex);
00536 
00537        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id));
00538 
00539        if (tsrm_tls_table) {
00540               for (i=0; i<tsrm_tls_table_size; i++) {
00541                      tsrm_tls_entry *p = tsrm_tls_table[i];
00542 
00543                      while (p) {
00544                             if (p->count > j && p->storage[j]) {
00545                                    if (resource_types_table && resource_types_table[j].dtor) {
00546                                           resource_types_table[j].dtor(p->storage[j], &p->storage);
00547                                    }
00548                                    free(p->storage[j]);
00549                                    p->storage[j] = NULL;
00550                             }
00551                             p = p->next;
00552                      }
00553               }
00554        }
00555        resource_types_table[j].done = 1;
00556 
00557        tsrm_mutex_unlock(tsmm_mutex);
00558 
00559        TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id));
00560 }
00561 
00562 
00563 
00564 
00565 /*
00566  * Utility Functions
00567  */
00568 
00569 /* Obtain the current thread id */
00570 TSRM_API THREAD_T tsrm_thread_id(void)
00571 {
00572 #ifdef TSRM_WIN32
00573        return GetCurrentThreadId();
00574 #elif defined(GNUPTH)
00575        return pth_self();
00576 #elif defined(PTHREADS)
00577        return pthread_self();
00578 #elif defined(NSAPI)
00579        return systhread_current();
00580 #elif defined(PI3WEB)
00581        return PIThread_getCurrent();
00582 #elif defined(TSRM_ST)
00583        return st_thread_self();
00584 #elif defined(BETHREADS)
00585        return find_thread(NULL);
00586 #endif
00587 }
00588 
00589 
00590 /* Allocate a mutex */
00591 TSRM_API MUTEX_T tsrm_mutex_alloc(void)
00592 {
00593        MUTEX_T mutexp;
00594 #ifdef TSRM_WIN32
00595        mutexp = malloc(sizeof(CRITICAL_SECTION));
00596        InitializeCriticalSection(mutexp);
00597 #elif defined(GNUPTH)
00598        mutexp = (MUTEX_T) malloc(sizeof(*mutexp));
00599        pth_mutex_init(mutexp);
00600 #elif defined(PTHREADS)
00601        mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
00602        pthread_mutex_init(mutexp,NULL);
00603 #elif defined(NSAPI)
00604        mutexp = crit_init();
00605 #elif defined(PI3WEB)
00606        mutexp = PIPlatform_allocLocalMutex();
00607 #elif defined(TSRM_ST)
00608        mutexp = st_mutex_new();
00609 #elif defined(BETHREADS)
00610        mutexp = (beos_ben*)malloc(sizeof(beos_ben));
00611        mutexp->ben = 0;
00612        mutexp->sem = create_sem(1, "PHP sempahore"); 
00613 #endif
00614 #ifdef THR_DEBUG
00615        printf("Mutex created thread: %d\n",mythreadid());
00616 #endif
00617        return( mutexp );
00618 }
00619 
00620 
00621 /* Free a mutex */
00622 TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
00623 {
00624        if (mutexp) {
00625 #ifdef TSRM_WIN32
00626               DeleteCriticalSection(mutexp);
00627               free(mutexp);
00628 #elif defined(GNUPTH)
00629               free(mutexp);
00630 #elif defined(PTHREADS)
00631               pthread_mutex_destroy(mutexp);
00632               free(mutexp);
00633 #elif defined(NSAPI)
00634               crit_terminate(mutexp);
00635 #elif defined(PI3WEB)
00636               PISync_delete(mutexp);
00637 #elif defined(TSRM_ST)
00638               st_mutex_destroy(mutexp);
00639 #elif defined(BETHREADS)
00640               delete_sem(mutexp->sem);
00641               free(mutexp);  
00642 #endif
00643        }
00644 #ifdef THR_DEBUG
00645        printf("Mutex freed thread: %d\n",mythreadid());
00646 #endif
00647 }
00648 
00649 
00650 /*
00651   Lock a mutex.
00652   A return value of 0 indicates success
00653 */
00654 TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
00655 {
00656        TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
00657 #ifdef TSRM_WIN32
00658        EnterCriticalSection(mutexp);
00659        return 0;
00660 #elif defined(GNUPTH)
00661        if (pth_mutex_acquire(mutexp, 0, NULL)) {
00662               return 0;
00663        }
00664        return -1;
00665 #elif defined(PTHREADS)
00666        return pthread_mutex_lock(mutexp);
00667 #elif defined(NSAPI)
00668        crit_enter(mutexp);
00669        return 0;
00670 #elif defined(PI3WEB)
00671        return PISync_lock(mutexp);
00672 #elif defined(TSRM_ST)
00673        return st_mutex_lock(mutexp);
00674 #elif defined(BETHREADS)
00675        if (atomic_add(&mutexp->ben, 1) != 0)  
00676               return acquire_sem(mutexp->sem);   
00677        return 0;
00678 #endif
00679 }
00680 
00681 
00682 /*
00683   Unlock a mutex.
00684   A return value of 0 indicates success
00685 */
00686 TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
00687 {
00688        TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
00689 #ifdef TSRM_WIN32
00690        LeaveCriticalSection(mutexp);
00691        return 0;
00692 #elif defined(GNUPTH)
00693        if (pth_mutex_release(mutexp)) {
00694               return 0;
00695        }
00696        return -1;
00697 #elif defined(PTHREADS)
00698        return pthread_mutex_unlock(mutexp);
00699 #elif defined(NSAPI)
00700        crit_exit(mutexp);
00701        return 0;
00702 #elif defined(PI3WEB)
00703        return PISync_unlock(mutexp);
00704 #elif defined(TSRM_ST)
00705        return st_mutex_unlock(mutexp);
00706 #elif defined(BETHREADS)
00707        if (atomic_add(&mutexp->ben, -1) != 1) 
00708               return release_sem(mutexp->sem);
00709        return 0;   
00710 #endif
00711 }
00712 
00713 
00714 TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
00715 {
00716        void *retval = (void *) tsrm_new_thread_begin_handler;
00717 
00718        tsrm_new_thread_begin_handler = new_thread_begin_handler;
00719        return retval;
00720 }
00721 
00722 
00723 TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
00724 {
00725        void *retval = (void *) tsrm_new_thread_end_handler;
00726 
00727        tsrm_new_thread_end_handler = new_thread_end_handler;
00728        return retval;
00729 }
00730 
00731 
00732 
00733 /*
00734  * Debug support
00735  */
00736 
00737 #if TSRM_DEBUG
00738 int tsrm_error(int level, const char *format, ...)
00739 {
00740        if (level<=tsrm_error_level) {
00741               va_list args;
00742               int size;
00743 
00744               fprintf(tsrm_error_file, "TSRM:  ");
00745               va_start(args, format);
00746               size = vfprintf(tsrm_error_file, format, args);
00747               va_end(args);
00748               fprintf(tsrm_error_file, "\n");
00749               fflush(tsrm_error_file);
00750               return size;
00751        } else {
00752               return 0;
00753        }
00754 }
00755 #endif
00756 
00757 
00758 void tsrm_error_set(int level, char *debug_filename)
00759 {
00760        tsrm_error_level = level;
00761 
00762 #if TSRM_DEBUG
00763        if (tsrm_error_file!=stderr) { /* close files opened earlier */
00764               fclose(tsrm_error_file);
00765        }
00766 
00767        if (debug_filename) {
00768               tsrm_error_file = fopen(debug_filename, "w");
00769               if (!tsrm_error_file) {
00770                      tsrm_error_file = stderr;
00771               }
00772        } else {
00773               tsrm_error_file = stderr;
00774        }
00775 #endif
00776 }
00777 
00778 #endif /* ZTS */