~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbxt/src/thread_xt.cc

  • Committer: Brian Aker
  • Date: 2009-10-15 00:22:33 UTC
  • mto: (1183.1.11 merge)
  • mto: This revision was merged to the branch mainline in revision 1198.
  • Revision ID: brian@gaz-20091015002233-fa4ao2mbc67wls91
First pass of information engine. OMG, ponies... is it so much easier to
deal with creating and engine.

The list table iterator though... its ass, needs to go. We should also
abstract out share. Very few engines need a custom one. Just say'in

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2005 PrimeBase Technologies GmbH
2
 
 *
3
 
 * PrimeBase XT
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
 
 *
19
 
 * 2005-01-03   Paul McCullagh
20
 
 *
21
 
 * H&G2JCtL
22
 
 */
23
 
 
24
 
#include "xt_config.h"
25
 
 
26
 
#ifdef DRIZZLED
27
 
#include <bitset>
28
 
#endif
29
 
 
30
 
#ifndef XT_WIN
31
 
#include <unistd.h>
32
 
#include <sys/time.h>
33
 
#include <sys/resource.h>
34
 
#endif
35
 
#include <time.h>
36
 
#include <stdarg.h>
37
 
#include <signal.h>
38
 
#include <stdlib.h>
39
 
#include <ctype.h>
40
 
#include <errno.h>
41
 
 
42
 
#include "xt_defs.h"
43
 
#include "strutil_xt.h"
44
 
#include "pthread_xt.h"
45
 
#include "thread_xt.h"
46
 
#include "memory_xt.h"
47
 
#include "sortedlist_xt.h"
48
 
#include "trace_xt.h"
49
 
#include "myxt_xt.h"
50
 
#include "database_xt.h"
51
 
 
52
 
#ifdef DEBUG
53
 
//#define DEBUG_NO_ACTIVITY
54
 
#endif
55
 
 
56
 
void xt_db_exit_thread(XTThreadPtr self);
57
 
 
58
 
static void thr_accumulate_statistics(XTThreadPtr self);
59
 
 
60
 
#define XT_NO_THREAD_ID         0
61
 
#define XT_SYS_THREAD_ID        1
62
 
#define XT_MIN_THREAD_ID        2
63
 
 
64
 
/*
65
 
 * -----------------------------------------------------------------------
66
 
 * THREAD GLOBALS
67
 
 */
68
 
 
69
 
xtPublic u_int                          xt_thr_maximum_threads;
70
 
xtPublic u_int                          xt_thr_current_thread_count;
71
 
xtPublic u_int                          xt_thr_current_max_threads;
72
 
 
73
 
/* This structure is a double linked list of thread, with a wait
74
 
 * condition on it.
75
 
 */
76
 
static XTLinkedListPtr          thr_list;
77
 
 
78
 
/* This structure maps thread ID's to thread pointers. */
79
 
THR_ARRAY_LOCK_TYPE                     xt_thr_array_resize_lock;
80
 
xtPublic XTThreadDataRec        *xt_thr_array;
81
 
static xt_mutex_type            thr_array_lock;
82
 
 
83
 
/* Global accumulated statistics: */
84
 
static XTStatisticsRec          thr_statistics;
85
 
 
86
 
#ifdef DEBUG
87
 
static void break_in_assertion(c_char *expr, c_char *func, c_char *file, u_int line)
88
 
{
89
 
        printf("%s(%s:%d) %s\n", func, file, (int) line, expr);
90
 
}
91
 
#endif
92
 
 
93
 
/*
94
 
 * -----------------------------------------------------------------------
95
 
 * Lock task
96
 
 */
97
 
 
98
 
void XTLockTask::tk_init(struct XTThread *self)
99
 
{
100
 
        xt_init_mutex_with_autoname(self, &lt_mutex);
101
 
}
102
 
 
103
 
void XTLockTask::tk_exit()
104
 
{
105
 
        xt_free_mutex(&lt_mutex);
106
 
        XTTask::tk_exit();
107
 
}
108
 
 
109
 
void XTLockTask::tk_lock()
110
 
111
 
        xt_lock_mutex_ns(&lt_mutex);
112
 
}
113
 
 
114
 
void XTLockTask::tk_unlock()
115
 
116
 
        xt_unlock_mutex_ns(&lt_mutex);
117
 
}
118
 
 
119
 
/*
120
 
 * -----------------------------------------------------------------------
121
 
 * Error logging
122
 
 */
123
 
 
124
 
static xt_mutex_type    log_mutex;
125
 
static int                              log_level = 0;
126
 
static FILE                             *log_file = NULL;
127
 
static xtBool                   log_newline = TRUE;
128
 
 
129
 
xtPublic xtBool xt_init_logging(void)
130
 
{
131
 
        int err;
132
 
 
133
 
        log_file = stdout;
134
 
        log_level = XT_LOG_TRACE;
135
 
        err = xt_p_mutex_init_with_autoname(&log_mutex, NULL);
136
 
        if (err) {
137
 
                xt_log_errno(XT_NS_CONTEXT, err);
138
 
                log_file = NULL;
139
 
                log_level = 0;
140
 
                return FALSE;
141
 
        }
142
 
        if (!xt_init_trace()) {
143
 
                xt_exit_logging();
144
 
                return FALSE;
145
 
        }
146
 
        return TRUE;
147
 
}
148
 
 
149
 
xtPublic void xt_exit_logging(void)
150
 
{
151
 
        if (log_file) {
152
 
                xt_free_mutex(&log_mutex);
153
 
                log_file = NULL;
154
 
        }
155
 
        xt_exit_trace();
156
 
}
157
 
 
158
 
xtPublic void xt_get_now(char *buffer, size_t len)
159
 
{
160
 
        time_t          ticks;
161
 
        struct tm       ltime;
162
 
 
163
 
        ticks = time(NULL);
164
 
        if (ticks == (time_t) -1) {
165
 
#ifdef XT_WIN
166
 
                printf(buffer, "** error %d getting time **", errno);
167
 
#else
168
 
                snprintf(buffer, len, "** error %d getting time **", errno);
169
 
#endif
170
 
                return;
171
 
        }
172
 
        localtime_r(&ticks, &ltime);
173
 
        strftime(buffer, len, "%y%m%d %H:%M:%S", &ltime);
174
 
}
175
 
 
176
 
static void thr_log_newline(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level)
177
 
{
178
 
        c_char  *level_str;
179
 
        char    time_str[200];
180
 
        char    thr_name[XT_THR_NAME_SIZE+3];
181
 
 
182
 
        xt_get_now(time_str, 200);
183
 
        if (self && *self->t_name) {
184
 
                xt_strcpy(XT_THR_NAME_SIZE+3, thr_name, " ");
185
 
                xt_strcat(XT_THR_NAME_SIZE+3, thr_name, self->t_name);
186
 
        }
187
 
        else
188
 
                thr_name[0] = 0;
189
 
        switch (level) {
190
 
                case XT_LOG_FATAL: level_str = " [Fatal]"; break;
191
 
                case XT_LOG_ERROR: level_str = " [Error]"; break;
192
 
                case XT_LOG_WARNING: level_str = " [Warning]"; break;
193
 
                case XT_LOG_INFO: level_str = " [Note]"; break;
194
 
                case XT_LOG_TRACE: level_str = " [Trace]"; break;
195
 
                default: level_str = " "; break;
196
 
        }
197
 
        if (func && *func && *func != '-') {
198
 
                char func_name[XT_MAX_FUNC_NAME_SIZE];
199
 
 
200
 
                xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, func_name, func, '(');
201
 
                if (file && *file)
202
 
                        fprintf(log_file, "%s%s%s %s(%s:%d) ", time_str, level_str, thr_name, func_name, xt_last_name_of_path(file), line);
203
 
                else
204
 
                        fprintf(log_file, "%s%s%s %s() ", time_str, level_str, thr_name, func_name);
205
 
        }
206
 
        else {
207
 
                if (file && *file)
208
 
                        fprintf(log_file, "%s%s%s [%s:%d] ", time_str, level_str, thr_name, xt_last_name_of_path(file), line);
209
 
                else
210
 
                        fprintf(log_file, "%s%s%s ", time_str, level_str, thr_name);
211
 
        }
212
 
}
213
 
 
214
 
#ifdef XT_WIN
215
 
/* Windows uses printf()!! */
216
 
#define DEFAULT_LOG_BUFFER_SIZE                 2000
217
 
#else
218
 
#ifdef DEBUG
219
 
#define DEFAULT_LOG_BUFFER_SIZE                 10
220
 
#else
221
 
#define DEFAULT_LOG_BUFFER_SIZE                 2000
222
 
#endif
223
 
#endif
224
 
 
225
 
void xt_log_flush(XTThreadPtr XT_UNUSED(self))
226
 
{
227
 
        fflush(log_file);
228
 
}
229
 
 
230
 
/*
231
 
 * Log the given formated string information to the log file.
232
 
 * Before each new line, this function writes the
233
 
 * log header, which includes the time, log level,
234
 
 * and source file and line number (optional).
235
 
 */
236
 
static void thr_log_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, va_list ap)
237
 
{
238
 
        char buffer[DEFAULT_LOG_BUFFER_SIZE];
239
 
        char *log_string = NULL;
240
 
 
241
 
        if (level > log_level)
242
 
                return;
243
 
 
244
 
        xt_lock_mutex_ns(&log_mutex);
245
 
 
246
 
#ifdef XT_WIN
247
 
        vsprintf(buffer, fmt, ap);
248
 
        log_string = buffer;
249
 
#else
250
 
#if !defined(va_copy) || defined(XT_SOLARIS)
251
 
        int len;
252
 
 
253
 
        len = vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE-1, fmt, ap);
254
 
        if (len > DEFAULT_LOG_BUFFER_SIZE-1)
255
 
                len = DEFAULT_LOG_BUFFER_SIZE-1;
256
 
        buffer[len] = 0;
257
 
        log_string = buffer;
258
 
#else
259
 
        /* Use the buffer, unless it is too small */
260
 
        va_list ap2;
261
 
        int bufsize;
262
 
 
263
 
        va_copy(ap2, ap);
264
 
        bufsize = vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE, fmt, ap);
265
 
        if (bufsize >= DEFAULT_LOG_BUFFER_SIZE) {
266
 
                log_string = (char *) malloc(bufsize + 1);
267
 
                if (vsnprintf(log_string, bufsize + 1, fmt, ap2) > bufsize) {
268
 
                        free(log_string);
269
 
                        log_string = NULL;
270
 
                }
271
 
        }
272
 
        else
273
 
                log_string = buffer;
274
 
#endif
275
 
#endif
276
 
 
277
 
        if (log_string) {
278
 
                char *str, *str_end, tmp_ch;
279
 
 
280
 
                str = log_string;
281
 
                while (*str) {
282
 
                        if (log_newline) {
283
 
                                thr_log_newline(self, func, file, line, level);
284
 
                                log_newline = FALSE;
285
 
                        }
286
 
                        str_end = strchr(str, '\n');
287
 
                        if (str_end) {
288
 
                                str_end++;
289
 
                                tmp_ch = *str_end;
290
 
                                *str_end = 0;
291
 
                                log_newline = TRUE;
292
 
                        }
293
 
                        else {
294
 
                                str_end = str + strlen(str);
295
 
                                tmp_ch = 0;
296
 
                        }
297
 
                        fprintf(log_file, "%s", str);
298
 
                        fflush(log_file);
299
 
                        *str_end = tmp_ch;
300
 
                        str = str_end;
301
 
                }
302
 
 
303
 
                if (log_string != buffer)
304
 
                        free(log_string);
305
 
        }
306
 
 
307
 
        xt_unlock_mutex_ns(&log_mutex);
308
 
}
309
 
 
310
 
xtPublic void xt_logf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, ...)
311
 
{
312
 
        va_list ap;
313
 
 
314
 
        va_start(ap, fmt);
315
 
        thr_log_va(self, func, file, line, level, fmt, ap);
316
 
        va_end(ap);
317
 
}
318
 
 
319
 
xtPublic void xt_log(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *string)
320
 
{
321
 
        xt_logf(self, func, file, line, level, "%s", string);
322
 
}
323
 
 
324
 
static int thr_log_error_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, va_list ap)
325
 
{
326
 
        int             default_level;
327
 
        char    xt_err_string[50];
328
 
 
329
 
        *xt_err_string = 0;
330
 
        switch (xt_err) {
331
 
                case XT_ASSERTION_FAILURE:
332
 
                        strcpy(xt_err_string, "Assertion");
333
 
                        default_level = XT_LOG_FATAL;
334
 
                        break;
335
 
                case XT_SYSTEM_ERROR:
336
 
                        strcpy(xt_err_string, "errno");
337
 
                        default_level = XT_LOG_ERROR;
338
 
                        break;
339
 
                case XT_SIGNAL_CAUGHT:
340
 
                        strcpy(xt_err_string, "Signal");
341
 
                        default_level = XT_LOG_ERROR;
342
 
                        break;
343
 
                default:
344
 
                        sprintf(xt_err_string, "%d", xt_err);
345
 
                        default_level = XT_LOG_ERROR;
346
 
                        break;
347
 
        }
348
 
        if (level == XT_LOG_DEFAULT)
349
 
                level = default_level;
350
 
 
351
 
        if (*xt_err_string) {
352
 
                if (sys_err)
353
 
                        xt_logf(self, func, file, line, level, "%s (%d): ", xt_err_string, sys_err);
354
 
                else
355
 
                        xt_logf(self, func, file, line, level, "%s: ", xt_err_string);
356
 
        }
357
 
        thr_log_va(self, func, file, line, level, fmt, ap);
358
 
        xt_logf(self, func, file, line, level, "\n");
359
 
        return level;
360
 
}
361
 
 
362
 
/* The function returns the actual log level used. */
363
 
xtPublic int xt_log_errorf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, ...)
364
 
{
365
 
        va_list ap;
366
 
 
367
 
        va_start(ap, fmt);
368
 
        level = thr_log_error_va(self, func, file, line, level, xt_err, sys_err, fmt, ap);
369
 
        va_end(ap);
370
 
        return level;
371
 
}
372
 
 
373
 
/* The function returns the actual log level used. */
374
 
xtPublic int xt_log_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *string)
375
 
{
376
 
        return xt_log_errorf(self, func, file, line, level, xt_err, sys_err, "%s", string);
377
 
}
378
 
 
379
 
xtPublic void xt_log_exception(XTThreadPtr self, XTExceptionPtr e, int level)
380
 
{
381
 
        ASSERT_NS(e->e_xt_err);
382
 
        level = xt_log_error(
383
 
                self,
384
 
                e->e_func_name,
385
 
                e->e_source_file,
386
 
                e->e_source_line,
387
 
                level,
388
 
                e->e_xt_err,
389
 
                e->e_sys_err,
390
 
                e->e_err_msg);
391
 
        /* Dump the catch trace: */
392
 
        if (*e->e_catch_trace)
393
 
                xt_logf(self, NULL, NULL, 0, level, "%s", e->e_catch_trace);
394
 
}
395
 
 
396
 
xtPublic void xt_log_and_clear_exception(XTThreadPtr self)
397
 
{
398
 
        xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT);
399
 
        xt_clear_exception(self);
400
 
}
401
 
 
402
 
xtPublic void xt_log_and_clear_exception_ns(void)
403
 
{
404
 
        xt_log_and_clear_exception(xt_get_self());
405
 
}
406
 
 
407
 
xtPublic void xt_log_and_clear_warning(XTThreadPtr self)
408
 
{
409
 
        xt_log_exception(self, &self->t_exception, XT_LOG_WARNING);
410
 
        xt_clear_exception(self);
411
 
}
412
 
 
413
 
xtPublic void xt_log_and_clear_warning_ns(void)
414
 
