You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

666 lines
18 KiB

28 years ago
28 years ago
28 years ago
24 years ago
28 years ago
28 years ago
24 years ago
28 years ago
28 years ago
24 years ago
28 years ago
26 years ago
27 years ago
26 years ago
24 years ago
24 years ago
26 years ago
24 years ago
24 years ago
24 years ago
24 years ago
26 years ago
24 years ago
24 years ago
24 years ago
26 years ago
24 years ago
24 years ago
26 years ago
24 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Thread Safe Resource Manager |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1999, 2000, Andi Gutmans, Sascha Schumann, Zeev Suraski|
  6. | This source file is subject to the TSRM license, that is bundled |
  7. | with this package in the file LICENSE |
  8. +----------------------------------------------------------------------+
  9. | Authors: Zeev Suraski <zeev@zend.com> |
  10. +----------------------------------------------------------------------+
  11. */
  12. #include "TSRM.h"
  13. #ifdef ZTS
  14. #include <stdio.h>
  15. #if HAVE_STDARG_H
  16. #include <stdarg.h>
  17. #endif
  18. typedef struct _tsrm_tls_entry tsrm_tls_entry;
  19. struct _tsrm_tls_entry {
  20. void **storage;
  21. int count;
  22. THREAD_T thread_id;
  23. tsrm_tls_entry *next;
  24. };
  25. typedef struct {
  26. size_t size;
  27. ts_allocate_ctor ctor;
  28. ts_allocate_dtor dtor;
  29. } tsrm_resource_type;
  30. /* The memory manager table */
  31. static tsrm_tls_entry **tsrm_tls_table=NULL;
  32. static int tsrm_tls_table_size;
  33. static ts_rsrc_id id_count;
  34. /* The resource sizes table */
  35. static tsrm_resource_type *resource_types_table=NULL;
  36. static int resource_types_table_size;
  37. static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
  38. /* New thread handlers */
  39. static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler;
  40. static tsrm_thread_end_func_t tsrm_new_thread_end_handler;
  41. /* Debug support */
  42. int tsrm_error(int level, const char *format, ...);
  43. /* Read a resource from a thread's resource storage */
  44. static int tsrm_error_level;
  45. static FILE *tsrm_error_file;
  46. #if TSRM_DEBUG
  47. #define TSRM_ERROR(args) tsrm_error args
  48. #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
  49. { \
  50. int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset); \
  51. \
  52. if (offset==0) { \
  53. return &array; \
  54. } else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) { \
  55. TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X", \
  56. unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset])); \
  57. return array[unshuffled_offset]; \
  58. } else { \
  59. TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", \
  60. unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1))); \
  61. return NULL; \
  62. } \
  63. }
  64. #else
  65. #define TSRM_ERROR(args)
  66. #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
  67. if (offset==0) { \
  68. return &array; \
  69. } else { \
  70. return array[TSRM_UNSHUFFLE_RSRC_ID(offset)]; \
  71. }
  72. #endif
  73. #if defined(PTHREADS)
  74. /* Thread local storage */
  75. static pthread_key_t tls_key;
  76. #elif defined(TSRM_ST)
  77. static int tls_key;
  78. #elif defined(TSRM_WIN32)
  79. static DWORD tls_key;
  80. #elif defined(BETHREADS)
  81. static int32 tls_key;
  82. #endif
  83. /* Startup TSRM (call once for the entire process) */
  84. TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename)
  85. {
  86. #if defined(GNUPTH)
  87. pth_init();
  88. #elif defined(PTHREADS)
  89. pthread_key_create( &tls_key, 0 );
  90. #elif defined(TSRM_ST)
  91. st_init();
  92. st_key_create(&tls_key, 0);
  93. #elif defined(TSRM_WIN32)
  94. tls_key = TlsAlloc();
  95. #elif defined(BETHREADS)
  96. tls_key = tls_allocate();
  97. #endif
  98. tsrm_error_file = stderr;
  99. tsrm_error_set(debug_level, debug_filename);
  100. tsrm_tls_table_size = expected_threads;
  101. tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
  102. if (!tsrm_tls_table) {
  103. TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
  104. return 0;
  105. }
  106. id_count=0;
  107. resource_types_table_size = expected_resources;
  108. resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
  109. if (!resource_types_table) {
  110. TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
  111. free(tsrm_tls_table);
  112. tsrm_tls_table = NULL;
  113. return 0;
  114. }
  115. tsmm_mutex = tsrm_mutex_alloc();
  116. tsrm_new_thread_begin_handler = tsrm_new_thread_end_handler = NULL;
  117. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
  118. return 1;
  119. }
  120. /* Shutdown TSRM (call once for the entire process) */
  121. TSRM_API void tsrm_shutdown(void)
  122. {
  123. int i;
  124. if (tsrm_tls_table) {
  125. for (i=0; i<tsrm_tls_table_size; i++) {
  126. tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
  127. while (p) {
  128. int j;
  129. next_p = p->next;
  130. for (j=0; j<id_count; j++) {
  131. if (resource_types_table && resource_types_table[j].dtor) {
  132. resource_types_table[j].dtor(p->storage[j], &p->storage);
  133. }
  134. free(p->storage[j]);
  135. }
  136. free(p->storage);
  137. free(p);
  138. p = next_p;
  139. }
  140. }
  141. free(tsrm_tls_table);
  142. tsrm_tls_table = NULL;
  143. }
  144. if (resource_types_table) {
  145. free(resource_types_table);
  146. resource_types_table=NULL;
  147. }
  148. tsrm_mutex_free(tsmm_mutex);
  149. tsmm_mutex = NULL;
  150. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
  151. if (tsrm_error_file!=stderr) {
  152. fclose(tsrm_error_file);
  153. }
  154. #if defined(GNUPTH)
  155. pth_kill();
  156. #elif defined(PTHREADS)
  157. pthread_key_delete(tls_key);
  158. #elif defined(TSRM_WIN32)
  159. TlsFree(tls_key);
  160. #endif
  161. }
  162. /* allocates a new thread-safe-resource id */
  163. TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
  164. {
  165. int i;
  166. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
  167. tsrm_mutex_lock(tsmm_mutex);
  168. /* obtain a resource id */
  169. *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
  170. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
  171. /* store the new resource type in the resource sizes table */
  172. if (resource_types_table_size < id_count) {
  173. resource_types_table = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
  174. if (!resource_types_table) {
  175. tsrm_mutex_unlock(tsmm_mutex);
  176. TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
  177. *rsrc_id = 0;
  178. return 0;
  179. }
  180. resource_types_table_size = id_count;
  181. }
  182. resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
  183. resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
  184. resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
  185. /* enlarge the arrays for the already active threads */
  186. for (i=0; i<tsrm_tls_table_size; i++) {
  187. tsrm_tls_entry *p = tsrm_tls_table[i];
  188. while (p) {
  189. if (p->count < id_count) {
  190. int j;
  191. p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
  192. for (j=p->count; j<id_count; j++) {
  193. p->storage[j] = (void *) malloc(resource_types_table[j].size);
  194. if (resource_types_table[j].ctor) {
  195. resource_types_table[j].ctor(p->storage[j], &p->storage);
  196. }
  197. }
  198. p->count = id_count;
  199. }
  200. p = p->next;
  201. }
  202. }
  203. tsrm_mutex_unlock(tsmm_mutex);
  204. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
  205. return *rsrc_id;
  206. }
  207. static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
  208. {
  209. int i;
  210. TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
  211. (*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
  212. (*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
  213. (*thread_resources_ptr)->count = id_count;
  214. (*thread_resources_ptr)->thread_id = thread_id;
  215. (*thread_resources_ptr)->next = NULL;
  216. #if defined(PTHREADS)
  217. /* Set thread local storage to this new thread resources structure */
  218. pthread_setspecific(tls_key, (void *) *thread_resources_ptr);
  219. #elif defined(TSRM_ST)
  220. st_thread_setspecific(tls_key, (void *) *thread_resources_ptr);
  221. #elif defined(TSRM_WIN32)
  222. TlsSetValue(tls_key, (void *) *thread_resources_ptr);
  223. #elif defined(BETHREADS)
  224. tls_set(tls_key, (void*) *thread_resources_ptr);
  225. #endif
  226. if (tsrm_new_thread_begin_handler) {
  227. tsrm_new_thread_begin_handler(thread_id, &((*thread_resources_ptr)->storage));
  228. }
  229. for (i=0; i<id_count; i++) {
  230. (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
  231. if (resource_types_table[i].ctor) {
  232. resource_types_table[i].ctor((*thread_resources_ptr)->storage[i], &(*thread_resources_ptr)->storage);
  233. }
  234. }
  235. tsrm_mutex_unlock(tsmm_mutex);
  236. if (tsrm_new_thread_end_handler) {
  237. tsrm_new_thread_end_handler(thread_id, &((*thread_resources_ptr)->storage));
  238. }
  239. }
  240. /* fetches the requested resource for the current thread */
  241. TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
  242. {
  243. THREAD_T thread_id;
  244. int hash_value;
  245. tsrm_tls_entry *thread_resources;
  246. #ifdef NETWARE
  247. /* The below if loop is added for NetWare to fix an abend while unloading PHP
  248. * when an Apache unload command is issued on the system console.
  249. * While exiting from PHP, at the end for some reason, this function is called
  250. * with tsrm_tls_table = NULL. When this happened, the server abends when
  251. * tsrm_tls_table is accessed since it is NULL.
  252. */
  253. if(tsrm_tls_table) {
  254. #endif
  255. if (!th_id) {
  256. #if defined(PTHREADS)
  257. /* Fast path for looking up the resources for the current
  258. * thread. Its used by just about every call to
  259. * ts_resource_ex(). This avoids the need for a mutex lock
  260. * and our hashtable lookup.
  261. */
  262. thread_resources = pthread_getspecific(tls_key);
  263. #elif defined(TSRM_ST)
  264. thread_resources = st_thread_getspecific(tls_key);
  265. #elif defined(TSRM_WIN32)
  266. thread_resources = TlsGetValue(tls_key);
  267. #elif defined(BETHREADS)
  268. thread_resources = (tsrm_tls_entry*)tls_get(tls_key);
  269. #else
  270. thread_resources = NULL;
  271. #endif
  272. if (thread_resources) {
  273. TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
  274. /* Read a specific resource from the thread's resources.
  275. * This is called outside of a mutex, so have to be aware about external
  276. * changes to the structure as we read it.
  277. */
  278. TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
  279. }
  280. thread_id = tsrm_thread_id();
  281. } else {
  282. thread_id = *th_id;
  283. }
  284. TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
  285. tsrm_mutex_lock(tsmm_mutex);
  286. hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
  287. thread_resources = tsrm_tls_table[hash_value];
  288. if (!thread_resources) {
  289. allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
  290. return ts_resource_ex(id, &thread_id);
  291. } else {
  292. do {
  293. if (thread_resources->thread_id == thread_id) {
  294. break;
  295. }
  296. if (thread_resources->next) {
  297. thread_resources = thread_resources->next;
  298. } else {
  299. allocate_new_resource(&thread_resources->next, thread_id);
  300. return ts_resource_ex(id, &thread_id);
  301. /*
  302. * thread_resources = thread_resources->next;
  303. * break;
  304. */
  305. }
  306. } while (thread_resources);
  307. }
  308. tsrm_mutex_unlock(tsmm_mutex);
  309. /* Read a specific resource from the thread's resources.
  310. * This is called outside of a mutex, so have to be aware about external
  311. * changes to the structure as we read it.
  312. */
  313. TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
  314. #ifdef NETWARE
  315. } /* if(tsrm_tls_table) */
  316. #endif
  317. }
  318. /* frees all resources allocated for the current thread */
  319. void ts_free_thread(void)
  320. {
  321. tsrm_tls_entry *thread_resources;
  322. int i;
  323. THREAD_T thread_id = tsrm_thread_id();
  324. int hash_value;
  325. tsrm_tls_entry *last=NULL;
  326. tsrm_mutex_lock(tsmm_mutex);
  327. hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
  328. thread_resources = tsrm_tls_table[hash_value];
  329. while (thread_resources) {
  330. if (thread_resources->thread_id == thread_id) {
  331. for (i=0; i<thread_resources->count; i++) {
  332. if (resource_types_table[i].dtor) {
  333. resource_types_table[i].dtor(thread_resources->storage[i], &thread_resources->storage);
  334. }
  335. }
  336. for (i=0; i<thread_resources->count; i++) {
  337. free(thread_resources->storage[i]);
  338. }
  339. free(thread_resources->storage);
  340. if (last) {
  341. last->next = thread_resources->next;
  342. } else {
  343. tsrm_tls_table[hash_value] = thread_resources->next;
  344. }
  345. #if defined(PTHREADS)
  346. pthread_setspecific(tls_key, 0);
  347. #elif defined(TSRM_WIN32)
  348. TlsSetValue(tls_key, 0);
  349. #endif
  350. free(thread_resources);
  351. break;
  352. }
  353. if (thread_resources->next) {
  354. last = thread_resources;
  355. }
  356. thread_resources = thread_resources->next;
  357. }
  358. tsrm_mutex_unlock(tsmm_mutex);
  359. }
  360. /* deallocates all occurrences of a given id */
  361. void ts_free_id(ts_rsrc_id id)
  362. {
  363. }
  364. /*
  365. * Utility Functions
  366. */
  367. /* Obtain the current thread id */
  368. TSRM_API THREAD_T tsrm_thread_id(void)
  369. {
  370. #ifdef TSRM_WIN32
  371. return GetCurrentThreadId();
  372. #elif defined(NETWARE)
  373. /* There seems to be some problem with the LibC call: NXThreadGetId().
  374. * Due to this, the PHPMyAdmin application is abending in PHP calls.
  375. * Used the call, kCurrentThread instead and it works fine.
  376. */
  377. /* return NXThreadGetId(); */
  378. return kCurrentThread();
  379. #elif defined(GNUPTH)
  380. return pth_self();
  381. #elif defined(PTHREADS)
  382. return pthread_self();
  383. #elif defined(NSAPI)
  384. return systhread_current();
  385. #elif defined(PI3WEB)
  386. return PIThread_getCurrent();
  387. #elif defined(TSRM_ST)
  388. return st_thread_self();
  389. #elif defined(BETHREADS)
  390. return find_thread(NULL);
  391. #endif
  392. }
  393. /* Allocate a mutex */
  394. TSRM_API MUTEX_T tsrm_mutex_alloc(void)
  395. {
  396. MUTEX_T mutexp;
  397. #ifdef NETWARE
  398. #ifndef USE_MPK
  399. /* To use the Recursive Mutex Locking of LibC */
  400. long flags = NX_MUTEX_RECURSIVE;
  401. NXHierarchy_t order = 0;
  402. NX_LOCK_INFO_ALLOC (lockInfo, "PHP-TSRM", 0);
  403. #endif
  404. #endif
  405. #ifdef TSRM_WIN32
  406. mutexp = malloc(sizeof(CRITICAL_SECTION));
  407. InitializeCriticalSection(mutexp);
  408. #elif defined(NETWARE)
  409. #ifdef USE_MPK
  410. mutexp = kMutexAlloc((BYTE*)"PHP-TSRM");
  411. #else
  412. mutexp = NXMutexAlloc(flags, order, &lockInfo);
  413. #endif
  414. #elif defined(GNUPTH)
  415. mutexp = (MUTEX_T) malloc(sizeof(*mutexp));
  416. pth_mutex_init(mutexp);
  417. #elif defined(PTHREADS)
  418. mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
  419. pthread_mutex_init(mutexp,NULL);
  420. #elif defined(NSAPI)
  421. mutexp = crit_init();
  422. #elif defined(PI3WEB)
  423. mutexp = PIPlatform_allocLocalMutex();
  424. #elif defined(TSRM_ST)
  425. mutexp = st_mutex_new();
  426. #elif defined(BETHREADS)
  427. mutexp = (beos_ben*)malloc(sizeof(beos_ben));
  428. mutexp->ben = 0;
  429. mutexp->sem = create_sem(1, "PHP sempahore");
  430. #endif
  431. #ifdef THR_DEBUG
  432. printf("Mutex created thread: %d\n",mythreadid());
  433. #endif
  434. return( mutexp );
  435. }
  436. /* Free a mutex */
  437. TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
  438. {
  439. if (mutexp) {
  440. #ifdef TSRM_WIN32
  441. DeleteCriticalSection(mutexp);
  442. free(mutexp);
  443. #elif defined(NETWARE)
  444. #ifdef USE_MPK
  445. kMutexFree(mutexp);
  446. #else
  447. NXMutexFree(mutexp);
  448. #endif
  449. #elif defined(GNUPTH)
  450. free(mutexp);
  451. #elif defined(PTHREADS)
  452. pthread_mutex_destroy(mutexp);
  453. free(mutexp);
  454. #elif defined(NSAPI)
  455. crit_terminate(mutexp);
  456. #elif defined(PI3WEB)
  457. PISync_delete(mutexp);
  458. #elif defined(TSRM_ST)
  459. st_mutex_destroy(mutexp);
  460. #elif defined(BETHREADS)
  461. delete_sem(mutexp->sem);
  462. free(mutexp);
  463. #endif
  464. }
  465. #ifdef THR_DEBUG
  466. printf("Mutex freed thread: %d\n",mythreadid());
  467. #endif
  468. }
  469. /* Lock a mutex */
  470. TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
  471. {
  472. TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
  473. #ifdef TSRM_WIN32
  474. EnterCriticalSection(mutexp);
  475. return 1;
  476. #elif defined(NETWARE)
  477. #ifdef USE_MPK
  478. return kMutexLock(mutexp);
  479. #else
  480. return NXLock(mutexp);
  481. #endif
  482. #elif defined(GNUPTH)
  483. return pth_mutex_acquire(mutexp, 0, NULL);
  484. #elif defined(PTHREADS)
  485. return pthread_mutex_lock(mutexp);
  486. #elif defined(NSAPI)
  487. return crit_enter(mutexp);
  488. #elif defined(PI3WEB)
  489. return PISync_lock(mutexp);
  490. #elif defined(TSRM_ST)
  491. return st_mutex_lock(mutexp);
  492. #elif defined(BETHREADS)
  493. if (atomic_add(&mutexp->ben, 1) != 0)
  494. return acquire_sem(mutexp->sem);
  495. return 0;
  496. #endif
  497. }
  498. /* Unlock a mutex */
  499. TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
  500. {
  501. TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
  502. #ifdef TSRM_WIN32
  503. LeaveCriticalSection(mutexp);
  504. return 1;
  505. #elif defined(NETWARE)
  506. #ifdef USE_MPK
  507. return kMutexUnlock(mutexp);
  508. #else
  509. return NXUnlock(mutexp);
  510. #endif
  511. #elif defined(GNUPTH)
  512. return pth_mutex_release(mutexp);
  513. #elif defined(PTHREADS)
  514. return pthread_mutex_unlock(mutexp);
  515. #elif defined(NSAPI)
  516. return crit_exit(mutexp);
  517. #elif defined(PI3WEB)
  518. return PISync_unlock(mutexp);
  519. #elif defined(TSRM_ST)
  520. return st_mutex_unlock(mutexp);
  521. #elif defined(BETHREADS)
  522. if (atomic_add(&mutexp->ben, -1) != 1)
  523. return release_sem(mutexp->sem);
  524. return 0;
  525. #endif
  526. }
  527. TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
  528. {
  529. void *retval = (void *) tsrm_new_thread_begin_handler;
  530. tsrm_new_thread_begin_handler = new_thread_begin_handler;
  531. return retval;
  532. }
  533. TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
  534. {
  535. void *retval = (void *) tsrm_new_thread_end_handler;
  536. tsrm_new_thread_end_handler = new_thread_end_handler;
  537. return retval;
  538. }
  539. /*
  540. * Debug support
  541. */
  542. #if TSRM_DEBUG
  543. int tsrm_error(int level, const char *format, ...)
  544. {
  545. if (level<=tsrm_error_level) {
  546. va_list args;
  547. int size;
  548. fprintf(tsrm_error_file, "TSRM: ");
  549. va_start(args, format);
  550. size = vfprintf(tsrm_error_file, format, args);
  551. va_end(args);
  552. fprintf(tsrm_error_file, "\n");
  553. fflush(tsrm_error_file);
  554. return size;
  555. } else {
  556. return 0;
  557. }
  558. }
  559. #endif
  560. void tsrm_error_set(int level, char *debug_filename)
  561. {
  562. tsrm_error_level = level;
  563. #if TSRM_DEBUG
  564. if (tsrm_error_file!=stderr) { /* close files opened earlier */
  565. fclose(tsrm_error_file);
  566. }
  567. if (debug_filename) {
  568. tsrm_error_file = fopen(debug_filename, "w");
  569. if (!tsrm_error_file) {
  570. tsrm_error_file = stderr;
  571. }
  572. } else {
  573. tsrm_error_file = stderr;
  574. }
  575. #endif
  576. }
  577. #endif /* ZTS */