~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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