{
415
 
        xt_log_and_clear_warning(xt_get_self());
416
 
}
417
 
 
418
 
/*
419
 
 * -----------------------------------------------------------------------
420
 
 * Exceptions
421
 
 */
422
 
 
423
 
static void thr_add_catch_trace(XTExceptionPtr e, c_char *func, c_char *file, u_int line)
424
 
{
425
 
        if (func && *func && *func != '-') {
426
 
                xt_strcat_term(XT_CATCH_TRACE_SIZE, e->e_catch_trace, func, '(');
427
 
                xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "(");
428
 
        }
429
 
        if (file && *file) {
430
 
                xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, xt_last_name_of_path(file));
431
 
                if (line) {
432
 
                        char buffer[40];
433
 
 
434
 
                        sprintf(buffer, "%u", line);
435
 
                        xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ":");
436
 
                        xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, buffer);
437
 
                }
438
 
        }
439
 
        if (func && *func && *func != '-')
440
 
                xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ")");
441
 
        xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "\n");
442
 
}
443
 
 
444
 
static void thr_save_error_va(XTExceptionPtr e, XTThreadPtr self, xtBool throw_it, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, va_list ap)
445
 
{
446
 
        int i;
447
 
 
448
 
        if (!e)
449
 
                return;
450
 
 
451
 
        e->e_xt_err = xt_err;
452
 
        e->e_sys_err = sys_err;
453
 
        vsnprintf(e->e_err_msg, XT_ERR_MSG_SIZE, fmt, ap);
454
 
 
455
 
        /* Make the first character of the message upper case: */
456
 
        /* This did not work for foreign languages! */
457
 
        if (e->e_err_msg[0] >= 'a' && e->e_err_msg[0] <= 'z')
458
 
                e->e_err_msg[0] = (char) toupper(e->e_err_msg[0]);
459
 
 
460
 
        if (func && *func && *func != '-')
461
 
                xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, e->e_func_name, func, '(');
462
 
        else
463
 
                *e->e_func_name = 0;
464
 
        if (file && *file) {
465
 
                xt_strcpy(XT_SOURCE_FILE_NAME_SIZE, e->e_source_file, xt_last_name_of_path(file));
466
 
                e->e_source_line = line;
467
 
        }
468
 
        else {
469
 
                *e->e_source_file = 0;
470
 
                e->e_source_line = 0;
471
 
        }
472
 
        *e->e_catch_trace = 0;
473
 
 
474
 
        if (!self)
475
 
                return;
476
 
 
477
 
        /* Create a stack trace for this exception: */
478
 
        thr_add_catch_trace(e, func, file, line);
479
 
        for (i=self->t_call_top-1; i>=0; i--)
480
 
                thr_add_catch_trace(e, self->t_call_stack[i].cs_func, self->t_call_stack[i].cs_file, self->t_call_stack[i].cs_line);
481
 
 
482
 
        if (throw_it)
483
 
                xt_throw(self);
484
 
}
485
 
 
486
 
/*
487
 
 * -----------------------------------------------------------------------
488
 
 * THROWING EXCEPTIONS
489
 
 */
490
 
 
491
 
/* If we have to allocate resources and the hold them temporarily during which
492
 
 * time an exception could occur, then these functions provide a holding
493
 
 * place for the data, which will be freed in the case of an exception.
494
 
 *
495
 
 * Note: the free functions could themselves allocated resources.
496
 
 * to make sure all things work out we only remove the resource from
497
 
 * then stack when it is freed.
498
 
 */
499
 
static void thr_free_resources(XTThreadPtr self, XTResourcePtr top)
500
 
{
501
 
        XTResourcePtr           rp;
502
 
        XTThreadFreeFunc        free_func;
503
 
 
504
 
        if (!top)
505
 
                return;
506
 
        while (self->t_res_top > top) {
507
 
                /* Pop the top resource: */
508
 
                rp = (XTResourcePtr) (((char *) self->t_res_top) - self->t_res_top->r_prev_size);
509
 
 
510
 
                /* Free the resource: */
511
 
                if (rp->r_free_func) {
512
 
                        free_func = rp->r_free_func;
513
 
                        rp->r_free_func = NULL;
514
 
                        free_func(self, rp->r_data);
515
 
                }
516
 
 
517
 
                self->t_res_top = rp;
518
 
        }
519
 
}
520
 
 
521
 
xtPublic void xt_bug(XTThreadPtr XT_UNUSED(self))
522
 
{
523
 
        static int *bug_ptr = NULL;
524
 
        
525
 
        bug_ptr = NULL;
526
 
}
527
 
 
528
 
/*
529
 
 * This function is called when an exception is caught.
530
 
 * It restores the function call top and frees
531
 
 * any resource allocated by lower levels.
532
 
 */
533
 
xtPublic void xt_caught(XTThreadPtr self)
534
 
{
535
 
        /* Restore the call top: */
536
 
        self->t_call_top = self->t_jmp_env[self->t_jmp_depth].jb_call_top;
537
 
 
538
 
        /* Free the temporary data that would otherwize be lost
539
 
         * This should do nothing, because we actually free things on throw
540
 
         * (se below).
541
 
         */
542
 
        thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth].jb_res_top);
543
 
}
544
 
 
545
 
xtPublic void xt_enter_exception_handler(XTThreadPtr self, XTExceptionPtr e)
546
 
{
547
 
        ASSERT_NS(self->t_exception.e_xt_err);
548
 
        self->t_in_handler++;
549
 
        *e = self->t_exception;
550
 
        /* If freeing resources, generates an error, we will know: */
551
 
        self->t_exception.e_xt_err = 0;
552
 
}
553
 
 
554
 
xtPublic void xt_exit_exception_handler(XTThreadPtr self, XTExceptionPtr e)
555
 
{
556
 
        if (self->t_exception.e_xt_err)
557
 
                xt_log_and_clear_exception(self);
558
 
        /* Restore the exception: */
559
 
        self->t_exception = *e;
560
 
        self->t_in_handler--;
561
 
}
562
 
 
563
 
/* Throw an already registered error: */
564
 
xtPublic void xt_throw(XTThreadPtr self)
565
 
{
566
 
        if (self) {
567
 
                /* We should not throw an exception in an exception handler! */
568
 
                ASSERT_NS(!self->t_in_handler);
569
 
 
570
 
                /* We cannot actually handle the situation that an exception is
571
 
                 * thrown when freeing resources here!
572
 
                 */
573
 
                if (self->t_jmp_depth > 0 && self->t_jmp_depth <= XT_MAX_JMP) {
574
 
                        /* Save the exception, in case it is overwritten during free
575
 
                         * resources!
576
 
                         */
577
 
                        XTException e;
578
 
 
579
 
                        /* As recommended by Barry: free the resources before the stack is invalid! */
580
 
                        xt_enter_exception_handler(self, &e);
581
 
                        thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth-1].jb_res_top);
582
 
                        xt_exit_exception_handler(self, &e);
583
 
 
584
 
                        /* Then do the longjmp: */
585
 
                        if (!self->t_in_handler)
586
 
                                longjmp(self->t_jmp_env[self->t_jmp_depth-1].jb_buffer, 1);
587
 
                }
588
 
        }
589
 
 
590
 
        /*
591
 
         * We cannot throw an error, because it will not be caught.
592
 
         * This means there is no try ... catch block above.
593
 
         * In this case, we just return.
594
 
         * The calling functions must handle errors...
595
 
        xt_caught(self);
596
 
        xt_log(XT_CONTEXT, XT_LOG_FATAL, "Uncaught exception\n");
597
 
        xt_exit_thread(self, NULL);
598
 
        */
599
 
}
600
 
 
601
 
xtPublic void xt_throwf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
602
 
{
603
 
        va_list         ap;
604
 
        XTThreadPtr     thread = self ? self : xt_get_self();
605
 
 
606
 
        va_start(ap, fmt);
607
 
        thr_save_error_va(thread ? &thread->t_exception : NULL, thread, self ? TRUE : FALSE, func, file, line, xt_err, sys_err, fmt, ap);
608
 
        va_end(ap);
609
 
}
610
 
 
611
 
xtPublic void xt_throw_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
612
 
{
613
 
        xt_throwf(self, func, file, line, xt_err, sys_err, "%s", msg);
614
 
}
615
 
 
616
 
#define XT_SYS_ERR_SIZE         300
617
 
 
618
 
#ifdef XT_WIN
619
 
static c_char *thr_get_sys_error(int err, char *err_msg)
620
 
#else
621
 
static c_char *thr_get_sys_error(int err, char *XT_UNUSED(err_msg))
622
 
#endif
623
 
{
624
 
#ifdef XT_WIN
625
 
        char *ptr;
626
 
 
627
 
        if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
628
 
                err, 0, err_msg, XT_SYS_ERR_SIZE, NULL)) {
629
 
                return strerror(err);
630
 
        }
631
 
 
632
 
        ptr = &err_msg[strlen(err_msg)];
633
 
        while (ptr-1 > err_msg) {
634
 
                if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.')
635
 
                        break;
636
 
                ptr--;
637
 
        }
638
 
        *ptr = 0;
639
 
return err_msg;
640
 
#else
641
 
        return strerror(err);
642
 
#endif
643
 
}
644
 
 
645
 
static c_char *thr_get_err_string(int xt_err)
646
 
{
647
 
        c_char *str;
648
 
 
649
 
        switch (xt_err) {
650
 
                case XT_ERR_STACK_OVERFLOW:             str = "Stack overflow"; break;
651
 
                case XT_ERR_JUMP_OVERFLOW:              str = "Jump overflow"; break;
652
 
                case XT_ERR_TABLE_EXISTS:               str = "Table `%s` already exists"; break;
653
 
                case XT_ERR_NAME_TOO_LONG:              str = "Name '%s' is too long"; break;
654
 
                case XT_ERR_TABLE_NOT_FOUND:    str = "Table `%s` not found"; break;
655
 
                case XT_ERR_SESSION_NOT_FOUND:  str = "Session %s not found"; break;
656
 
                case XT_ERR_BAD_ADDRESS:                str = "Incorrect address '%s'"; break;
657
 
                case XT_ERR_UNKNOWN_SERVICE:    str = "Unknown service '%s'"; break;
658
 
                case XT_ERR_UNKNOWN_HOST:               str = "Host '%s' not found"; break;
659
 
                case XT_ERR_TOKEN_EXPECTED:             str = "%s expected in place of %s"; break;
660
 
                case XT_ERR_PROPERTY_REQUIRED:  str = "Property '%s' required"; break;
661
 
                case XT_ERR_DEADLOCK:                   str = "Deadlock, transaction aborted"; break;
662
 
                case XT_ERR_CANNOT_CHANGE_DB:   str = "Cannot change database while transaction is in progress"; break;
663
 
                case XT_ERR_ILLEGAL_CHAR:               str = "Illegal character: '%s'"; break;
664
 
                case XT_ERR_UNTERMINATED_STRING:str = "Unterminated string: %s"; break;
665
 
                case XT_ERR_SYNTAX:                             str = "Syntax error near %s"; break;
666
 
                case XT_ERR_ILLEGAL_INSTRUCTION:str = "Illegal instruction"; break;
667
 
                case XT_ERR_OUT_OF_BOUNDS:              str = "Memory reference out of bounds"; break;
668
 
                case XT_ERR_STACK_UNDERFLOW:    str = "Stack underflow"; break;
669
 
                case XT_ERR_TYPE_MISMATCH:              str = "Type mismatch"; break;
670
 
                case XT_ERR_ILLEGAL_TYPE:               str = "Illegal type for operator"; break;
671
 
                case XT_ERR_ID_TOO_LONG:                str = "Identifier too long: %s"; break;
672
 
                case XT_ERR_TYPE_OVERFLOW:              str = "Type overflow: %s"; break;
673
 
                case XT_ERR_TABLE_IN_USE:               str = "Table `%s` in use"; break;
674
 
                case XT_ERR_NO_DATABASE_IN_USE: str = "No database in use"; break;
675
 
                case XT_ERR_CANNOT_RESOLVE_TYPE:str = "Cannot resolve type with ID: %s"; break;
676
 
                case XT_ERR_BAD_INDEX_DESC:             str = "Unsupported index description: %s"; break;
677
 
                case XT_ERR_WRONG_NO_OF_VALUES: str = "Incorrect number of values"; break;
678
 
                case XT_ERR_CANNOT_OUTPUT_VALUE:str = "Cannot output given type"; break;
679
 
                case XT_ERR_COLUMN_NOT_FOUND:   str = "Column `%s.%s` not found"; break;
680
 
                case XT_ERR_NOT_IMPLEMENTED:    str = "Not implemented"; break;
681
 
                case XT_ERR_UNEXPECTED_EOS:             str = "Connection unexpectedly lost"; break;
682
 
                case XT_ERR_BAD_TOKEN:                  str = "Incorrect binary token"; break;
683
 
                case XT_ERR_RES_STACK_OVERFLOW: str = "Internal error: resource stack overflow"; break;
684
 
                case XT_ERR_BAD_INDEX_TYPE:             str = "Unsupported index type: %s"; break;
685
 
                case XT_ERR_INDEX_EXISTS:               str = "Index '%s' already exists"; break;
686
 
                case XT_ERR_INDEX_STRUC_EXISTS: str = "Index '%s' has an identical structure"; break;
687
 
                case XT_ERR_INDEX_NOT_FOUND:    str = "Index '%s' not found"; break;
688
 
                case XT_ERR_INDEX_CORRUPT:              str = "Cannot read index '%s'"; break;
689
 
                case XT_ERR_TYPE_NOT_SUPPORTED: str = "Data type %s not supported"; break;
690
 
                case XT_ERR_BAD_TABLE_VERSION:  str = "Table `%s` version not supported, upgrade required"; break;
691
 
                case XT_ERR_BAD_RECORD_FORMAT:  str = "Record format unknown, either corrupted or upgrade required"; break;
692
 
                case XT_ERR_BAD_EXT_RECORD:             str = "Extended record part does not match reference"; break;
693
 
                case XT_ERR_RECORD_CHANGED:             str = "Record already updated, transaction aborted"; break;
694
 
                case XT_ERR_XLOG_WAS_CORRUPTED: str = "Corrupted transaction log has been truncated"; break;
695
 
                case XT_ERR_DUPLICATE_KEY:              str = "Duplicate unique key"; break;
696
 
                case XT_ERR_NO_DICTIONARY:              str = "Table `%s` has not yet been opened by MySQL"; break;
697
 
                case XT_ERR_TOO_MANY_TABLES:    str = "Limit of %s tables per database exceeded"; break;
698
 
                case XT_ERR_KEY_TOO_LARGE:              str = "Index '%s' exceeds the key size limit of %s"; break;
699
 
                case XT_ERR_MULTIPLE_DATABASES: str = "Multiple database in a single transaction is not permitted"; break;
700
 
                case XT_ERR_NO_TRANSACTION:             str = "Internal error: no transaction running"; break;
701
 
                case XT_ERR_A_EXPECTED_NOT_B:   str = "%s expected in place of %s"; break;
702
 
                case XT_ERR_NO_MATCHING_INDEX:  str = "Matching index required for '%s'"; break;
703
 
                case XT_ERR_TABLE_LOCKED:               str = "Table `%s` locked"; break;
704
 
                case XT_ERR_NO_REFERENCED_ROW:          str = "Constraint: `%s`"; break;  // "Foreign key '%s', referenced row does not exist"
705
 
                case XT_ERR_ROW_IS_REFERENCED:          str = "Constraint: `%s`"; break;  // "Foreign key '%s', has a referencing row"
706
 
                case XT_ERR_BAD_DICTIONARY:                     str = "Internal dictionary does not match MySQL dictionary"; break;
707
 
                case XT_ERR_LOADING_MYSQL_DIC:          str = "Error loading %s.frm file, MySQL error: %s"; break;
708
 
                case XT_ERR_COLUMN_IS_NOT_NULL:         str = "Column `%s` is NOT NULL"; break;
709
 
                case XT_ERR_INCORRECT_NO_OF_COLS:       str = "Incorrect number of columns near %s"; break;
710
 
                case XT_ERR_FK_ON_TEMP_TABLE:           str = "Cannot create foreign key on temporary table"; break;
711
 
                case XT_ERR_REF_TABLE_NOT_FOUND:        str = "Referenced table `%s` not found"; break;
712
 
                case XT_ERR_REF_TYPE_WRONG:                     str = "Incorrect data type on referenced column `%s`"; break;
713
 
                case XT_ERR_DUPLICATE_FKEY:                     str = "Duplicate unique foreign key, contraint: %s"; break;
714
 
                case XT_ERR_INDEX_FILE_TO_LARGE:        str = "Index file has grown too large: %s"; break;
715
 
                case XT_ERR_UPGRADE_TABLE:                      str = "Table `%s` must be upgraded from PBXT version %s"; break;
716
 
                case XT_ERR_INDEX_NEW_VERSION:          str = "Table `%s` index created by a newer version, upgrade required"; break;
717
 
                case XT_ERR_LOCK_TIMEOUT:                       str = "Lock timeout on table `%s`"; break;
718
 
                case XT_ERR_CONVERSION:                         str = "Error converting value for column `%s.%s`"; break;
719
 
                case XT_ERR_NO_ROWS:                            str = "No matching row found in table `%s`"; break;
720
 
                case XT_ERR_DATA_LOG_NOT_FOUND:         str = "Data log not found: '%s'"; break;
721
 
                case XT_ERR_LOG_MAX_EXCEEDED:           str = "Maximum log count, %s, exceeded"; break;
722
 
                case XT_ERR_MAX_ROW_COUNT:                      str = "Maximum row count reached"; break;
723
 
                case XT_ERR_FILE_TOO_LONG:                      str = "File cannot be mapped, too large: '%s'"; break;
724
 
                case XT_ERR_BAD_IND_BLOCK_SIZE:         str = "Table `%s`, incorrect index block size: %s"; break;
725
 
                case XT_ERR_INDEX_CORRUPTED:            str = "Table `%s` index is corrupted, REPAIR TABLE required"; break;
726
 
                case XT_ERR_NO_INDEX_CACHE:                     str = "Not enough index cache memory to handle concurrent updates"; break;
727
 
                case XT_ERR_INDEX_LOG_CORRUPT:          str = "Index log corrupt: '%s'"; break;
728
 
                case XT_ERR_TOO_MANY_THREADS:           str = "Too many threads: %s, increase pbxt_max_threads"; break;
729
 
                case XT_ERR_TOO_MANY_WAITERS:           str = "Too many waiting threads: %s"; break;
730
 
                case XT_ERR_INDEX_OLD_VERSION:          str = "Table `%s` index created by an older version, REPAIR TABLE required"; break;
731
 
                case XT_ERR_PBXT_TABLE_EXISTS:          str = "System table cannot be dropped because PBXT table still exists"; break;
732
 
                case XT_ERR_SERVER_RUNNING:                     str = "A server is possibly already running"; break;
733
 
                case XT_ERR_INDEX_MISSING:                      str = "Index file of table '%s' is missing"; break;
734
 
                case XT_ERR_RECORD_DELETED:                     str = "Record was deleted"; break;
735
 
                case XT_ERR_NEW_TYPE_OF_XLOG:           str = "Transaction log %s, is using a newer format, upgrade required"; break;
736
 
                case XT_ERR_NO_BEFORE_IMAGE:            str = "Internal error: no before image"; break;
737
 
                case XT_ERR_FK_REF_TEMP_TABLE:          str = "Foreign key may not reference temporary table"; break;
738
 
                case XT_ERR_FILE_OP_NOT_SUPP:           str = "File operation not supported on this file: %s"; break;
739
 
                case XT_ERR_INDEX_NOT_RECOVERED:        str = "Index of table '%s' cannot be used because the table was not recovered"; break;
740
 
                case XT_ERR_MYSQL_SHUTDOWN:                     str = "Cannot open table, MySQL has shutdown"; break;
741
 
                case XT_ERR_MYSQL_NO_THREAD:            str = "Cannot create thread, MySQL has shutdown"; break;
742
 
                case XT_ERR_BUFFER_TOO_SMALL:           str = "System backup buffer too small"; break;
743
 
                case XT_ERR_BAD_BACKUP_FORMAT:          str = "Unknown or corrupt backup format, restore aborted"; break;
744
 
                case XT_ERR_PBXT_NOT_INSTALLED:         str = "PBXT plugin is not installed"; break;
745
 
                case XT_ERR_LOG_HEADER_CORRUPT:         str = "Transaction log %s, file header corrupt"; break;
746
 
                default:                                                        str = "Unknown XT error"; break;
747
 
        }
748
 
        return str;
749
 
}
750
 
 
751
 
xtPublic void xt_throw_i2xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2)
752
 
{
753
 
        xt_throwf(self, func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2);
754
 
}
755
 
 
756
 
xtPublic void xt_throw_ixterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item)
757
 
{
758
 
        xt_throw_i2xterr(self, func, file, line, xt_err, item, NULL);
759
 
}
760
 
 
761
 
xtPublic void xt_throw_tabcolerr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2)
762
 
{
763
 
        char buffer[XT_TABLE_NAME_BUF_SIZE];
764
 
 
765
 
        xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
766
 
        xt_throw_i2xterr(self, func, file, line, xt_err, buffer, item2);
767
 
}
768
 
 
769
 
xtPublic void xt_throw_taberr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item)
770
 
{
771
 
        char buffer[XT_TABLE_NAME_BUF_SIZE];
772
 
 
773
 
        xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
774
 
        xt_throw_ixterr(self, func, file, line, xt_err, buffer);
775
 
}
776
 
 
777
 
xtPublic void xt_throw_ulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, u_long value)
778
 
{
779
 
        char buffer[100];
780
 
 
781
 
        sprintf(buffer, "%lu", value);
782
 
        xt_throw_ixterr(self, func, file, line, xt_err, buffer);
783
 
}
784
 
 
785
 
xtPublic void xt_throw_sulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, u_long value)
786
 
{
787
 
        char buffer[100];
788
 
 
789
 
        sprintf(buffer, "%lu", value);
790
 
        xt_throw_i2xterr(self, func, file, line, xt_err, item, buffer);
791
 
}
792
 
 
793
 
xtPublic void xt_throw_xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err)
794
 
{
795
 
        xt_throw_ixterr(self, func, file, line, xt_err, NULL);
796
 
}
797
 
 
798
 
xtPublic void xt_throw_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
799
 
{
800
 
        char err_msg[XT_SYS_ERR_SIZE];
801
 
 
802
 
        xt_throw_error(self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
803
 
}
804
 
 
805
 
xtPublic void xt_throw_ferrno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err, c_char *path)
806
 
{
807
 
        char err_msg[XT_SYS_ERR_SIZE];
808
 
 
809
 
        xt_throwf(self, func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path);
810
 
}
811
 
 
812
 
xtPublic void xt_throw_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str)
813
 
{
814
 
        xt_throw_error(self, func, file, line, XT_ASSERTION_FAILURE, 0, str);
815
 
}
816
 
 
817
 
static void xt_log_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str)
818
 
{
819
 
        xt_log_error(self, func, file, line, XT_LOG_DEFAULT, XT_ASSERTION_FAILURE, 0, str);
820
 
}
821
 
 
822
 
xtPublic void xt_throw_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line, int sig)
823
 
{
824
 
#ifdef XT_WIN
825
 
        char buffer[100];
826
 
 
827
 
        sprintf(buffer, "Signal #%d", sig);
828
 
        xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, buffer);
829
 
#else
830
 
        xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, strsignal(sig));
831
 
#endif
832
 
}
833
 
 
834
 
/*
835
 
 * -----------------------------------------------------------------------
836
 
 * REGISTERING EXCEPTIONS
837
 
 */
838
 
 
839
 
xtPublic void xt_registerf(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
840
 
{
841
 
        va_list         ap;
842
 
        XTThreadPtr     thread = xt_get_self();
843
 
 
844
 
        va_start(ap, fmt);
845
 
        thr_save_error_va(thread ? &thread->t_exception : NULL, thread, FALSE, func, file, line, xt_err, sys_err, fmt, ap);
846
 
        va_end(ap);
847
 
}
848
 
 
849
 
xtPublic void xt_register_i2xterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2)
850
 
{
851
 
        xt_registerf(func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2);
852
 
}
853
 
 
854
 
xtPublic void xt_register_ixterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item)
855
 
{
856
 
        xt_register_i2xterr(func, file, line, xt_err, item, NULL);
857
 
}
858
 
 
859
 
xtPublic void xt_register_tabcolerr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2)
860
 
{
861
 
        char buffer[XT_TABLE_NAME_BUF_SIZE];
862
 
 
863
 
        xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
864
 
        xt_register_i2xterr(func, file, line, xt_err, buffer, item2);
865
 
}
866
 
 
867
 
xtPublic void xt_register_taberr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item)
868
 
{
869
 
        char buffer[XT_TABLE_NAME_BUF_SIZE];
870
 
 
871
 
        xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
872
 
        xt_register_ixterr(func, file, line, xt_err, buffer);
873
 
}
874
 
 
875
 
xtPublic void xt_register_ulxterr(c_char *func, c_char *file, u_int line, int xt_err, u_long value)
876
 
{
877
 
        char buffer[100];
878
 
 
879
 
        sprintf(buffer, "%lu", value);
880
 
        xt_register_ixterr(func, file, line, xt_err, buffer);
881
 
}
882
 
 
883
 
xtPublic xtBool xt_register_ferrno(c_char *func, c_char *file, u_int line, int err, c_char *path)
884
 
{
885
 
        char err_msg[XT_SYS_ERR_SIZE];
886
 
 
887
 
        xt_registerf(func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path);
888
 
        return FAILED;
889
 
}
890
 
 
891
 
xtPublic void xt_register_error(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
892
 
{
893
 
        xt_registerf(func, file, line, xt_err, sys_err, "%s", msg);
894
 
}
895
 
 
896
 
xtPublic xtBool xt_register_errno(c_char *func, c_char *file, u_int line, int err)
897
 
{
898
 
        char err_msg[XT_SYS_ERR_SIZE];
899
 
 
900
 
        xt_register_error(func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
901
 
        return FAILED;
902
 
}
903
 
 
904
 
xtPublic void xt_register_xterr(c_char *func, c_char *file, u_int line, int xt_err)
905
 
{
906
 
        xt_register_error(func, file, line, xt_err, 0, thr_get_err_string(xt_err));
907
 
}
908
 
 
909
 
/*
910
 
 * -----------------------------------------------------------------------
911
 
 * CREATING EXCEPTIONS
912
 
 */
913
 
 
914
 
xtPublic void xt_exceptionf(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
915
 
{
916
 
        va_list ap;
917
 
 
918
 
        va_start(ap, fmt);
919
 
        thr_save_error_va(e, self, FALSE, func, file, line, xt_err, sys_err, fmt, ap);
920
 
        va_end(ap);
921
 
}
922
 
 
923
 
xtPublic void xt_exception_error(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
924
 
{
925
 
        xt_exceptionf(e, self, func, file, line, xt_err, sys_err, "%s", msg);
926
 
}
927
 
 
928
 
xtPublic xtBool xt_exception_errno(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
929
 
{
930
 
        char err_msg[XT_SYS_ERR_SIZE];
931
 
 
932
 
        xt_exception_error(e, self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
933
 
        return FAILED;
934
 
}
935
 
 
936
 
xtPublic void xt_exception_xterr(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err)
937
 
{
938
 
        xt_exception_error(e, self, func, file, line, xt_err, 0, thr_get_err_string(xt_err));
939
 
}
940
 
 
941
 
/*
942
 
 * -----------------------------------------------------------------------
943
 
 * LOG ERRORS
944
 
 */
945
 
 
946
 
xtPublic void xt_log_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
947
 
{
948
 
        XTExceptionRec e;
949
 
 
950
 
        xt_exception_errno(&e, self, func, file, line, err);
951
 
        xt_log_exception(self, &e, XT_LOG_DEFAULT);
952
 
}
953
 
 
954
 
/*
955
 
 * -----------------------------------------------------------------------
956
 
 * Assertions and failures (one breakpoints for all failures)
957
 
 */
958
 
//#define CRASH_ON_ASSERT
959
 
 
960
 
xtPublic xtBool xt_assert(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line)
961
 
{
962
 
        (void) self;
963
 
#ifdef DEBUG
964
 
        //xt_set_fflush(TRUE);
965
 
        //xt_dump_trace();
966
 
        break_in_assertion(expr, func, file, line);
967
 
#ifdef CRASH_ON_ASSERT
968
 
        abort();
969
 
#endif
970
 
#ifdef XT_WIN
971
 
        FatalAppExit(0, "Assertion Failed!");
972
 
#endif
973
 
#else
974
 
        xt_throw_assertion(self, func, file, line, expr);
975
 
#endif
976
 
        return FALSE;
977
 
}
978
 
 
979
 
xtPublic xtBool xt_assume(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line)
980
 
{
981
 
        xt_log_assertion(self, func, file, line, expr);
982
 
        return FALSE;
983
 
}
984
 
 
985
 
/*
986
 
 * -----------------------------------------------------------------------
987
 
 * Create and destroy threads
988
 
 */
989
 
 
990
 
typedef struct ThreadData {
991
 
        xtBool                  td_started;
992
 
        XTThreadPtr             td_thr;
993
 
        void                    *(*td_start_routine)(XTThreadPtr self);
994
 
} ThreadDataRec, *ThreadDataPtr;
995
 
 
996
 
#ifdef XT_WIN
997
 
pthread_key(void *, thr_key);
998
 
#else
999
 
static pthread_key_t thr_key;
1000
 
#endif
1001
 
 
1002
 
#ifdef HANDLE_SIGNALS
1003
 
static void thr_ignore_signal(int sig)
1004
 
{
1005
 
#pragma unused(sig)
1006
 
}
1007
 
 
1008
 
static void thr_throw_signal(int sig)
1009
 
{
1010
 
        XTThreadPtr     self;
1011
 
 
1012
 
        self = xt_get_self();
1013
 
 
1014
 
        if (self->t_main) {
1015
 
                /* The main thread will pass on a signal to all threads: */
1016
 
                xt_signal_all_threads(self, sig);
1017
 
                if (sig != SIGTERM) {
1018
 
                        if (self->t_disable_interrupts) {
1019
 
                                self->t_delayed_signal = sig;
1020
 
                                self->t_disable_interrupts = FALSE;     /* Prevent infinite loop */
1021
 
                        }
1022
 
                        else {
1023
 
                                self->t_delayed_signal = 0;
1024
 
                                xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig);
1025
 
                        }
1026
 
                }
1027
 
        }
1028
 
        else {
1029
 
                if (self->t_disable_interrupts) {
1030
 
                        self->t_delayed_signal = sig;
1031
 
                        self->t_disable_interrupts = FALSE;     /* Prevent infinite loop */
1032
 
                }
1033
 
                else {
1034
 
                        self->t_delayed_signal = 0;
1035
 
                        xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig);
1036
 
                }
1037
 
        }
1038
 
}
1039
 
 
1040
 
static xtBool thr_setup_signals(void)
1041
 
{
1042
 
        struct sigaction action;
1043
 
 
1044
 
    sigemptyset(&action.sa_mask);
1045
 
    action.sa_flags = 0;
1046
 
    action.sa_handler = thr_ignore_signal;
1047
 
 
1048
 
        if (sigaction(SIGPIPE, &action, NULL) == -1)
1049
 
                goto error_occurred;
1050
 
        if (sigaction(SIGHUP, &action, NULL) == -1)
1051
 
                goto error_occurred;
1052
 
 
1053
 
    action.sa_handler = thr_throw_signal;
1054
 
 
1055
 
        if (sigaction(SIGQUIT, &action, NULL) == -1)
1056
 
                goto error_occurred;
1057
 
        if (sigaction(SIGTERM, &action, NULL) == -1)
1058
 
                goto error_occurred;
1059
 
#ifndef DEBUG
1060
 
        if (sigaction(SIGILL, &action, NULL) == -1)
1061
 
                goto error_occurred;
1062
 
        if (sigaction(SIGBUS, &action, NULL) == -1)
1063
 
                goto error_occurred;
1064
 
        if (sigaction(SIGSEGV, &action, NULL) == -1)
1065
 
                goto error_occurred;
1066
 
#endif
1067
 
        return TRUE;
1068
 
 
1069
 
        error_occurred:
1070
 
        xt_log_errno(XT_NS_CONTEXT, errno);
1071
 
        return FALSE;
1072
 
}
1073
 
#endif
1074
 
 
1075
 
typedef void *(*ThreadMainFunc)(XTThreadPtr self);
1076
 
 
1077
 
extern "C" void *xt_thread_main(void *data)
1078
 
{
1079
 
        ThreadDataPtr   td = (ThreadDataPtr) data;
1080
 
        XTThreadPtr             self = td->td_thr;
1081
 
        ThreadMainFunc          start_routine;
1082
 
        void                    *return_data;
1083
 
 
1084
 
        enter_();
1085
 
        self->t_pthread = pthread_self();
1086
 
        start_routine = td->td_start_routine;
1087
 
        return_data = NULL;
1088
 
 
1089
 
#ifdef HANDLE_SIGNALS
1090
 
        if (!thr_setup_signals())
1091
 
                return NULL;
1092
 
#endif
1093
 
 
1094
 
        try_(a) {
1095
 
                if (!xt_set_key((pthread_key_t)thr_key, self, &self->t_exception))
1096
 
                        throw_();
1097
 
                td->td_started = TRUE;
1098
 
                return_data = (*start_routine)(self);
1099
 
        }
1100
 
        catch_(a) {
1101
 
                xt_log_and_clear_exception(self);
1102
 
        }
1103
 
        cont_(a);
1104
 
 
1105
 
        outer_();
1106
 
        xt_free_thread(self);
1107
 
        
1108
 
        /* {MYSQL-THREAD-KILL}
1109
 
         * Clean up any remaining MySQL thread!
1110
 
         */
1111
 
        myxt_delete_remaining_thread();
1112
 
        return return_data;
1113
 
}
1114
 
 
1115
 
static void thr_free_data(XTThreadPtr self)
1116
 
{
1117
 
        if (self->t_free_data) {
1118
 
                (*self->t_free_data)(self, self->t_data);
1119
 
                self->t_data = NULL;
1120
 
        }
1121
 
}
1122
 
 
1123
 
xtPublic void xt_set_thread_data(XTThreadPtr self, void *data, XTThreadFreeFunc free_func)
1124
 
{
1125
 
        thr_free_data(self);
1126
 
        self->t_free_data = free_func;
1127
 
        self->t_data = data;
1128
 
}
1129
 
 
1130
 
static void thr_exit(XTThreadPtr self)
1131
 
{
1132
 
        /* Free the thread temporary data. */
1133
 
        thr_free_resources(self, (XTResourcePtr) self->x.t_res_stack);
1134
 
        xt_db_exit_thread(self);
1135
 
        thr_free_data(self);                                    /* Free custom user data. */
1136
 
 
1137
 
        if (self->t_id > 0) {
1138
 
                ASSERT(self->t_id < xt_thr_current_max_threads);
1139
 
                xt_lock_mutex(self, &thr_array_lock);
1140
 
                pushr_(xt_unlock_mutex, &thr_array_lock);
1141
 
                thr_accumulate_statistics(self);
1142
 
                // No read resize lock required if I have the array lock
1143
 
                xt_thr_array[self->t_id].td_thread = NULL;
1144
 
                xt_thr_current_thread_count--;
1145
 
                if (self->t_id+1 == xt_thr_current_max_threads) {
1146
 
                        /* We can reduce the current maximum,
1147
 
                         * this makes operations that scan the array faster!
1148
 
                         */
1149
 
                        u_int i;
1150
 
 
1151
 
                        i = self->t_id;
1152
 
                        for(;;) {
1153
 
                                if (xt_thr_array[i].td_thread)
1154
 
                                        break;
1155
 
                                if (!i)
1156
 
                                        break;
1157
 
                                i--;
1158
 
                        }
1159
 
                        xt_thr_current_max_threads = i+1;
1160
 
                }
1161
 
                freer_(); // xt_unlock_mutex(&thr_array_lock)
1162
 
        }
1163
 
 
1164
 
        xt_free_cond(&self->t_cond);
1165
 
        xt_free_mutex(&self->t_lock);
1166
 
 
1167
 
        self->st_tasks_todo.pl_exit();
1168
 
        self->st_tasks_done.pl_exit();
1169
 
 
1170
 
        self->st_thread_list_count = 0;
1171
 
        self->st_thread_list_size = 0;
1172
 
        if (self->st_thread_list) {
1173
 
                xt_free_ns(self->st_thread_list);
1174
 
                self->st_thread_list = NULL;
1175
 
        }
1176
 
}
1177
 
 
1178
 
#ifdef DEBUG
1179
 
#define XT_THREAD_ARRAY_INC_SIZE                5
1180
 
#else
1181
 
#define XT_THREAD_ARRAY_INC_SIZE                100
1182
 
#endif
1183
 
 
1184
 
static xtBool thr_init_ns(XTThreadPtr new_thread)
1185
 
{
1186
 
        new_thread->t_res_top = (XTResourcePtr) new_thread->x.t_res_stack;
1187
 
 
1188
 
        new_thread->st_thread_list_count = 0;
1189
 
        new_thread->st_thread_list_size = 0;
1190
 
        new_thread->st_thread_list = NULL;
1191
 
 
1192
 
        if (!new_thread->st_tasks_todo.pl_init_ns())
1193
 
                goto failed;
1194
 
 
1195
 
        if (!new_thread->st_tasks_done.pl_init_ns())
1196
 
                goto failed;
1197
 
 
1198
 
        xt_init_cond(NULL, &new_thread->t_cond);
1199
 
        xt_init_mutex_with_autoname(NULL, &new_thread->t_lock);
1200
 
 
1201
 
        xt_lock_mutex_ns(&thr_array_lock);
1202
 
 
1203
 
        ASSERT_NS(xt_thr_current_thread_count <= xt_thr_current_max_threads);
1204
 
        ASSERT_NS(xt_thr_current_max_threads <= xt_thr_maximum_threads);
1205
 
        if (xt_thr_current_thread_count == xt_thr_maximum_threads) {
1206
 
                XTThreadDataRec *tmp;
1207
 
 
1208
 
                /* We can use a fixed thread ID because only one thread can do
1209
 
                 * this at any given time.
1210
 
                 *
1211
 
                 * We use XT_SYS_THREAD_ID to avoid the problem that we this function
1212
 
                 * allocates thread IDs, but needs a thread ID to aquire the
1213
 
                 * lock here!
1214
 
                 */
1215
 
                THR_ARRAY_WRITE_LOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1216
 
                if (!(tmp = (XTThreadDataRec *) realloc(xt_thr_array, (xt_thr_maximum_threads + XT_THREAD_ARRAY_INC_SIZE) * sizeof(XTThreadDataRec)))) {
1217
 
                        THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1218
 
                        goto failed_2;
1219
 
                }
1220
 
 
1221
 
                xt_thr_array = tmp;
1222
 
                xt_thr_maximum_threads += XT_THREAD_ARRAY_INC_SIZE;
1223
 
 
1224
 
                for (u_int i=xt_thr_maximum_threads - XT_THREAD_ARRAY_INC_SIZE; i<xt_thr_maximum_threads; i++)
1225
 
                        xt_thr_array[i].td_thread = NULL;
1226
 
        
1227
 
                for (u_int i=xt_thr_maximum_threads - XT_THREAD_ARRAY_INC_SIZE; i<xt_thr_maximum_threads; i++) {
1228
 
                        if (!(xt_thr_array[i].td_waiting = (XTWaitThreadPtr) xt_calloc_ns(sizeof(XTWaitThreadRec)))) {
1229
 
                                xt_thr_maximum_threads = i;
1230
 
                                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1231
 
                                goto failed_2;
1232
 
                        }
1233
 
                        xt_init_mutex_with_autoname(NULL, &xt_thr_array[i].td_waiting->wt_lock);
1234
 
                        xt_init_cond(NULL, &xt_thr_array[i].td_waiting->wt_cond);
1235
 
                        xt_spinlock_init_with_autoname(NULL, &xt_thr_array[i].td_waiting->wt_wait_list_lock);
1236
 
                }
1237
 
 
1238
 
                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1239
 
        }
1240
 
 
1241
 
        if (xt_thr_current_thread_count == xt_thr_current_max_threads) {
1242
 
                new_thread->t_id = xt_thr_current_thread_count;
1243
 
                xt_thr_array[new_thread->t_id].td_thread = new_thread;
1244
 
                xt_thr_current_max_threads++;
1245
 
        }
1246
 
        else {
1247
 
                /* There must be a free slot: */
1248
 
                for (u_int i=0; i<xt_thr_current_max_threads; i++) {
1249
 
                        if (!xt_thr_array[i].td_thread) {
1250
 
                                new_thread->t_id = i;
1251
 
                                xt_thr_array[i].td_thread = new_thread;
1252
 
                                break;
1253
 
                        }
1254
 
                }
1255
 
        }
1256
 
        xt_thr_current_thread_count++;
1257
 
 
1258
 
        xt_unlock_mutex_ns(&thr_array_lock);
1259
 
 
1260
 
        xt_db_init_thread_ns(new_thread);
1261
 
        return OK;
1262
 
 
1263
 
        failed_2:
1264
 
        xt_unlock_mutex_ns(&thr_array_lock);
1265
 
 
1266
 
        failed:
1267
 
        thr_exit(new_thread);
1268
 
        return FAILED;
1269
 
}
1270
 
 
1271
 
/*
1272
 
 * The caller of this function automatically becomes the main thread.
1273
 
 */
1274
 
xtPublic XTThreadPtr xt_init_threading()
1275
 
{
1276
 
        volatile XTThreadPtr    self = NULL;
1277
 
        XTExceptionRec                  e;
1278
 
        int                                             err;
1279
 
 
1280
 
#ifdef HANDLE_SIGNALS
1281
 
        if (!thr_setup_signals())
1282
 
                return NULL;
1283
 
#endif
1284
 
 
1285
 
        xt_p_init_threading();
1286
 
 
1287
 
        err = pthread_key_create(&thr_key, NULL);
1288
 
        if (err) {
1289
 
                xt_log_errno(XT_NS_CONTEXT, err);
1290
 
                return NULL;
1291
 
        }
1292
 
 
1293
 
        if ((err = xt_p_mutex_init_with_autoname(&thr_array_lock, NULL))) {
1294
 
                xt_log_errno(XT_NS_CONTEXT, err);
1295
 
                goto failed;
1296
 
        }
1297
 
        
1298
 
        xt_thr_maximum_threads = 2;
1299
 
        if (!(xt_thr_array = (XTThreadDataRec *) malloc(xt_thr_maximum_threads * sizeof(XTThreadDataRec)))) {
1300
 
                xt_log_errno(XT_NS_CONTEXT, XT_ENOMEM);
1301
 
                goto failed;
1302
 
        }
1303
 
 
1304
 
        xt_thr_array[XT_NO_THREAD_ID].td_thread = (XTThreadPtr) 1; // Dummy, not used
1305
 
        xt_thr_array[XT_NO_THREAD_ID].td_waiting = NULL;
1306
 
        xt_thr_array[XT_SYS_THREAD_ID].td_thread = (XTThreadPtr) 1; // System ID, used for resizing the thread array
1307
 
        xt_thr_array[XT_SYS_THREAD_ID].td_waiting = NULL;
1308
 
        xt_thr_current_thread_count = XT_MIN_THREAD_ID;
1309
 
        xt_thr_current_max_threads = XT_MIN_THREAD_ID;
1310
 
 
1311
 
        THR_ARRAY_INIT_LOCK(NULL, &xt_thr_array_resize_lock);
1312
 
 
1313
 
        /* Create the main thread: */
1314
 
        self = xt_create_thread("MainThread", TRUE, FALSE, &e);
1315
 
        if (!self) {
1316
 
                xt_log_exception(NULL, &e, XT_LOG_DEFAULT);
1317
 
                goto failed;
1318
 
        }
1319
 
 
1320
 
        try_(a) {
1321
 
                XTThreadPtr     thread = self;
1322
 
                thr_list = xt_new_linkedlist(thread, NULL, NULL, TRUE);
1323
 
                
1324
 
        }
1325
 
        catch_(a) {
1326
 
                XTThreadPtr     thread = self;
1327
 
                xt_log_and_clear_exception(thread);
1328
 
                xt_exit_threading(thread);
1329
 
        }
1330
 
        cont_(a);
1331
 
 
1332
 
        return self;
1333
 
        
1334
 
        failed:
1335
 
        xt_exit_threading(NULL);
1336
 
        return NULL;
1337
 
}
1338
 
 
1339
 
xtPublic void xt_exit_threading(XTThreadPtr self)
1340
 
{
1341
 
        if (thr_list) {
1342
 
                xt_free_linkedlist(self, thr_list);
1343
 
                thr_list = NULL;
1344
 
        }
1345
 
 
1346
 
        /* This should be the main thread! */
1347
 
        if (self) {
1348
 
                ASSERT(self->t_main);
1349
 
                xt_free_thread(self);
1350
 
        }
1351
 
 
1352
 
        if (xt_thr_array) {
1353
 
                for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_maximum_threads; i++) {
1354
 
                        xt_free_mutex(&xt_thr_array[i].td_waiting->wt_lock);
1355
 
                        xt_free_cond(&xt_thr_array[i].td_waiting->wt_cond);
1356
 
                        xt_spinlock_free(self, &xt_thr_array[i].td_waiting->wt_wait_list_lock);
1357
 
                        if (xt_thr_array[i].td_waiting->wt_wait_list)
1358
 
                                xt_free_ns(xt_thr_array[i].td_waiting->wt_wait_list);
1359
 
                        xt_free_ns(xt_thr_array[i].td_waiting);
1360
 
                }
1361
 
 
1362
 
                free(xt_thr_array);
1363
 
                xt_thr_array = NULL;
1364
 
                THR_ARRAY_FREE_LOCK(self, &xt_thr_array_resize_lock);
1365
 
                xt_free_mutex(&thr_array_lock);
1366
 
        }
1367
 
 
1368
 
        xt_thr_current_thread_count = 0;
1369
 
        xt_thr_current_max_threads = 0;
1370
 
 
1371
 
        /* I no longer delete 'thr_key' because
1372
 
         * functions that call xt_get_self() after this
1373
 
         * point will get junk back if we delete
1374
 
         * thr_key. In particular the XT_THREAD_LOCK_INFO
1375
 
         * code fails
1376
 
        if (thr_key) {
1377
 
                pthread_key_delete(thr_key);
1378
 
                thr_key = (pthread_key_t) 0;
1379
 
        }
1380
 
        */
1381
 
}
1382
 
 
1383
 
xtPublic void xt_wait_for_all_threads(XTThreadPtr self)
1384
 
{
1385
 
        if (thr_list)
1386
 
                xt_ll_wait_till_empty(self, thr_list);
1387
 
}
1388
 
 
1389
 
/*
1390
 
 * Call this function in a busy wait loop!
1391
 
 * Use if for wait loops that are not
1392
 
 * time critical.
1393
 
 */
1394
 
xtPublic void xt_busy_wait(void)
1395
 
{
1396
 
#ifdef XT_WIN
1397
 
        Sleep(1);
1398
 
#else
1399
 
        usleep(10);
1400
 
#endif
1401
 
}
1402
 
 
1403
 
xtPublic void xt_critical_wait(void)
1404
 
{
1405
 
        /* NOTE: On Mac xt_busy_wait() works better than xt_yield()
1406
 
         */
1407
 
#if defined(XT_MAC) || defined(XT_WIN)
1408
 
        xt_busy_wait();
1409
 
#else
1410
 
        xt_yield();
1411
 
#endif
1412
 
}
1413
 
 
1414
 
 
1415
 
/*
1416
 
 * Use this for loops that time critical.
1417
 
 * Time critical means we need to get going
1418
 
 * as soon as possible!
1419
 
 */
1420
 
xtPublic void xt_yield(void)
1421
 
{
1422
 
#ifdef XT_WIN
1423
 
        Sleep(0);
1424
 
#elif defined(XT_MAC) || defined(XT_SOLARIS)
1425
 
        usleep(0);
1426
 
#elif defined(XT_NETBSD)
1427
 
        sched_yield();
1428
 
#else
1429
 
        pthread_yield();
1430
 
#endif
1431
 
}
1432
 
 
1433
 
xtPublic void xt_sleep_milli_second(u_int t)
1434
 
{
1435
 
#ifdef XT_WIN
1436
 
        Sleep(t);
1437
 
#else
1438
 
        usleep(t * 1000);
1439
 
#endif
1440
 
}
1441
 
 
1442
 
xtPublic void xt_signal_all_threads(XTThreadPtr self, int sig)
1443
 
{
1444
 
        XTLinkedItemPtr li;
1445
 
        XTThreadPtr             sig_thr;
1446
 
 
1447
 
        xt_ll_lock(self, thr_list);
1448
 
        try_(a) {
1449
 
                li = thr_list->ll_items;
1450
 
                while (li) {
1451
 
                        sig_thr = (XTThreadPtr) li;
1452
 
                        if (sig_thr != self)
1453
 
                                pthread_kill(sig_thr->t_pthread, sig);
1454
 
                        li = li->li_next;
1455
 
                }
1456
 
        }
1457
 
        catch_(a) {
1458
 
                xt_ll_unlock(self, thr_list);
1459
 
                throw_();
1460
 
        }
1461
 
        cont_(a);
1462
 
        xt_ll_unlock(self, thr_list);
1463
 
}
1464
 
 
1465
 
/*
1466
 
 * Apply the given function to all threads except self!
1467
 
 */
1468
 
xtPublic void xt_do_to_all_threads(XTThreadPtr self, void (*do_func_ptr)(XTThreadPtr self, XTThreadPtr to_thr, void *thunk), void *thunk)
1469
 
{
1470
 
        XTLinkedItemPtr li;
1471
 
        XTThreadPtr             to_thr;
1472
 
 
1473
 
        xt_ll_lock(self, thr_list);
1474
 
        pushr_(xt_ll_unlock, thr_list);
1475
 
 
1476
 
        li = thr_list->ll_items;
1477
 
        while (li) {
1478
 
                to_thr = (XTThreadPtr) li;
1479
 
                if (to_thr != self)
1480
 
                        (*do_func_ptr)(self, to_thr, thunk);
1481
 
                li = li->li_next;
1482
 
        }
1483
 
 
1484
 
        freer_(); // xt_ll_unlock(thr_list)
1485
 
}
1486
 
 
1487
 
xtPublic XTThreadPtr xt_get_self(void)
1488
 
{
1489
 
        XTThreadPtr self;
1490
 
 
1491
 
        /* First check if the handler has the data: */
1492
 
        if ((self = myxt_get_self()))
1493
 
                return self;
1494
 
        /* Then it must be a background process, and the 
1495
 
         * thread info is stored in the local key: */
1496
 
        return (XTThreadPtr) xt_get_key((pthread_key_t)thr_key);
1497
 
}
1498
 
 
1499
 
xtPublic void xt_set_self(XTThreadPtr self)
1500
 
{
1501
 
        xt_set_key((pthread_key_t)thr_key, self, NULL);
1502
 
}
1503
 
 
1504
 
xtPublic void xt_clear_exception(XTThreadPtr thread)
1505
 
{
1506
 
        thread->t_exception.e_xt_err = 0;
1507
 
        thread->t_exception.e_sys_err = 0;
1508
 
        *thread->t_exception.e_err_msg = 0;
1509
 
        *thread->t_exception.e_func_name = 0;
1510
 
        *thread->t_exception.e_source_file = 0;
1511
 
        thread->t_exception.e_source_line = 0;
1512
 
        *thread->t_exception.e_catch_trace = 0;
1513
 
}
1514
 
 
1515
 
/*
1516
 
 * Create a thread without requiring thread to do it (as in xt_create_daemon()).
1517
 
 *
1518
 
 * This function returns NULL on error.
1519
 
 */
1520
 
xtPublic XTThreadPtr xt_create_thread(c_char *name, xtBool main_thread, xtBool user_thread, XTExceptionPtr e)
1521
 
{
1522
 
        volatile XTThreadPtr self;
1523
 
        
1524
 
        self = (XTThreadPtr) xt_calloc_ns(sizeof(XTThreadRec));
1525
 
        if (!self) {
1526
 
                xt_exception_errno(e, XT_CONTEXT, ENOMEM);
1527
 
                return NULL;
1528
 
        }
1529
 
 
1530
 
        if (!xt_set_key((pthread_key_t)thr_key, self, e)) {
1531
 
                xt_free_ns(self);
1532
 
                return NULL;
1533
 
        }
1534
 
 
1535
 
        xt_strcpy(XT_THR_NAME_SIZE, self->t_name, name);
1536
 
        self->t_main = main_thread;
1537
 
        self->t_daemon = FALSE;
1538
 
 
1539
 
        if (!thr_init_ns(self)) {
1540
 
                *e = self->t_exception;
1541
 
                xt_set_key((pthread_key_t)thr_key, NULL, NULL);
1542
 
                xt_free_ns(self);
1543
 
                self = NULL;
1544
 
        }
1545
 
 
1546
 
        if (self && user_thread) {
1547
 
                /* Add non-temporary threads to the thread list. */
1548
 
                try_(b) {
1549
 
                        xt_ll_add(self, thr_list, &self->t_links, TRUE);
1550
 
                }
1551
 
                catch_(b) {
1552
 
                        *e = self->t_exception;
1553
 
                        xt_free_thread(self);
1554
 
                        self = NULL;
1555
 
                }
1556
 
                cont_(b);
1557
 
        }
1558
 
 
1559
 
        return self;
1560
 
}
1561
 
 
1562
 
/*
1563
 
 * Create a daemon thread.
1564
 
 */
1565
 
xtPublic XTThreadPtr xt_create_daemon_ns(c_char *name)
1566
 
{
1567
 
        XTThreadPtr new_thread;
1568
 
 
1569
 
        /* NOTE: thr_key will be set when this thread start running. */
1570
 
        if (!(new_thread = (XTThreadPtr) xt_calloc_ns(sizeof(XTThreadRec))))
1571
 
                return NULL;
1572
 
 
1573
 
        xt_strcpy(XT_THR_NAME_SIZE, new_thread->t_name, name);
1574
 
        new_thread->t_main = FALSE;
1575
 
        new_thread->t_daemon = TRUE;
1576
 
 
1577
 
        if (!thr_init_ns(new_thread)) {
1578
 
                xt_free_ns(new_thread);
1579
 
                return NULL;
1580
 
        }
1581
 
 
1582
 
        return new_thread;
1583
 
}
1584
 
 
1585
 
xtPublic XTThreadPtr xt_create_daemon(XTThreadPtr self, c_char *name)
1586
 
{
1587
 
        XTThreadPtr new_thread;
1588
 
 
1589
 
        if (!(new_thread = xt_create_daemon_ns(name)))
1590
 
                xt_throw(self);
1591
 
        return new_thread;
1592
 
}
1593
 
 
1594
 
void xt_free_thread(XTThreadPtr self)
1595
 
{
1596
 
        thr_exit(self);
1597
 
        if (!self->t_daemon && thr_list)
1598
 
                xt_ll_remove(self, thr_list, &self->t_links, TRUE);
1599
 
        /* Note, if I move this before thr_exit() then self = xt_get_self(); will fail in 
1600
 
         * xt_close_file_ns() which is called by xt_unuse_database()!
1601
 
         */
1602
 
 
1603
 
         /*
1604
 
          * Do not clear the pthread's key value unless it is the same as the thread just released.
1605
 
          * This can happen during shutdown when the engine is deregistered with the PBMS engine.
1606
 
          *
1607
 
          * What happens is that during deregistration the PBMS engine calls close to close all
1608
 
          * PBXT resources on all MySQL THDs created by PBMS for it's own pthreads. So the 'self' 
1609
 
          * being freed is not the same 'self' associated with the PBXT 'thr_key'.
1610
 
          */
1611
 
        if (thr_key && (self == ((XTThreadPtr) xt_get_key((pthread_key_t)thr_key)))) {
1612
 
                xt_set_key((pthread_key_t)thr_key, NULL, NULL);
1613
 
        }
1614
 
        xt_free_ns(self);
1615
 
}
1616
 
 
1617
 
xtPublic xtBool xt_run_thread_ns(XTThreadPtr child, void *(*start_routine)(XTThreadPtr))
1618
 
{
1619
 
        ThreadDataRec   data;
1620
 
        int                             err;
1621
 
        pthread_t               child_thread;
1622
 
        
1623
 
        // 'data' can be on the stack because we are waiting for the thread to start
1624
 
        // before exiting the function.
1625
 
        data.td_started = FALSE;
1626
 
        data.td_thr = child;
1627
 
        data.td_start_routine = start_routine;
1628
 
#ifdef XT_WIN
1629
 
        {
1630
 
                pthread_attr_t  attr = { 0, 0, 0 };
1631
 
 
1632
 
                attr.priority = THREAD_PRIORITY_NORMAL;
1633
 
                err = pthread_create(&child_thread, &attr, xt_thread_main, &data);
1634
 
        }
1635
 
#else
1636
 
        err = pthread_create(&child_thread, NULL, xt_thread_main, &data);
1637
 
#endif
1638
 
        if (err) {
1639
 
                xt_free_thread(child);
1640
 
                return xt_register_errno(XT_REG_CONTEXT, err);
1641
 
        }
1642
 
 
1643
 
        while (!data.td_started) {
1644
 
                /* Check that the self is still alive: */
1645
 
                if (pthread_kill(child_thread, 0))
1646
 
                        break;
1647
 
                xt_busy_wait();
1648
 
        }
1649
 
 
1650
 
        return OK;
1651
 
}
1652
 
 
1653
 
xtPublic void xt_run_thread(XTThreadPtr self, XTThreadPtr child, void *(*start_routine)(XTThreadPtr))
1654
 
{
1655
 
        if (!xt_run_thread_ns(child, start_routine))
1656
 
                xt_throw(self);
1657
 
}
1658
 
 
1659
 
xtPublic void xt_exit_thread(XTThreadPtr self, void *result)
1660
 
{
1661
 
        xt_free_thread(self);
1662
 
        pthread_exit(result);
1663
 
}
1664
 
 
1665
 
xtPublic void *xt_wait_for_thread_to_exit(xtThreadID tid, xtBool ignore_error)
1666
 
{
1667
 
        int                     err;
1668
 
        void            *value_ptr = NULL;
1669
 
        xtBool          ok = FALSE;
1670
 
        XTThreadPtr thread;
1671
 
        pthread_t       t1 = 0;
1672
 
 
1673
 
        xt_lock_mutex_ns(&thr_array_lock);
1674
 
        if (tid < xt_thr_maximum_threads) {
1675
 
                // No resize lock required if I have the array lock.
1676
 
                if ((thread = xt_thr_array[tid].td_thread)) {
1677
 
                        t1 = thread->t_pthread;
1678
 
                        ok = TRUE;
1679
 
                }
1680
 
        }
1681
 
        xt_unlock_mutex_ns(&thr_array_lock);
1682
 
        if (ok) {
1683
 
                err = xt_p_join(t1, &value_ptr);
1684
 
                if (err && !ignore_error)
1685
 
                        xt_log_errno(XT_NS_CONTEXT, err);
1686
 
        }
1687
 
        return value_ptr;
1688
 
}
1689
 
 
1690
 
/*
1691
 
 * Kill the given thead, and wait for it to terminate.
1692
 
 * This function just returns if the self is already dead.
1693
 
 */
1694
 
xtPublic void xt_kill_thread(pthread_t t1)
1695
 
{
1696
 
        int             err;
1697
 
        void    *value_ptr = NULL;
1698
 
 
1699
 
        err = pthread_kill(t1, SIGTERM);
1700
 
        if (err)
1701
 
                return;
1702
 
        err = xt_p_join(t1, &value_ptr);
1703
 
        if (err)
1704
 
                xt_log_errno(XT_NS_CONTEXT, err);
1705
 
}
1706
 
 
1707
 
/*
1708
 
 * -----------------------------------------------------------------------
1709
 
 * Read/write locking
1710
 
 */
1711
 
 
1712
 
#ifdef XT_THREAD_LOCK_INFO
1713
 
xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock, const char *name)
1714
 
#else
1715
 
xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1716
 
#endif
1717
 
{
1718
 
        int err;
1719
 
 
1720
 
#ifdef XT_THREAD_LOCK_INFO
1721
 
        err = xt_p_rwlock_init_with_name(rwlock, NULL, name);
1722
 
#else
1723
 
        err = xt_p_rwlock_init(rwlock, NULL);
1724
 
#endif
1725
 
 
1726
 
        if (err) {
1727
 
                xt_throw_errno(XT_CONTEXT, err);
1728
 
                return FAILED;
1729
 
        }
1730
 
        return OK;
1731
 
}
1732
 
 
1733
 
xtPublic void xt_free_rwlock(xt_rwlock_type *rwlock)
1734
 
{
1735
 
        int err;
1736
 
 
1737
 
        for (;;) {
1738
 
                err = xt_p_rwlock_destroy(rwlock);
1739
 
                if (err != XT_EBUSY)
1740
 
                        break;
1741
 
                xt_busy_wait();
1742
 
        }
1743
 
        /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1744
 
         * This generates a lot of log entries. But I have no desire to only call
1745
 
         * free for those articles that I have init'ed!
1746
 
        if (err)
1747
 
                xt_log_errno(XT_NS_CONTEXT, err);
1748
 
        */
1749
 
}
1750
 
 
1751
 
xtPublic xt_rwlock_type *xt_slock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1752
 
{
1753
 
        int err;
1754
 
 
1755
 
        for (;;) {
1756
 
                err = xt_slock_rwlock_ns(rwlock);
1757
 
                if (err != XT_EAGAIN)
1758
 
                        break;
1759
 
                xt_busy_wait();
1760
 
        }
1761
 
        if (err) {
1762
 
                xt_throw_errno(XT_CONTEXT, err);
1763
 
                return NULL;
1764
 
        }
1765
 
        return rwlock;
1766
 
}
1767
 
 
1768
 
xtPublic xt_rwlock_type *xt_xlock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1769
 
{
1770
 
        int err;
1771
 
 
1772
 
        for (;;) {
1773
 
                err = xt_xlock_rwlock_ns(rwlock);
1774
 
                if (err != XT_EAGAIN)
1775
 
                        break;
1776
 
                xt_busy_wait();
1777
 
        }
1778
 
 
1779
 
        if (err) {
1780
 
                xt_throw_errno(XT_CONTEXT, err);
1781
 
                return NULL;
1782
 
        }
1783
 
        return rwlock;
1784
 
}
1785
 
 
1786
 
xtPublic void xt_unlock_rwlock(XTThreadPtr XT_UNUSED(self), xt_rwlock_type *rwlock)
1787
 
{
1788
 
        int err;
1789
 
 
1790
 
        err = xt_unlock_rwlock_ns(rwlock);
1791
 
        if (err)
1792
 
                xt_log_errno(XT_NS_CONTEXT, err);
1793
 
}
1794
 
 
1795
 
/*
1796
 
 * -----------------------------------------------------------------------
1797
 
 * Mutex locking
1798
 
 */
1799
 
 
1800
 
xtPublic xt_mutex_type *xt_new_mutex(XTThreadPtr self)
1801
 
{
1802
 
        xt_mutex_type *mx;
1803
 
 
1804
 
        if (!(mx = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type))))
1805
 
                return NULL;
1806
 
        pushr_(xt_free, mx);
1807
 
        if (!xt_init_mutex_with_autoname(self, mx)) {
1808
 
                freer_();
1809
 
                return NULL;
1810
 
        }
1811
 
        popr_();
1812
 
        return mx;
1813
 
}
1814
 
 
1815
 
xtPublic void xt_delete_mutex(XTThreadPtr self, xt_mutex_type *mx)
1816
 
{
1817
 
        if (mx) {
1818
 
                xt_free_mutex(mx);
1819
 
                xt_free(self, mx);
1820
 
        }
1821
 
}
1822
 
 
1823
 
#ifdef XT_THREAD_LOCK_INFO
1824
 
xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx, const char *name)
1825
 
#else
1826
 
xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx)
1827
 
#endif
1828
 
{
1829
 
        int err;
1830
 
 
1831
 
        err = xt_p_mutex_init_with_name(mx, NULL, name);
1832
 
        if (err) {
1833
 
                xt_throw_errno(XT_CONTEXT, err);
1834
 
                return FALSE;
1835
 
        }
1836
 
        return TRUE;
1837
 
}
1838
 
 
1839
 
void xt_free_mutex(xt_mutex_type *mx)
1840
 
{
1841
 
        int err;
1842
 
 
1843
 
        for (;;) {
1844
 
                err = xt_p_mutex_destroy(mx);
1845
 
                if (err != XT_EBUSY)
1846
 
                        break;
1847
 
                xt_busy_wait();
1848
 
        }
1849
 
        /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1850
 
        if (err)
1851
 
                xt_log_errno(XT_NS_CONTEXT, err);
1852
 
        */
1853
 
}
1854
 
 
1855
 
xtPublic xtBool xt_lock_mutex(XTThreadPtr self, xt_mutex_type *mx)
1856
 
{
1857
 
        int err;
1858
 
 
1859
 
        for (;;) {
1860
 
                err = xt_lock_mutex_ns(mx);
1861
 
                if (err != XT_EAGAIN)
1862
 
                        break;
1863
 
                xt_busy_wait();
1864
 
        }
1865
 
 
1866
 
        if (err) {
1867
 
                xt_throw_errno(XT_CONTEXT, err);
1868
 
                return FALSE;
1869
 
        }
1870
 
        return TRUE;
1871
 
}
1872
 
 
1873
 
xtPublic void xt_unlock_mutex(XTThreadPtr self, xt_mutex_type *mx)
1874
 
{
1875
 
        int err;
1876
 
 
1877
 
        err = xt_unlock_mutex_ns(mx);
1878
 
        if (err)
1879
 
                xt_throw_errno(XT_CONTEXT, err);
1880
 
}
1881
 
 
1882
 
xtPublic xtBool xt_set_key(pthread_key_t key, const void *value, XTExceptionPtr e)
1883
 
{
1884
 
#ifdef XT_WIN
1885
 
        my_pthread_setspecific_ptr(thr_key, (void *) value);
1886
 
#else
1887
 
        int err;
1888
 
 
1889
 
        err = pthread_setspecific(key, value);
1890
 
        if (err) {
1891
 
                if (e)
1892
 
                        xt_exception_errno(e, XT_NS_CONTEXT, err);
1893
 
                return FALSE;
1894
 
        }
1895
 
#endif
1896
 
        return TRUE;
1897
 
}
1898
 
 
1899
 
xtPublic void *xt_get_key(pthread_key_t key)
1900
 
{
1901
 
#ifdef XT_WIN
1902
 
        return my_pthread_getspecific_ptr(void *, thr_key);
1903
 
#else
1904
 
        return pthread_getspecific(key);
1905
 
#endif
1906
 
}
1907
 
 
1908
 
xtPublic xt_cond_type *xt_new_cond(XTThreadPtr self)
1909
 
{
1910
 
        xt_cond_type *cond;
1911
 
 
1912
 
        if (!(cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type))))
1913
 
                return NULL;
1914
 
        pushr_(xt_free, cond);
1915
 
        if (!xt_init_cond(self, cond)) {
1916
 
                freer_();
1917
 
                return NULL;
1918
 
        }
1919
 
        popr_();
1920
 
        return cond;
1921
 
}
1922
 
 
1923
 
xtPublic void xt_delete_cond(XTThreadPtr self, xt_cond_type *cond)
1924
 
{
1925
 
        if (cond) {
1926
 
                xt_free_cond(cond);
1927
 
                xt_free(self, cond);
1928
 
        }
1929
 
}
1930
 
 
1931
 
xtPublic xtBool xt_init_cond(XTThreadPtr self, xt_cond_type *cond)
1932
 
{
1933
 
        int err;
1934
 
 
1935
 
        err = pthread_cond_init(cond, NULL);
1936
 
        if (err) {
1937
 
                xt_throw_errno(XT_CONTEXT, err);
1938
 
                return FALSE;
1939
 
        }
1940
 
        return TRUE;
1941
 
}
1942
 
 
1943
 
xtPublic void xt_free_cond(xt_cond_type *cond)
1944
 
{
1945
 
        int err;
1946
 
 
1947
 
        for (;;) {
1948
 
                err = pthread_cond_destroy(cond);
1949
 
                if (err != XT_EBUSY)
1950
 
                        break;
1951
 
                xt_busy_wait();
1952
 
        }
1953
 
        /* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1954
 
        if (err)
1955
 
                xt_log_errno(XT_NS_CONTEXT, err);
1956
 
        */
1957
 
}
1958
 
 
1959
 
xtPublic xtBool xt_throw_delayed_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line)
1960
 
{
1961
 
        XTThreadPtr me = self ? self : xt_get_self();
1962
 
 
1963
 
        if (me->t_delayed_signal) {
1964
 
                int sig = me->t_delayed_signal;
1965
 
                
1966
 
                me->t_delayed_signal = 0;
1967
 
                xt_throw_signal(self, func, file, line, sig);
1968
 
                return FAILED;
1969
 
        }
1970
 
        return OK;
1971
 
}
1972
 
 
1973
 
xtPublic xtBool xt_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex)
1974
 
{
1975
 
        int                     err;
1976
 
        XTThreadPtr     me = self ? self : xt_get_self();
1977
 
 
1978
 
        /* PMC - In my tests, if I throw an exception from within the wait
1979
 
         * the condition and the mutex remain locked.
1980
 
         */
1981
 
        me->t_disable_interrupts = TRUE;
1982
 
        err = xt_p_cond_wait(cond, mutex);
1983
 
        me->t_disable_interrupts = FALSE;
1984
 
        if (err) {
1985
 
                xt_throw_errno(XT_CONTEXT, err);
1986
 
                return FALSE;
1987
 
        }
1988
 
        if (me->t_delayed_signal) {
1989
 
                xt_throw_delayed_signal(XT_CONTEXT);
1990
 
                return FALSE;
1991
 
        }
1992
 
        return TRUE;
1993
 
}
1994
 
 
1995
 
xtPublic xtBool xt_suspend(XTThreadPtr thread)
1996
 
{
1997
 
        xtBool ok;
1998
 
 
1999
 
        // You can only suspend yourself. 
2000
 
        ASSERT_NS(pthread_equal(thread->t_pthread, pthread_self()));
2001
 
        
2002
 
        xt_lock_mutex_ns(&thread->t_lock);
2003
 
        ok = xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock);
2004
 
        xt_unlock_mutex_ns(&thread->t_lock);
2005
 
        return ok;
2006
 
}
2007
 
 
2008
 
xtPublic xtBool xt_unsuspend(XTThreadPtr target)
2009
 
{
2010
 
        return xt_broadcast_cond_ns(&target->t_cond);
2011
 
}
2012
 
 
2013
 
xtPublic void xt_lock_thread(XTThreadPtr thread)
2014
 
{
2015
 
        xt_lock_mutex_ns(&thread->t_lock);
2016
 
}
2017
 
 
2018
 
xtPublic void xt_unlock_thread(XTThreadPtr thread)
2019
 
{
2020
 
        xt_unlock_mutex_ns(&thread->t_lock);
2021
 
}
2022
 
 
2023
 
xtPublic xtBool xt_wait_thread(XTThreadPtr thread)
2024
 
{
2025
 
        return xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock);
2026
 
}
2027
 
 
2028
 
xtPublic xtBool xt_timed_wait_thread(XTThreadPtr thread, u_long milli_sec)
2029
 
{
2030
 
        return xt_timed_wait_cond(NULL, &thread->t_cond, &thread->t_lock, milli_sec);
2031
 
}
2032
 
 
2033
 
xtPublic void xt_signal_thread(XTThreadPtr target)
2034
 
{
2035
 
        xt_broadcast_cond_ns(&target->t_cond);
2036
 
}
2037
 
 
2038
 
xtPublic void xt_terminate_thread(XTThreadPtr XT_UNUSED(self), XTThreadPtr target)
2039
 
{
2040
 
        target->t_quit = TRUE;
2041
 
        target->t_delayed_signal = SIGTERM;
2042
 
}
2043
 
 
2044
 
xtPublic xtProcID xt_getpid()
2045
 
{
2046
 
#ifdef XT_WIN
2047
 
        return GetCurrentProcessId();
2048
 
#else
2049
 
        return getpid();
2050
 
#endif
2051
 
}
2052
 
 
2053
 
xtPublic xtBool xt_process_exists(xtProcID pid)
2054
 
{
2055
 
        xtBool found;
2056
 
 
2057
 
#ifdef XT_WIN
2058
 
        HANDLE  h;
2059
 
        DWORD   code;
2060
 
 
2061
 
        found = FALSE;
2062
 
        h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
2063
 
        if (h) {
2064
 
                if (GetExitCodeProcess(h, &code)) {
2065
 
                        if (code == STILL_ACTIVE)
2066
 
                                found = TRUE;
2067
 
                }
2068
 
                CloseHandle(h);
2069
 
        }
2070
 
        else {
2071
 
                int err;
2072
 
 
2073
 
                err = HRESULT_CODE(GetLastError());
2074
 
                if (err != ERROR_INVALID_PARAMETER)
2075
 
                        found = TRUE;
2076
 
        }
2077
 
#else
2078
 
        found = TRUE;
2079
 
        if (kill(pid, 0) == -1) {
2080
 
                if (errno == ESRCH)
2081
 
                        found = FALSE;
2082
 
        }
2083
 
#endif
2084
 
        return found;   
2085
 
}
2086
 
 
2087
 
xtPublic xtBool xt_timed_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex, u_long milli_sec)
2088
 
{
2089
 
        int                             err;
2090
 
        struct timespec abstime;
2091
 
        XTThreadPtr             me = self ? self : xt_get_self();
2092
 
 
2093
 
#ifdef XT_WIN
2094
 
        union ft64              now;
2095
 
  
2096
 
        GetSystemTimeAsFileTime(&now.ft);
2097
 
 
2098
 
        /* System time is measured in 100ns units.
2099
 
         * This calculation will be reversed by the Windows implementation
2100
 
         * of pthread_cond_timedwait(), in order to extract the
2101
 
         * milli-second timeout!
2102
 
         */
2103
 
        abstime.tv.i64 = now.i64 + (milli_sec * 10000);
2104
 
  
2105
 
        abstime.max_timeout_msec = milli_sec;
2106
 
#else
2107
 
        struct timeval  now;
2108
 
        u_llong                 micro_sec;
2109
 
 
2110
 
        /* Get the current time in microseconds: */
2111
 
        gettimeofday(&now, NULL);
2112
 
        micro_sec = (u_llong) now.tv_sec * (u_llong) 1000000 + (u_llong) now.tv_usec;
2113
 
        
2114
 
        /* Add the timeout which is in milli seconds */
2115
 
        micro_sec += (u_llong) milli_sec * (u_llong) 1000;
2116
 
 
2117
 
        /* Setup the end time, which is in nano-seconds. */
2118
 
        abstime.tv_sec = (long) (micro_sec / 1000000);                          /* seconds */
2119
 
        abstime.tv_nsec = (long) ((micro_sec % 1000000) * 1000);        /* and nanoseconds */
2120
 
#endif
2121
 
 
2122
 
        me->t_disable_interrupts = TRUE;
2123
 
        err = xt_p_cond_timedwait(cond, mutex, &abstime);
2124
 
        me->t_disable_interrupts = FALSE;
2125
 
        if (err && err != ETIMEDOUT) {
2126
 
                xt_throw_errno(XT_CONTEXT, err);
2127
 
                return FALSE;
2128
 
        }
2129
 
        if (me->t_delayed_signal) {
2130
 
                xt_throw_delayed_signal(XT_CONTEXT);
2131
 
                return FALSE;
2132
 
        }
2133
 
        return TRUE;
2134
 
}
2135
 
 
2136
 
xtPublic xtBool xt_signal_cond(XTThreadPtr self, xt_cond_type *cond)
2137
 
{
2138
 
        int err;
2139
 
 
2140
 
        err = pthread_cond_signal(cond);
2141
 
        if (err) {
2142
 
                xt_throw_errno(XT_CONTEXT, err);
2143
 
                return FAILED;
2144
 
        }
2145
 
        return OK;
2146
 
}
2147
 
 
2148
 
xtPublic void xt_broadcast_cond(XTThreadPtr self, xt_cond_type *cond)
2149
 
{
2150
 
        int err;
2151
 
 
2152
 
        err = pthread_cond_broadcast(cond);
2153
 
        if (err)
2154
 
                xt_throw_errno(XT_CONTEXT, err);
2155
 
}
2156
 
 
2157
 
xtPublic xtBool xt_broadcast_cond_ns(xt_cond_type *cond)
2158
 
{
2159
 
        int err;
2160
 
 
2161
 
        err = pthread_cond_broadcast(cond);
2162
 
        if (err) {
2163
 
                xt_register_errno(XT_REG_CONTEXT, err);
2164
 
                return FAILED;
2165
 
        }
2166
 
        return OK;
2167
 
}
2168
 
 
2169
 
static int prof_setjmp_count = 0;
2170
 
 
2171
 
xtPublic int prof_setjmp(void)
2172
 
{
2173
 
        prof_setjmp_count++;
2174
 
        return 0;
2175
 
}
2176
 
 
2177
 
xtPublic void xt_set_low_priority(XTThreadPtr self)
2178
 
{
2179
 
        int err = xt_p_set_low_priority(self->t_pthread);
2180
 
        if (err) {
2181
 
                self = NULL; /* Will cause logging, instead of throwing exception */
2182
 
                xt_throw_errno(XT_CONTEXT, err);
2183
 
        }
2184
 
}
2185
 
 
2186
 
xtPublic void xt_set_normal_priority(XTThreadPtr self)
2187
 
{
2188
 
        int err = xt_p_set_normal_priority(self->t_pthread);
2189
 
        if (err) {
2190
 
                self = NULL; /* Will cause logging, instead of throwing exception */
2191
 
                xt_throw_errno(XT_CONTEXT, err);
2192
 
        }
2193
 
}
2194
 
 
2195
 
xtPublic void xt_set_high_priority(XTThreadPtr self)
2196
 
{
2197
 
        int err = xt_p_set_high_priority(self->t_pthread);
2198
 
        if (err) {
2199
 
                self = NULL; /* Will cause logging, instead of throwing exception */
2200
 
                xt_throw_errno(XT_CONTEXT, err);
2201
 
        }
2202
 
}
2203
 
 
2204
 
xtPublic void xt_set_priority(XTThreadPtr self, int priority)
2205
 
{
2206
 
        if (priority < XT_PRIORITY_NORMAL)
2207
 
                xt_set_low_priority(self);
2208
 
        else if (priority > XT_PRIORITY_NORMAL)
2209
 
                xt_set_high_priority(self);
2210
 
        else
2211
 
                xt_set_normal_priority(self);
2212
 
}
2213
 
 
2214
 
/* ----------------------------------------------------------------------
2215
 
 * THREAD WAIT LIST
2216
 
 */
2217
 
 
2218
 
/*
2219
 
 * Add a thread the wakeup list of a thread.
2220
 
 */
2221
 
xtPublic xtBool xt_add_to_wakeup_list(xtThreadID waiting_id, xtThreadID wait_for_id)
2222
 
{
2223
 
        XTWaitThreadPtr wt;
2224
 
        
2225
 
        THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, waiting_id);
2226
 
        wt = xt_thr_array[wait_for_id].td_waiting;
2227
 
        THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, waiting_id);
2228
 
        xt_spinlock_lock(&wt->wt_wait_list_lock);
2229
 
        if (wt->wt_wait_list_count == wt->wt_wait_list_size) {
2230
 
                if (!xt_realloc_ns((void **) &wt->wt_wait_list, (wt->wt_wait_list_size+1) * sizeof(xtThreadID)))
2231
 
                        return FAILED;
2232
 
                wt->wt_wait_list_size++;
2233
 
        }
2234
 
        for (u_int i=0; i<wt->wt_wait_list_count; i++) {
2235
 
                if (wt->wt_wait_list[i] == waiting_id)
2236
 
                        goto done;
2237
 
        }
2238
 
        wt->wt_wait_list[wt->wt_wait_list_count] = waiting_id;
2239
 
        wt->wt_wait_list_count++;
2240
 
        done:
2241
 
        xt_spinlock_unlock(&wt->wt_wait_list_lock);
2242
 
        return OK;
2243
 
}
2244
 
 
2245
 
/*
2246
 
 * Wakeup a single thread.
2247
 
 */
2248
 
// Depending on platform 'thread->t_id' may not be used by THR_ARRAY_READ_LOCK().
2249
 
xtPublic void xt_wakeup_thread(xtThreadID thd_id, XTThreadPtr thread __attribute__((unused)))
2250
 
{
2251
 
        XTWaitThreadPtr target_wt;
2252
 
 
2253
 
        THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2254
 
        target_wt = xt_thr_array[thd_id].td_waiting;
2255
 
        THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2256
 
        xt_lock_mutex_ns(&target_wt->wt_lock);
2257
 
        xt_broadcast_cond_ns(&target_wt->wt_cond);
2258
 
        xt_unlock_mutex_ns(&target_wt->wt_lock);
2259
 
}
2260
 
 
2261
 
/*
2262
 
 * Wakeup a list of threads (the list is local to the calling thread).
2263
 
 */
2264
 
xtPublic void xt_wakeup_thread_list(XTThreadPtr thread)
2265
 
{
2266
 
        XTWaitThreadPtr target_wt;
2267
 
 
2268
 
        for (u_int i=0; i<thread->st_thread_list_count; i++) {
2269
 
                THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2270
 
                target_wt = xt_thr_array[thread->st_thread_list[i]].td_waiting;
2271
 
                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2272
 
                xt_lock_mutex_ns(&target_wt->wt_lock);
2273
 
                xt_broadcast_cond_ns(&target_wt->wt_cond);
2274
 
                xt_unlock_mutex_ns(&target_wt->wt_lock);
2275
 
        }
2276
 
        thread->st_thread_list_count = 0;
2277
 
}
2278
 
 
2279
 
/*
2280
 
 * Wakeup all threads waiting for this thread.
2281
 
 */
2282
 
xtPublic void xt_wakeup_waiting_threads(XTThreadPtr thread)
2283
 
{
2284
 
        XTWaitThreadPtr wt;
2285
 
        XTWaitThreadPtr target_wt;
2286
 
        
2287
 
        THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2288
 
        wt = xt_thr_array[thread->t_id].td_waiting;
2289
 
        THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2290
 
        if (!wt->wt_wait_list_count)
2291
 
                return;
2292
 
 
2293
 
        xt_spinlock_lock(&wt->wt_wait_list_lock);
2294
 
        if (thread->st_thread_list_size < wt->wt_wait_list_count) {
2295
 
                if (!xt_realloc_ns((void **) &thread->st_thread_list, wt->wt_wait_list_count * sizeof(xtThreadID)))
2296
 
                        goto failed;
2297
 
                 thread->st_thread_list_size = wt->wt_wait_list_count;
2298
 
        }
2299
 
        memcpy(thread->st_thread_list, wt->wt_wait_list, wt->wt_wait_list_count * sizeof(xtThreadID));
2300
 
        thread->st_thread_list_count = wt->wt_wait_list_count;
2301
 
        wt->wt_wait_list_count = 0;
2302
 
        xt_spinlock_unlock(&wt->wt_wait_list_lock);
2303
 
 
2304
 
        xt_wakeup_thread_list(thread);
2305
 
        return;
2306
 
        
2307
 
        failed:
2308
 
        for (u_int i=0; i<wt->wt_wait_list_count; i++) {
2309
 
                THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2310
 
                target_wt = xt_thr_array[wt->wt_wait_list[i]].td_waiting;
2311
 
                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2312
 
                xt_lock_mutex_ns(&target_wt->wt_lock);
2313
 
                xt_broadcast_cond_ns(&target_wt->wt_cond);
2314
 
                xt_unlock_mutex_ns(&target_wt->wt_lock);
2315
 
        }
2316
 
        wt->wt_wait_list_count = 0;
2317
 
        xt_spinlock_unlock(&wt->wt_wait_list_lock);
2318
 
}
2319
 
 
2320
 
/*
2321
 
 * -----------------------------------------------------------------------
2322
 
 * STATISTICS
2323
 
 */
2324
 
 
2325
 
#ifdef DEBUG_NO_ACTIVITY
2326
 
static void debug_no_activity()
2327
 
{
2328
 
        xt_logf(XT_NT_INFO, "No activity!\n");
2329
 
}
2330
 
 
2331
 
time_t          last_call_time;
2332
 
u_llong         last_commit_total;
2333
 
xtWord8         last_rec_flush_time = (xtWord8) -1;
2334
 
xtWord8         last_rec_write_time = (xtWord8) -1;
2335
 
xtWord8         last_ind_flush_time = (xtWord8) -1;
2336
 
xtWord8         last_ind_write_time = (xtWord8) -1;
2337
 
xtWord8         last_ilog_flush_time = (xtWord8) -1;
2338
 
xtWord8         last_ilog_write_time = (xtWord8) -1;
2339
 
xtWord8         last_xlog_flush_time = (xtWord8) -1;
2340
 
xtWord8         last_xlog_write_time = (xtWord8) -1;
2341
 
xtWord8         last_data_flush_time = (xtWord8) -1;
2342
 
xtWord8         last_data_write_time = (xtWord8) -1;
2343
 
#endif
2344
 
 
2345
 
xtPublic void xt_gather_statistics(XTStatisticsPtr stats)
2346
 
{
2347
 
        XTThreadDataRec *thr_data;
2348
 
        XTThreadPtr             thr;
2349
 
        xtWord8                 s;
2350
 
 
2351
 
        xt_lock_mutex_ns(&thr_array_lock);
2352
 
        *stats = thr_statistics;
2353
 
        // Ignore index 0, it is not used!
2354
 
        // No read resize lock required if I have the array lock
2355
 
        thr_data = &xt_thr_array[XT_MIN_THREAD_ID];
2356
 
        for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_current_max_threads; i++) {
2357
 
                if ((thr = thr_data->td_thread)) {
2358
 
                        stats->st_commits += thr->st_statistics.st_commits;
2359
 
                        stats->st_rollbacks += thr->st_statistics.st_rollbacks;
2360
 
                        stats->st_stat_read += thr->st_statistics.st_stat_read;
2361
 
                        stats->st_stat_write += thr->st_statistics.st_stat_write;
2362
 
 
2363
 
                        XT_ADD_STATS(stats->st_rec, thr->st_statistics.st_rec);
2364
 
                        if ((s = thr->st_statistics.st_rec.ts_flush_start))
2365
 
                                stats->st_rec.ts_flush_time += xt_trace_clock() - s;
2366
 
#ifdef XT_TIME_DISK_WRITES
2367
 
                        if ((s = thr->st_statistics.st_rec.ts_write_start))
2368
 
                                stats->st_rec.ts_write_time += xt_trace_clock() - s;
2369
 
#endif
2370
 
#ifdef XT_TIME_DISK_READS
2371
 
                        if ((s = thr->st_statistics.st_rec.ts_read_start))
2372
 
                                stats->st_rec.ts_read_time += xt_trace_clock() - s;
2373
 
#endif
2374
 
                        stats->st_rec_cache_hit += thr->st_statistics.st_rec_cache_hit;
2375
 
                        stats->st_rec_cache_miss += thr->st_statistics.st_rec_cache_miss;
2376
 
                        stats->st_rec_cache_frees += thr->st_statistics.st_rec_cache_frees;
2377
 
 
2378
 
                        XT_ADD_STATS(stats->st_ind, thr->st_statistics.st_ind);
2379
 
                        if ((s = thr->st_statistics.st_ind.ts_flush_start))
2380
 
                                stats->st_ind.ts_flush_time += xt_trace_clock() - s;
2381
 
#ifdef XT_TIME_DISK_WRITES
2382
 
                        if ((s = thr->st_statistics.st_ind.ts_write_start))
2383
 
                                stats->st_ind.ts_write_time += xt_trace_clock() - s;
2384
 
#endif
2385
 
#ifdef XT_TIME_DISK_READS
2386
 
                        if ((s = thr->st_statistics.st_ind.ts_read_start))
2387
 
                                stats->st_ind.ts_read_time += xt_trace_clock() - s;
2388
 
#endif
2389
 
                        stats->st_ind_cache_hit += thr->st_statistics.st_ind_cache_hit;
2390
 
                        stats->st_ind_cache_miss += thr->st_statistics.st_ind_cache_miss;
2391
 
                        XT_ADD_STATS(stats->st_ilog, thr->st_statistics.st_ilog);
2392
 
                        if ((s = thr->st_statistics.st_ilog.ts_flush_start))
2393
 
                                stats->st_ilog.ts_flush_time += xt_trace_clock() - s;
2394
 
#ifdef XT_TIME_DISK_WRITES
2395
 
                        if ((s = thr->st_statistics.st_ilog.ts_write_start))
2396
 
                                stats->st_ilog.ts_write_time += xt_trace_clock() - s;
2397
 
#endif
2398
 
#ifdef XT_TIME_DISK_READS
2399
 
                        if ((s = thr->st_statistics.st_ilog.ts_read_start))
2400
 
                                stats->st_ilog.ts_read_time += xt_trace_clock() - s;
2401
 
#endif
2402
 
 
2403
 
                        XT_ADD_STATS(stats->st_xlog, thr->st_statistics.st_xlog);
2404
 
                        if ((s = thr->st_statistics.st_xlog.ts_flush_start))
2405
 
                                stats->st_xlog.ts_flush_time += xt_trace_clock() - s;
2406
 
#ifdef XT_TIME_DISK_WRITES
2407
 
                        if ((s = thr->st_statistics.st_xlog.ts_write_start))
2408
 
                                stats->st_xlog.ts_write_time += xt_trace_clock() - s;
2409
 
#endif
2410
 
#ifdef XT_TIME_DISK_READS
2411
 
                        if ((s = thr->st_statistics.st_xlog.ts_read_start))
2412
 
                                stats->st_xlog.ts_read_time += xt_trace_clock() - s;
2413
 
#endif
2414
 
                        stats->st_xlog_cache_hit += thr->st_statistics.st_xlog_cache_hit;
2415
 
                        stats->st_xlog_cache_miss += thr->st_statistics.st_xlog_cache_miss;
2416
 
 
2417
 
                        XT_ADD_STATS(stats->st_data, thr->st_statistics.st_data);
2418
 
                        if ((s = thr->st_statistics.st_data.ts_flush_start))
2419
 
                                stats->st_data.ts_flush_time += xt_trace_clock() - s;
2420
 
#ifdef XT_TIME_DISK_WRITES
2421
 
                        if ((s = thr->st_statistics.st_data.ts_write_start))
2422
 
                                stats->st_data.ts_write_time += xt_trace_clock() - s;
2423
 
#endif
2424
 
#ifdef XT_TIME_DISK_READS
2425
 
                        if ((s = thr->st_statistics.st_data.ts_read_start))
2426
 
                                stats->st_data.ts_read_time += xt_trace_clock() - s;
2427
 
#endif
2428
 
 
2429
 
                        stats->st_scan_index += thr->st_statistics.st_scan_index;
2430
 
                        stats->st_scan_table += thr->st_statistics.st_scan_table;
2431
 
                        stats->st_row_select += thr->st_statistics.st_row_select;
2432
 
                        stats->st_row_insert += thr->st_statistics.st_row_insert;
2433
 
                        stats->st_row_update += thr->st_statistics.st_row_update;
2434
 
                        stats->st_row_delete += thr->st_statistics.st_row_delete;
2435
 
 
2436
 
                        stats->st_wait_for_xact += thr->st_statistics.st_wait_for_xact;
2437
 
                        stats->st_retry_index_scan += thr->st_statistics.st_retry_index_scan;
2438
 
                        stats->st_reread_record_list += thr->st_statistics.st_reread_record_list;
2439
 
 
2440
 
                        stats->st_ind_cache_dirty += thr->st_statistics.st_ind_cache_dirty;
2441
 
                }
2442
 
                thr_data++;
2443
 
        }
2444
 
        xt_unlock_mutex_ns(&thr_array_lock);
2445
 
 
2446
 
#ifdef DEBUG_NO_ACTIVITY
2447
 
        time_t now = time(NULL);
2448
 
 
2449
 
        /* Make sure at least 1 second has gone by: */
2450
 
        if (!last_call_time || now > last_call_time) {
2451
 
                if (last_commit_total &&
2452
 
                        last_commit_total == stats->st_commits &&
2453
 
                        last_rec_flush_time == stats->st_rec.ts_flush_time &&
2454
 
                        last_ind_flush_time == stats->st_ind.ts_flush_time &&
2455
 
                        last_ilog_flush_time == stats->st_ilog.ts_flush_time &&
2456
 
                        last_xlog_flush_time == stats->st_xlog.ts_flush_time &&
2457
 
                        last_data_flush_time == stats->st_data.ts_flush_time &&
2458
 
                        last_rec_write_time == stats->st_rec.ts_write_time &&
2459
 
                        last_ind_write_time == stats->st_ind.ts_write_time &&
2460
 
                        last_ilog_write_time == stats->st_ilog.ts_write_time &&
2461
 
                        last_xlog_write_time == stats->st_xlog.ts_write_time &&
2462
 
                        last_data_write_time == stats->st_data.ts_write_time
2463
 
                        )
2464
 
                        debug_no_activity();
2465
 
 
2466
 
                last_call_time = now;
2467
 
                last_commit_total = stats->st_commits;
2468
 
 
2469
 
                last_rec_flush_time = stats->st_rec.ts_flush_time;
2470
 
                last_ind_flush_time = stats->st_ind.ts_flush_time;
2471
 
                last_ilog_flush_time = stats->st_ilog.ts_flush_time;
2472
 
                last_xlog_flush_time = stats->st_xlog.ts_flush_time;
2473
 
                last_data_flush_time = stats->st_data.ts_flush_time;
2474
 
 
2475
 
                last_rec_write_time = stats->st_rec.ts_write_time;
2476
 
                last_ind_write_time = stats->st_ind.ts_write_time;
2477
 
                last_ilog_write_time = stats->st_ilog.ts_write_time;
2478
 
                last_xlog_write_time = stats->st_xlog.ts_write_time;
2479
 
                last_data_write_time = stats->st_data.ts_write_time;
2480
 
        }
2481
 
#endif
2482
 
}
2483
 
 
2484
 
xtPublic int xt_get_index_cache_dirty_perc()
2485
 
{
2486
 
        XTThreadDataRec *thr;
2487
 
        XTStatisticsRec stats;
2488
 
        double                  v;
2489
 
 
2490
 
        xt_lock_mutex_ns(&thr_array_lock);
2491
 
        stats = thr_statistics;
2492
 
        // Ignore index 0 and 1, it is not used!
2493
 
        // No read resize lock required if I have the array lock
2494
 
        thr = &xt_thr_array[XT_MIN_THREAD_ID];
2495
 
        for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_current_max_threads; i++) {
2496
 
                if (thr->td_thread)
2497
 
                        stats.st_ind_cache_dirty += thr->td_thread->st_statistics.st_ind_cache_dirty;
2498
 
                thr++;
2499
 
        }
2500
 
        xt_unlock_mutex_ns(&thr_array_lock);
2501
 
        v = (double) stats.st_ind_cache_dirty * (double) XT_INDEX_PAGE_SIZE;
2502
 
        return (int) (v / (double) xt_ind_get_size() * (double) 100);
2503
 
}
2504
 
 
2505
 
static void thr_accumulate_statistics(XTThreadPtr self)
2506
 
{
2507
 
        thr_statistics.st_commits += self->st_statistics.st_commits;
2508
 
        thr_statistics.st_rollbacks += self->st_statistics.st_rollbacks;
2509
 
        thr_statistics.st_stat_read += self->st_statistics.st_stat_read;
2510
 
        thr_statistics.st_stat_write += self->st_statistics.st_stat_write;
2511
 
 
2512
 
        XT_ADD_STATS(thr_statistics.st_rec, self->st_statistics.st_rec);
2513
 
        thr_statistics.st_rec_cache_hit += self->st_statistics.st_rec_cache_hit;
2514
 
        thr_statistics.st_rec_cache_miss += self->st_statistics.st_rec_cache_miss;
2515
 
        thr_statistics.st_rec_cache_frees += self->st_statistics.st_rec_cache_frees;
2516
 
 
2517
 
        XT_ADD_STATS(thr_statistics.st_ind, self->st_statistics.st_ind);
2518
 
        thr_statistics.st_ind_cache_hit += self->st_statistics.st_ind_cache_hit;
2519
 
        thr_statistics.st_ind_cache_miss += self->st_statistics.st_ind_cache_miss;
2520
 
        XT_ADD_STATS(thr_statistics.st_ilog, self->st_statistics.st_ilog);
2521
 
 
2522
 
        XT_ADD_STATS(thr_statistics.st_xlog, self->st_statistics.st_xlog);
2523
 
        thr_statistics.st_xlog_cache_hit += self->st_statistics.st_xlog_cache_hit;
2524
 
        thr_statistics.st_xlog_cache_miss += self->st_statistics.st_xlog_cache_miss;
2525
 
 
2526
 
        XT_ADD_STATS(thr_statistics.st_data, self->st_statistics.st_data);
2527
 
 
2528
 
        thr_statistics.st_scan_index += self->st_statistics.st_scan_index;
2529
 
        thr_statistics.st_scan_table += self->st_statistics.st_scan_table;
2530
 
        thr_statistics.st_row_select += self->st_statistics.st_row_select;
2531
 
        thr_statistics.st_row_insert += self->st_statistics.st_row_insert;
2532
 
        thr_statistics.st_row_update += self->st_statistics.st_row_update;
2533
 
        thr_statistics.st_row_delete += self->st_statistics.st_row_delete;
2534
 
 
2535
 
        thr_statistics.st_wait_for_xact += self->st_statistics.st_wait_for_xact;
2536
 
        thr_statistics.st_retry_index_scan += self->st_statistics.st_retry_index_scan;
2537
 
        thr_statistics.st_reread_record_list += self->st_statistics.st_reread_record_list;
2538
 
 
2539
 
        thr_statistics.st_ind_cache_dirty += self->st_statistics.st_ind_cache_dirty;
2540
 
}
2541
 
 
2542
 
xtPublic u_llong xt_get_statistic(XTStatisticsPtr stats, XTDatabaseHPtr db, u_int rec_id)
2543
 
{
2544
 
        u_llong stat_value;
2545
 
 
2546
 
        switch (rec_id) {
2547
 
                case XT_STAT_TIME_CURRENT:
2548
 
                        stat_value = (u_llong) time(NULL);
2549
 
                        break;
2550
 
                case XT_STAT_TIME_PASSED:
2551
 
                        stat_value = (u_llong) xt_trace_clock();
2552
 
                        break;
2553
 
                case XT_STAT_COMMITS:
2554
 
                        stat_value = stats->st_commits;
2555
 
                        break;
2556
 
                case XT_STAT_ROLLBACKS:
2557
 
                        stat_value = stats->st_rollbacks;
2558
 
                        break;
2559
 
                case XT_STAT_STAT_READS:
2560
 
                        stat_value = stats->st_stat_read;
2561
 
                        break;
2562
 
                case XT_STAT_STAT_WRITES:
2563
 
                        stat_value = stats->st_stat_write;
2564
 
                        break;
2565
 
 
2566
 
                case XT_STAT_REC_BYTES_IN:
2567
 
                        stat_value = stats->st_rec.ts_read;
2568
 
                        break;
2569
 
                case XT_STAT_REC_BYTES_OUT:
2570
 
                        stat_value = stats->st_rec.ts_write;
2571
 
                        break;
2572
 
                case XT_STAT_REC_SYNC_COUNT:
2573
 
                        stat_value = stats->st_rec.ts_flush;
2574
 
                        break;
2575
 
                case XT_STAT_REC_SYNC_TIME:
2576
 
                        stat_value = stats->st_rec.ts_flush_time;
2577
 
                        break;
2578
 
                case XT_STAT_REC_CACHE_HIT:
2579
 
                        stat_value = stats->st_rec_cache_hit;
2580
 
                        break;
2581
 
                case XT_STAT_REC_CACHE_MISS:
2582
 
                        stat_value = stats->st_rec_cache_miss;
2583
 
                        break;
2584
 
                case XT_STAT_REC_CACHE_FREES:
2585
 
                        stat_value = stats->st_rec_cache_frees;
2586
 
                        break;
2587
 
                case XT_STAT_REC_CACHE_USAGE:
2588
 
                        stat_value = (u_llong) xt_tc_get_usage();
2589
 
                        break;
2590
 
 
2591
 
                case XT_STAT_IND_BYTES_IN:
2592
 
                        stat_value = stats->st_ind.ts_read;
2593
 
                        break;
2594
 
                case XT_STAT_IND_BYTES_OUT:
2595
 
                        stat_value = stats->st_ind.ts_write;
2596
 
                        break;
2597
 
                case XT_STAT_IND_SYNC_COUNT:
2598
 
                        stat_value = stats->st_ind.ts_flush;
2599
 
                        break;
2600
 
                case XT_STAT_IND_SYNC_TIME:
2601
 
                        stat_value = stats->st_ind.ts_flush_time;
2602
 
                        break;
2603
 
                case XT_STAT_IND_CACHE_HIT:
2604
 
                        stat_value = stats->st_ind_cache_hit;
2605
 
                        break;
2606
 
                case XT_STAT_IND_CACHE_MISS:
2607
 
                        stat_value = stats->st_ind_cache_miss;
2608
 
                        break;
2609
 
                case XT_STAT_IND_CACHE_USAGE:
2610
 
                        stat_value = (u_llong) xt_ind_get_usage();
2611
 
                        break;
2612
 
                case XT_STAT_ILOG_BYTES_IN:
2613
 
                        stat_value = stats->st_ilog.ts_read;
2614
 
                        break;
2615
 
                case XT_STAT_ILOG_BYTES_OUT:
2616
 
                        stat_value = stats->st_ilog.ts_write;
2617
 
                        break;
2618
 
                case XT_STAT_ILOG_SYNC_COUNT:
2619
 
                        stat_value = stats->st_ilog.ts_flush;
2620
 
                        break;
2621
 
                case XT_STAT_ILOG_SYNC_TIME:
2622
 
                        stat_value = stats->st_ilog.ts_flush_time;
2623
 
                        break;
2624
 
 
2625
 
                case XT_STAT_XLOG_BYTES_IN:
2626
 
                        stat_value = stats->st_xlog.ts_read;
2627
 
                        break;
2628
 
                case XT_STAT_XLOG_BYTES_OUT:
2629
 
                        stat_value = stats->st_xlog.ts_write;
2630
 
                        break;
2631
 
                case XT_STAT_XLOG_SYNC_COUNT:
2632
 
                        stat_value = stats->st_xlog.ts_flush;
2633
 
                        break;
2634
 
                case XT_STAT_XLOG_SYNC_TIME:
2635
 
                        stat_value = stats->st_xlog.ts_flush_time;
2636
 
                        break;
2637
 
                case XT_STAT_XLOG_CACHE_HIT:
2638
 
                        stat_value = stats->st_xlog_cache_hit;
2639
 
                        break;
2640
 
                case XT_STAT_XLOG_CACHE_MISS:
2641
 
                        stat_value = stats->st_xlog_cache_miss;
2642
 
                        break;
2643
 
                case XT_STAT_XLOG_CACHE_USAGE:
2644
 
                        stat_value = (u_llong) xt_xlog_get_usage();
2645
 
                        break;
2646
 
 
2647
 
                case XT_STAT_DATA_BYTES_IN:
2648
 
                        stat_value = stats->st_data.ts_read;
2649
 
                        break;
2650
 
                case XT_STAT_DATA_BYTES_OUT:
2651
 
                        stat_value = stats->st_data.ts_write;
2652
 
                        break;
2653
 
                case XT_STAT_DATA_SYNC_COUNT:
2654
 
                        stat_value = stats->st_data.ts_flush;
2655
 
                        break;
2656
 
                case XT_STAT_DATA_SYNC_TIME:
2657
 
                        stat_value = stats->st_data.ts_flush_time;
2658
 
                        break;
2659
 
 
2660
 
                case XT_STAT_BYTES_TO_CHKPNT:
2661
 
                        stat_value = db ? xt_bytes_since_last_checkpoint(db, db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset) : 0;
2662
 
                        break;
2663
 
                case XT_STAT_LOG_BYTES_TO_WRITE:
2664
 
                        stat_value = db ? db->db_xlog.xl_log_bytes_written - db->db_xlog.xl_log_bytes_read : 0;//db->db_xlog.xlog_bytes_to_write();
2665
 
                        break;
2666
 
                case XT_STAT_BYTES_TO_SWEEP:
2667
 
                        /* This stat is potentially very expensive: */
2668
 
                        stat_value = db ? xt_xn_bytes_to_sweep(db, xt_get_self()) : 0;
2669
 
                        break;
2670
 
                case XT_STAT_WAIT_FOR_XACT:
2671
 
                        stat_value = stats->st_wait_for_xact;
2672
 
                        break;
2673
 
                case XT_STAT_XACT_TO_CLEAN:
2674
 
#ifdef XT_SWEEPER_SORT_XACTS
2675
 
                        stat_value = db ? db->db_xn_curr_id + 1 - db->db_sw_to_add + db->db_sw_list_size : 0;
2676
 
#else
2677
 
                        stat_value = db ? db->db_xn_curr_id + 1 - db->db_xn_to_clean_id : 0;
2678
 
#endif
2679
 
                        break;
2680
 
                case XT_STAT_SWEEPER_WAITS:
2681
 
                        stat_value = db ? db->db_stat_sweep_waits : 0;
2682
 
                        break;
2683
 
 
2684
 
                case XT_STAT_SCAN_INDEX:
2685
 
                        stat_value = stats->st_scan_index;
2686
 
                        break;
2687
 
                case XT_STAT_SCAN_TABLE:
2688
 
                        stat_value = stats->st_scan_table;
2689
 
                        break;
2690
 
                case XT_STAT_ROW_SELECT:
2691
 
                        stat_value = stats->st_row_select;
2692
 
                        break;
2693
 
                case XT_STAT_ROW_INSERT:
2694
 
                        stat_value = stats->st_row_insert;
2695
 
                        break;
2696
 
                case XT_STAT_ROW_UPDATE:
2697
 
                        stat_value = stats->st_row_update;
2698
 
                        break;
2699
 
                case XT_STAT_ROW_DELETE:
2700
 
                        stat_value = stats->st_row_delete;
2701
 
                        break;
2702
 
 
2703
 
                case XT_STAT_RETRY_INDEX_SCAN:
2704
 
                        stat_value = stats->st_retry_index_scan;
2705
 
                        break;
2706
 
                case XT_STAT_REREAD_REC_LIST:
2707
 
                        stat_value = stats->st_reread_record_list;
2708
 
                        break;
2709
 
 
2710
 
                case XT_STAT_IND_CACHE_DIRTY:
2711
 
                        ASSERT_NS(stats->st_ind_cache_dirty >= 0);
2712
 
                        if (stats->st_ind_cache_dirty < 0)
2713
 
                                stat_value = 0;
2714
 
                        else
2715
 
                                stat_value = stats->st_ind_cache_dirty;
2716
 
                        stat_value *= (u_llong) XT_INDEX_PAGE_SIZE;
2717
 
                        break;
2718
 
 
2719
 
#ifdef XT_TIME_DISK_WRITES
2720
 
                case XT_STAT_REC_WRITE_TIME:
2721
 
                        stat_value = stats->st_rec.ts_write_time;
2722
 
                        break;
2723
 
                case XT_STAT_IND_WRITE_TIME:
2724
 
                        stat_value = stats->st_ind.ts_write_time;
2725
 
                        break;
2726
 
                case XT_STAT_ILOG_WRITE_TIME:
2727
 
                        stat_value = stats->st_ilog.ts_write_time;
2728
 
                        break;
2729
 
                case XT_STAT_XLOG_WRITE_TIME:
2730
 
                        stat_value = stats->st_xlog.ts_write_time;
2731
 
                        break;
2732
 
                case XT_STAT_DATA_WRITE_TIME:
2733
 
                        stat_value = stats->st_data.ts_write_time;
2734
 
                        break;
2735
 
#endif
2736
 
 
2737
 
#ifdef XT_TIME_DISK_READS
2738
 
                case XT_STAT_REC_READ_TIME:
2739
 
                        stat_value = stats->st_rec.ts_read_time;
2740
 
                        break;
2741
 
                case XT_STAT_IND_READ_TIME:
2742
 
                        stat_value = stats->st_ind.ts_read_time;
2743
 
                        break;
2744
 
                case XT_STAT_LOG_READ_TIME:
2745
 
                        stat_value = stats->st_ilog.ts_read_time + stats->st_xlog.ts_read_time + stats->st_data.ts_read_time;
2746
 
                        break;
2747
 
#endif
2748
 
 
2749
 
                default:
2750
 
                        stat_value = 0;
2751
 
                        break;
2752
 
        }
2753
 
        return stat_value;
2754
 
}
2755