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

« back to all changes in this revision

Viewing changes to plugin/pbxt/src/lock_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
 * 2008-01-24   Paul McCullagh
 
20
 *
 
21
 * Row lock functions.
 
22
 *
 
23
 * H&G2JCtL
 
24
 */
 
25
 
 
26
#include "xt_config.h"
 
27
 
 
28
#ifdef DRIZZLED
 
29
#include <bitset>
 
30
#endif
 
31
 
 
32
#include <stdio.h>
 
33
 
 
34
#include "lock_xt.h"
 
35
#include "thread_xt.h"
 
36
#include "table_xt.h"
 
37
#include "xaction_xt.h"
 
38
#include "database_xt.h"
 
39
#include "trace_xt.h"
 
40
 
 
41
#ifdef DEBUG
 
42
//#define XT_TRACE_LOCKS
 
43
//#define CHECK_ROWLOCK_GROUP_CONSISTENCY
 
44
#endif
 
45
 
 
46
/*
 
47
 * This function should never be called. It indicates a link
 
48
 * error!
 
49
 */
 
50
xtPublic void xt_log_atomic_error_and_abort(c_char *func, c_char *file, u_int line)
 
51
{
 
52
        xt_logf(NULL, func, file, line, XT_LOG_ERROR, "%s", "Atomic operations not supported\n");
 
53
        abort();
 
54
}
 
55
 
 
56
/*
 
57
 * -----------------------------------------------------------------------
 
58
 * ROW LOCKS, LIST BASED
 
59
 */
 
60
#ifdef XT_USE_LIST_BASED_ROW_LOCKS
 
61
 
 
62
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
63
/* 
 
64
 * Requires a spin-lock on group->lg_lock!
 
65
 */
 
66
static void check_rowlock_group(XTLockGroupPtr group)
 
67
{
 
68
        XTThreadPtr self = xt_get_self();
 
69
 
 
70
        char *crash = NULL;
 
71
 
 
72
        if (group->lg_lock.spl_locker != self)
 
73
                *crash = 1;
 
74
 
 
75
        if (group->lg_list_in_use > group->lg_list_size)
 
76
                *crash = 1;
 
77
 
 
78
        xtRowID prev_row = 0;
 
79
        XTLockItemPtr item = group->lg_list;
 
80
 
 
81
        for (int i = 0; i < group->lg_list_in_use; i++, item++) {
 
82
 
 
83
                if (!item->li_thread_id)
 
84
                        *crash = 1;
 
85
 
 
86
                THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, self->t_id);
 
87
                if(!xt_thr_array[item->li_thread_id]->st_xact_data)
 
88
                        *crash = 1;
 
89
                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, self->t_id);
 
90
 
 
91
                if(item->li_count > XT_TEMP_LOCK_BYTES)
 
92
                        *crash = 1;
 
93
 
 
94
                // rows per thread must obey the row_id > prev_row_id + prev_count*group_size rule
 
95
                if (prev_row >= item->li_row_id)
 
96
                        *crash = 1;
 
97
 
 
98
                // calculate the new prev. row
 
99
                if (item->li_count < XT_TEMP_LOCK_BYTES)
 
100
                        prev_row = item->li_row_id + (item->li_count - 1) * XT_ROW_LOCK_GROUP_COUNT;
 
101
                else
 
102
                        prev_row = item->li_row_id;
 
103
        }
 
104
}
 
105
#endif
 
106
 
 
107
static int xlock_cmp_row_ids(XTThreadPtr XT_UNUSED(self), register const void *XT_UNUSED(thunk), register const void *a, register const void *b)
 
108
{
 
109
        xtRowID                 row_id = *((xtTableID *) a);
 
110
        XTLockItemPtr   item = (XTLockItemPtr) b;
 
111
 
 
112
        if (row_id < item->li_row_id)
 
113
                return -1;
 
114
        if (row_id > item->li_row_id)
 
115
                return 1;
 
116
        return 0;
 
117
}
 
118
 
 
119
void XTRowLockList::xt_remove_all_locks(struct XTDatabase *, XTThreadPtr thread)
 
120
{
 
121
#ifdef XT_TRACE_LOCKS
 
122
        xt_ttracef(xt_get_self(), "remove all locks\n");
 
123
#endif
 
124
        if (!bl_count)
 
125
                return;
 
126
 
 
127
        xtThreadID                      thd_id;
 
128
        XTPermRowLockPtr        plock;
 
129
#ifndef XT_USE_TABLE_REF
 
130
        XTOpenTablePtr          pot = NULL;
 
131
#endif
 
132
 
 
133
        thd_id = thread->t_id;
 
134
        plock = (XTPermRowLockPtr) bl_data;
 
135
        for (u_int i=0; i<bl_count; i++) {
 
136
#ifdef XT_USE_TABLE_REF
 
137
                XTTableHPtr             tab = plock->pr_table;
 
138
#else
 
139
                if (!xt_db_open_pool_table_ns(&pot, db, plock->pr_tab_id)) {
 
140
                        /* Should not happen, but just in case, we just don't
 
141
                         * remove the lock. We will probably end up with a deadlock
 
142
                         * somewhere.
 
143
                         */
 
144
                        xt_log_and_clear_exception_ns();
 
145
                }
 
146
                else {
 
147
#endif
 
148
                        for (int j=0; j<XT_ROW_LOCK_GROUP_COUNT; j++) {
 
149
                                if (plock->pr_group[j]) {
 
150
                                        /* Go through group j and compact. */
 
151
#ifndef XT_USE_TABLE_REF
 
152
                                        XTTableHPtr             tab = pot->ot_table;
 
153
#endif
 
154
                                        XTLockGroupPtr  group;
 
155
                                        XTLockItemPtr   copy;
 
156
                                        XTLockItemPtr   item;
 
157
                                        int                             new_count;
 
158
 
 
159
                                        group = &tab->tab_locks.rl_groups[j];
 
160
                                        xt_spinlock_lock(&group->lg_lock);
 
161
                                        copy = group->lg_list;
 
162
                                        item = group->lg_list;
 
163
                                        new_count = 0;
 
164
                                        for (size_t k=0; k<group->lg_list_in_use; k++) {
 
165
                                                if (item->li_thread_id != thd_id) {
 
166
                                                        if (copy != item) {
 
167
                                                                copy->li_row_id = item->li_row_id;
 
168
                                                                copy->li_count = item->li_count;
 
169
                                                                copy->li_thread_id = item->li_thread_id;
 
170
                                                        }
 
171
                                                        new_count++;
 
172
                                                        copy++;
 
173
                                                }
 
174
#ifdef XT_TRACE_LOCKS
 
175
                                                else {
 
176
                                                        if (item->li_count == XT_TEMP_LOCK_BYTES)
 
177
                                                                xt_ttracef(xt_get_self(), "remove group %d lock row_id=%d TEMP\n", j, (int) item->li_row_id);
 
178
                                                        else
 
179
                                                                xt_ttracef(xt_get_self(), "remove group %d locks row_id=%d (%d)\n", j, (int) item->li_row_id, (int) item->li_count);
 
180
                                                }
 
181
#endif
 
182
                                                item++;
 
183
                                        }
 
184
                                        group->lg_list_in_use = new_count;
 
185
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
186
                                        check_rowlock_group(group);
 
187
#endif
 
188
                                        if (group->lg_wait_queue)
 
189
                                                tab->tab_locks.rl_grant_locks(group, thread);
 
190
 
 
191
                                        xt_spinlock_unlock(&group->lg_lock);
 
192
                                        
 
193
                                        xt_wakeup_thread_list(thread);
 
194
                                }
 
195
                        }
 
196
#ifdef XT_USE_TABLE_REF
 
197
                        xt_heap_release_ns(plock->pr_table);
 
198
#else
 
199
                        xt_db_return_table_to_pool_ns(pot);
 
200
                }
 
201
#endif
 
202
                plock++;
 
203
        }
 
204
        bl_count = 0;
 
205
}
 
206
 
 
207
#ifdef DEBUG_LOCK_QUEUE
 
208
int *dummy_ptr = 0;
 
209
 
 
210
void XTRowLocks::rl_check(XTLockWaitPtr no_lw)
 
211
{
 
212
        XTLockGroupPtr  group;
 
213
        XTLockWaitPtr   lw, lw_prev;
 
214
 
 
215
        for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) {
 
216
                group = &rl_groups[i];
 
217
                xt_spinlock_lock(&group->lg_lock);
 
218
 
 
219
                lw = group->lg_wait_queue;
 
220
                lw_prev = NULL;
 
221
                while (lw) {
 
222
                        if (lw == no_lw)
 
223
                                *dummy_ptr = 1;
 
224
                        if (lw->lw_prev != lw_prev)
 
225
                                *dummy_ptr = 2;
 
226
                        lw_prev = lw;
 
227
                        lw = lw->lw_next;
 
228
                }
 
229
                xt_spinlock_unlock(&group->lg_lock);
 
230
        }
 
231
}
 
232
#endif
 
233
 
 
234
// Depending on platform 'thread->t_id' may not be used by THR_ARRAY_READ_LOCK().
 
235
xtBool XTRowLocks::rl_lock_row(XTLockGroupPtr group, XTLockWaitPtr lw, XTRowLockListPtr, int *result, XTThreadPtr thread __attribute__((unused)))
 
236
{
 
237
        XTLockItemPtr   item;
 
238
        size_t                  index;
 
239
        xtRowID                 row_id = lw->lw_row_id;
 
240
 
 
241
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
242
        check_rowlock_group(group);
 
243
#endif
 
244
        if (group->lg_list_size == group->lg_list_in_use) {
 
245
                if (!xt_realloc_ns((void **) &group->lg_list, (group->lg_list_size + 2) * sizeof(XTLockItemRec)))
 
246
                        return FAILED;
 
247
                group->lg_list_size += 2;
 
248
        }
 
249
        item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids);
 
250
        
 
251
        /* There's no item with this ID, but there could be an item with a range that covers this row */
 
252
        if (!item && group->lg_list_in_use) {
 
253
                if (index > 0) {
 
254
                        int count;
 
255
        
 
256
                        item = group->lg_list + index - 1;
 
257
 
 
258
                        count = item->li_count;
 
259
                        if (item->li_count == XT_TEMP_LOCK_BYTES)
 
260
                                count = 1;
 
261
 
 
262
                        if (row_id >= item->li_row_id + count * XT_ROW_LOCK_GROUP_COUNT)
 
263
                                item = NULL;
 
264
                }
 
265
        }
 
266
        
 
267
        if (item) {
 
268
                XTThreadPtr tmp_thr;
 
269
 
 
270
                /* Item already exists. */
 
271
                if (item->li_thread_id == lw->lw_thread->t_id) {
 
272
                        /* Already have a permanent lock: */
 
273
                        *result = XT_NO_LOCK;
 
274
                        lw->lw_curr_lock = XT_NO_LOCK;
 
275
                        return OK;
 
276
                }
 
277
                /* {REMOVE-LOCKS}
 
278
                 * This must be valid because a thread must remove
 
279
                 * the locks before it frees its st_xact_data structure,
 
280
                 * xt_thr_array entry must also be valid, because
 
281
                 * transaction must be ended before the thread is
 
282
                 * killed.
 
283
                 */
 
284
                *result = item->li_count == XT_TEMP_LOCK_BYTES ? XT_TEMP_LOCK : XT_PERM_LOCK;
 
285
                THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
 
286
                tmp_thr = xt_thr_array[item->li_thread_id].td_thread;
 
287
                THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
 
288
                lw->lw_xn_id = tmp_thr->st_xact_data->xd_start_xn_id;
 
289
                lw->lw_curr_lock = *result;
 
290
                return OK;
 
291
        }
 
292
 
 
293
        /* Add the lock: */
 
294
        XT_MEMMOVE(group->lg_list, &group->lg_list[index+1], 
 
295
                &group->lg_list[index], (group->lg_list_in_use - index) * sizeof(XTLockItemRec));
 
296
        group->lg_list[index].li_row_id = row_id;
 
297
        group->lg_list[index].li_count = XT_TEMP_LOCK_BYTES;
 
298
        group->lg_list[index].li_thread_id = lw->lw_thread->t_id;
 
299
        group->lg_list_in_use++;
 
300
 
 
301
#ifdef XT_TRACE_LOCKS
 
302
        xt_ttracef(ot->ot_thread, "set temp lock row=%d setby=%s\n", (int) row_id, xt_get_self()->t_name);
 
303
#endif
 
304
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
305
        check_rowlock_group(group);
 
306
#endif
 
307
        *result = XT_NO_LOCK;
 
308
        lw->lw_ot->ot_temp_row_lock = row_id;
 
309
        lw->lw_curr_lock = XT_NO_LOCK;
 
310
        return OK;
 
311
}
 
312
 
 
313
void XTRowLocks::rl_grant_locks(XTLockGroupPtr group, XTThreadPtr thread)
 
314
{
 
315
        XTLockWaitPtr   lw, lw_next, lw_prev;
 
316
        int                             result;
 
317
        xtThreadID              lw_thd_id;
 
318
 
 
319
        thread->st_thread_list_count = 0;
 
320
        lw = group->lg_wait_queue;
 
321
        while (lw) {
 
322
                lw_next = lw->lw_next;
 
323
                lw_prev = lw->lw_prev;
 
324
                lw_thd_id = lw->lw_thread->t_id;
 
325
                /* NOTE: after lw_curr_lock is changed, lw may no longer be referenced
 
326
                 * by this function!!!
 
327
                 */
 
328
                if (!rl_lock_row(group, lw, &lw->lw_thread->st_lock_list, &result, thread)) {
 
329
                        /* We transfer the error to the other thread! */
 
330
                        XTThreadPtr self = xt_get_self();
 
331
 
 
332
                        result = XT_LOCK_ERR;
 
333
                        memcpy(&lw->lw_thread->t_exception, &self->t_exception, sizeof(XTExceptionRec));
 
334
                        lw->lw_curr_lock = XT_LOCK_ERR;
 
335
                }
 
336
                if (result == XT_NO_LOCK || result == XT_LOCK_ERR) {
 
337
                        /* Remove from the wait queue: */
 
338
                        if (lw_next)
 
339
                                lw_next->lw_prev = lw_prev;
 
340
                        if (lw_prev)
 
341
                                lw_prev->lw_next = lw_next;
 
342
                        if (group->lg_wait_queue == lw)
 
343
                                group->lg_wait_queue = lw_next;
 
344
                        if (group->lg_wait_queue_end == lw)
 
345
                                group->lg_wait_queue_end = lw_prev;
 
346
                        if (result == XT_NO_LOCK) {
 
347
                                /* Add to the thread list: */
 
348
                                if (thread->st_thread_list_count == thread->st_thread_list_size) {
 
349
                                        if (!xt_realloc_ns((void **) &thread->st_thread_list, (thread->st_thread_list_size+1) * sizeof(xtThreadID))) {
 
350
                                                xt_wakeup_thread(lw_thd_id, thread);
 
351
                                                goto done;
 
352
                                        }
 
353
                                        thread->st_thread_list_size++;
 
354
                                }
 
355
                                thread->st_thread_list[thread->st_thread_list_count] = lw_thd_id;
 
356
                                thread->st_thread_list_count++;
 
357
                                done:;
 
358
                        }
 
359
                }
 
360
                lw = lw_next;
 
361
        }
 
362
}
 
363
 
 
364
void XTRowLocks::xt_cancel_temp_lock(XTLockWaitPtr lw)
 
365
{
 
366
        XTLockGroupPtr  group;
 
367
 
 
368
        group = &rl_groups[lw->lw_row_id % XT_ROW_LOCK_GROUP_COUNT];
 
369
        xt_spinlock_lock(&group->lg_lock);
 
370
        if (lw->lw_curr_lock == XT_TEMP_LOCK || lw->lw_curr_lock == XT_PERM_LOCK) {
 
371
                /* In case of XT_LOCK_ERR or XT_NO_LOCK, the lw structure will
 
372
                 * no longer be on the wait queue.
 
373
                 */
 
374
                XTLockWaitPtr   lw_next, lw_prev;
 
375
 
 
376
                lw_next = lw->lw_next;
 
377
                lw_prev = lw->lw_prev;
 
378
 
 
379
                /* Remove from the wait queue: */
 
380
                if (lw_next)
 
381
                        lw_next->lw_prev = lw_prev;
 
382
                if (lw_prev)
 
383
                        lw_prev->lw_next = lw_next;
 
384
                if (group->lg_wait_queue == lw)
 
385
                        group->lg_wait_queue = lw_next;
 
386
                if (group->lg_wait_queue_end == lw)
 
387
                        group->lg_wait_queue_end = lw_prev;
 
388
        }
 
389
        xt_spinlock_unlock(&group->lg_lock);
 
390
}
 
391
 
 
392
//#define QUEUE_ORDER_FIFO
 
393
 
 
394
/* Try to lock a row.
 
395
 * This function returns:
 
396
 * XT_NO_LOCK on success.
 
397
 * XT_TEMP_LOCK if there is a temporary lock on the row.
 
398
 * XT_PERM_LOCK if there is a permanent lock in the row.
 
399
 * XT_FAILED an error occured.
 
400
 *
 
401
 * If there is a lock on this row, the transaction ID of the
 
402
 * locker is also returned.
 
403
 *
 
404
 * The caller must wait if the row is locked. If the lock is
 
405
 * permanent, then the caller must wait for the transaction to
 
406
 * terminate. If the lock is temporary, then the caller must
 
407
 * wait for the transaction to signal that the lock has been
 
408
 * released.
 
409
 */
 
410
xtBool XTRowLocks::xt_set_temp_lock(XTOpenTablePtr ot, XTLockWaitPtr lw, XTRowLockListPtr lock_list)
 
411
{
 
412
        XTLockGroupPtr  group;
 
413
        int                             result;
 
414
 
 
415
        if (ot->ot_temp_row_lock) {
 
416
                /* Check if we don't already have this temp lock: */
 
417
                if (ot->ot_temp_row_lock == lw->lw_row_id) {
 
418
                        lw->lw_curr_lock = XT_NO_LOCK;
 
419
                        return OK;
 
420
                }
 
421
 
 
422
                xt_make_lock_permanent(ot, lock_list);
 
423
        }
 
424
 
 
425
        /* Add a temporary lock. */
 
426
        group = &rl_groups[lw->lw_row_id % XT_ROW_LOCK_GROUP_COUNT];
 
427
        xt_spinlock_lock(&group->lg_lock);
 
428
 
 
429
        if (!rl_lock_row(group, lw, lock_list, &result, ot->ot_thread)) {
 
430
                xt_spinlock_unlock(&group->lg_lock);
 
431
                return FAILED;
 
432
        }
 
433
 
 
434
        if (result != XT_NO_LOCK) {
 
435
                /* Add the thread to the end of the thread queue: */
 
436
#ifdef QUEUE_ORDER_FIFO
 
437
                if (group->lg_wait_queue_end) {
 
438
                        group->lg_wait_queue_end->lw_next = lw;
 
439
                        lw->lw_prev = group->lg_wait_queue_end;
 
440
                }
 
441
                else {
 
442
                        group->lg_wait_queue = lw;
 
443
                        lw->lw_prev = NULL;
 
444
                }
 
445
                lw->lw_next = NULL;
 
446
                group->lg_wait_queue_end = lw;
 
447
#else
 
448
                XTLockWaitPtr   pos = group->lg_wait_queue_end;
 
449
                xtXactID                xn_id = ot->ot_thread->st_xact_data->xd_start_xn_id;
 
450
                
 
451
                while (pos) {
 
452
                        if (pos->lw_thread->st_xact_data->xd_start_xn_id < xn_id)
 
453
                                break;
 
454
                        pos = pos->lw_prev;
 
455
                }
 
456
                if (pos) {
 
457
                        lw->lw_prev = pos;
 
458
                        lw->lw_next = pos->lw_next;
 
459
                        if (pos->lw_next)
 
460
                                pos->lw_next->lw_prev = lw;
 
461
                        else
 
462
                                group->lg_wait_queue_end = lw;
 
463
                        pos->lw_next = lw;
 
464
                }
 
465
                else {
 
466
                        /* Front of the queue: */
 
467
                        lw->lw_prev = NULL;
 
468
                        lw->lw_next = group->lg_wait_queue;
 
469
                        if (group->lg_wait_queue)
 
470
                                group->lg_wait_queue->lw_prev = lw;
 
471
                        else
 
472
                                group->lg_wait_queue_end = lw;
 
473
                        group->lg_wait_queue = lw;
 
474
                }
 
475
#endif
 
476
        }
 
477
 
 
478
        xt_spinlock_unlock(&group->lg_lock);
 
479
        return OK;
 
480
}
 
481
 
 
482
/*
 
483
 * Remove a temporary lock.
 
484
 * 
 
485
 * If updated is set to TRUE this means that the row was update.
 
486
 * This means that any thread waiting on the temporary lock will
 
487
 * also have to wait for the transaction to quit before
 
488
 * continuing.
 
489
 *
 
490
 * If the thread were to continue it would just hang again because
 
491
 * it will discover that the transaction has updated the row.
 
492
 *
 
493
 * So the 'updated' flag is an optimisation which prevents the
 
494
 * thread from making an unncessary retry.
 
495
 */
 
496
void XTRowLocks::xt_remove_temp_lock(XTOpenTablePtr ot, xtBool updated)
 
497
{
 
498
        xtRowID                 row_id;
 
499
        XTLockGroupPtr  group;
 
500
        XTLockItemPtr   item;
 
501
        size_t                  index;
 
502
        xtBool                  lock_granted = FALSE;
 
503
        xtThreadID              locking_thread_id = 0;
 
504
 
 
505
        if (!(row_id = ot->ot_temp_row_lock))
 
506
                return;
 
507
 
 
508
        group = &rl_groups[row_id % XT_ROW_LOCK_GROUP_COUNT];
 
509
        xt_spinlock_lock(&group->lg_lock);
 
510
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
511
        check_rowlock_group(group);
 
512
#endif
 
513
 
 
514
#ifdef XT_TRACE_LOCKS
 
515
        xt_ttracef(xt_get_self(), "remove temp lock %d\n", (int) row_id);
 
516
#endif
 
517
        item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids);
 
518
        if (item) {
 
519
                /* Item exists. */
 
520
                if (item->li_thread_id == ot->ot_thread->t_id &&
 
521
                        item->li_count == XT_TEMP_LOCK_BYTES) {
 
522
                        XTLockWaitPtr   lw;
 
523
 
 
524
                        /* First check if there is some thread waiting to take over this lock: */
 
525
                        lw = group->lg_wait_queue;
 
526
                        while (lw) {
 
527
                                if (lw->lw_row_id == row_id) {
 
528
                                        lock_granted = TRUE;
 
529
                                        break;
 
530
                                }
 
531
                                lw = lw->lw_next;
 
532
                        }
 
533
 
 
534
                        if (lock_granted) {
 
535
                                /* Grant the lock just released... */
 
536
                                XTLockWaitPtr   lw_next, lw_prev;
 
537
                                xtXactID                locking_xact_id;
 
538
 
 
539
                                /* Store this info, lw will soon be untouchable! */
 
540
                                lw_next = lw->lw_next;
 
541
                                lw_prev = lw->lw_prev;
 
542
                                locking_xact_id = lw->lw_thread->st_xact_data->xd_start_xn_id;
 
543
                                locking_thread_id = lw->lw_thread->t_id;
 
544
 
 
545
                                /* Lock has moved from one thread to the next.
 
546
                                 * change the thread holding this lock:
 
547
                                 */
 
548
                                item->li_thread_id = locking_thread_id;
 
549
 
 
550
                                /* Remove from the wait queue: */
 
551
                                if (lw_next)
 
552
                                        lw_next->lw_prev = lw_prev;
 
553
                                if (lw_prev)
 
554
                                        lw_prev->lw_next = lw_next;
 
555
                                if (group->lg_wait_queue == lw)
 
556
                                        group->lg_wait_queue = lw_next;
 
557
                                if (group->lg_wait_queue_end == lw)
 
558
                                        group->lg_wait_queue_end = lw_prev;
 
559
 
 
560
                                /* If the thread that release the lock updated the
 
561
                                 * row then we will have to wait for the transaction
 
562
                                 * to terminate:
 
563
                                 */
 
564
                                if (updated) {
 
565
                                        lw->lw_row_updated = TRUE;
 
566
                                        lw->lw_updating_xn_id = ot->ot_thread->st_xact_data->xd_start_xn_id;
 
567
                                }
 
568
 
 
569
                                /* The thread has the lock now: */
 
570
                                lw->lw_ot->ot_temp_row_lock = row_id;
 
571
                                lw->lw_curr_lock = XT_NO_LOCK;
 
572
 
 
573
                                /* Everyone after this that is waiting for the same lock is
 
574
                                 * now waiting for a different transaction:
 
575
                                 */
 
576
                                lw = lw_next;
 
577
                                while (lw) {
 
578
                                        if (lw->lw_row_id == row_id) {
 
579
                                                lw->lw_xn_id = locking_xact_id;
 
580
                                                lw->lw_curr_lock = XT_TEMP_LOCK;
 
581
                                        }
 
582
                                        lw = lw->lw_next;
 
583
                                }
 
584
                        }
 
585
                        else {
 
586
                                /* Remove the lock: */
 
587
                                XT_MEMMOVE(group->lg_list, &group->lg_list[index], 
 
588
                                        &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec));
 
589
                                group->lg_list_in_use--;
 
590
                        }
 
591
                }
 
592
        }
 
593
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
594
        check_rowlock_group(group);
 
595
#endif
 
596
        xt_spinlock_unlock(&group->lg_lock);
 
597
 
 
598
        ot->ot_temp_row_lock = 0;
 
599
        if (lock_granted)
 
600
                xt_wakeup_thread(locking_thread_id, ot->ot_thread);
 
601
}
 
602
 
 
603
xtBool XTRowLocks::xt_make_lock_permanent(XTOpenTablePtr ot, XTRowLockListPtr lock_list)
 
604
{
 
605
        xtRowID                 row_id;
 
606
        XTLockGroupPtr  group;
 
607
        XTLockItemPtr   item;
 
608
        size_t                  index;
 
609
 
 
610
        if (!(row_id = ot->ot_temp_row_lock))
 
611
                return OK;
 
612
 
 
613
#ifdef XT_TRACE_LOCKS
 
614
        xt_ttracef(xt_get_self(), "make lock perm %d\n", (int) ot->ot_temp_row_lock);
 
615
#endif
 
616
 
 
617
        /* Add to the lock list: */
 
618
        XTPermRowLockPtr locks = (XTPermRowLockPtr) lock_list->bl_data;
 
619
        for (unsigned i=0; i<lock_list->bl_count; i++) {
 
620
#ifdef XT_USE_TABLE_REF
 
621
                if (locks->pr_table == ot->ot_table) {
 
622
#else
 
623
                if (locks->pr_tab_id == ot->ot_table->tab_id) {
 
624
#endif
 
625
                        locks->pr_group[row_id % XT_ROW_LOCK_GROUP_COUNT] = 1;
 
626
                        goto done;
 
627
                }
 
628
                locks++;
 
629
        }
 
630
 
 
631
        /* Add new to lock list: */
 
632
        {
 
633
                XTPermRowLockRec perm_lock;
 
634
                
 
635
#ifdef XT_USE_TABLE_REF
 
636
                perm_lock.pr_table = ot->ot_table;
 
637
                xt_heap_reference_ns(perm_lock.pr_table);
 
638
#else
 
639
                perm_lock.pr_tab_id = ot->ot_table->tab_id;
 
640
#endif
 
641
                memset(perm_lock.pr_group, 0, XT_ROW_LOCK_GROUP_COUNT);
 
642
                perm_lock.pr_group[row_id % XT_ROW_LOCK_GROUP_COUNT] = 1;
 
643
                if (!xt_bl_append(NULL, lock_list, &perm_lock)) {
 
644
                        xt_remove_temp_lock(ot, FALSE);
 
645
                        return FAILED;
 
646
                }
 
647
        }
 
648
 
 
649
        done:
 
650
        group = &rl_groups[row_id % XT_ROW_LOCK_GROUP_COUNT];
 
651
        xt_spinlock_lock(&group->lg_lock);
 
652
 
 
653
        item = (XTLockItemPtr) xt_bsearch(NULL, &row_id, group->lg_list, group->lg_list_in_use, sizeof(XTLockItemRec), &index, NULL, xlock_cmp_row_ids);
 
654
        ASSERT_NS(item);
 
655
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
656
        check_rowlock_group(group);
 
657
#endif
 
658
        if (item) {
 
659
                /* Lock exists (it should!). */
 
660
                if (item->li_thread_id == ot->ot_thread->t_id &&
 
661
                        item->li_count == XT_TEMP_LOCK_BYTES) {
 
662
                        if (index > 0 &&
 
663
                                group->lg_list[index-1].li_thread_id == ot->ot_thread->t_id &&
 
664
                                group->lg_list[index-1].li_count < XT_TEMP_LOCK_BYTES-2 &&
 
665
                                group->lg_list[index-1].li_row_id == row_id - (XT_ROW_LOCK_GROUP_COUNT * group->lg_list[index-1].li_count)) {
 
666
                                group->lg_list[index-1].li_count++;
 
667
                                /* Combine with the left: */
 
668
                                if (index + 1 < group->lg_list_in_use &&
 
669
                                        group->lg_list[index+1].li_thread_id == ot->ot_thread->t_id &&
 
670
                                        group->lg_list[index+1].li_count != XT_TEMP_LOCK_BYTES &&
 
671
                                        group->lg_list[index+1].li_row_id == row_id + XT_ROW_LOCK_GROUP_COUNT) {
 
672
                                        /* And combine with the right */
 
673
                                        u_int left = group->lg_list[index-1].li_count + group->lg_list[index+1].li_count;
 
674
                                        u_int right;
 
675
 
 
676
                                        if (left > XT_TEMP_LOCK_BYTES-1) {
 
677
                                                right = left - (XT_TEMP_LOCK_BYTES-1);
 
678
                                                left = XT_TEMP_LOCK_BYTES-1;
 
679
                                        }
 
680
                                        else
 
681
                                                right = 0;
 
682
 
 
683
                                        group->lg_list[index-1].li_count = left;
 
684
                                        if (right) {
 
685
                                                /* There is something left over on the right: */
 
686
                                                group->lg_list[index+1].li_count = right;
 
687
                                                group->lg_list[index+1].li_row_id = group->lg_list[index-1].li_row_id + left * XT_ROW_LOCK_GROUP_COUNT;
 
688
                                                XT_MEMMOVE(group->lg_list, &group->lg_list[index], 
 
689
                                                        &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec));
 
690
                                                group->lg_list_in_use--;
 
691
                                        }
 
692
                                        else {
 
693
                                                XT_MEMMOVE(group->lg_list, &group->lg_list[index], 
 
694
                                                        &group->lg_list[index+2], (group->lg_list_in_use - index - 2) * sizeof(XTLockItemRec));
 
695
                                                group->lg_list_in_use -= 2;
 
696
                                        }
 
697
                                }
 
698
                                else {
 
699
                                        XT_MEMMOVE(group->lg_list, &group->lg_list[index], 
 
700
                                                &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec));
 
701
                                        group->lg_list_in_use--;
 
702
                                }
 
703
                        }
 
704
                        else if (index + 1 < group->lg_list_in_use &&
 
705
                                        group->lg_list[index+1].li_thread_id == ot->ot_thread->t_id &&
 
706
                                        group->lg_list[index+1].li_count < XT_TEMP_LOCK_BYTES-2 &&
 
707
                                        group->lg_list[index+1].li_row_id == row_id + XT_ROW_LOCK_GROUP_COUNT) {
 
708
                                /* Combine with the right: */
 
709
                                group->lg_list[index+1].li_count++;
 
710
                                group->lg_list[index+1].li_row_id = row_id;
 
711
                                XT_MEMMOVE(group->lg_list, &group->lg_list[index], 
 
712
                                        &group->lg_list[index+1], (group->lg_list_in_use - index - 1) * sizeof(XTLockItemRec));
 
713
                                group->lg_list_in_use--;
 
714
                        }
 
715
                        else
 
716
                                group->lg_list[index].li_count = 1;
 
717
                }
 
718
        }
 
719
#ifdef CHECK_ROWLOCK_GROUP_CONSISTENCY
 
720
        check_rowlock_group(group);
 
721
#endif
 
722
        xt_spinlock_unlock(&group->lg_lock);
 
723
 
 
724
        ot->ot_temp_row_lock = 0;
 
725
        return OK;
 
726
}
 
727
 
 
728
xtBool xt_init_row_locks(XTRowLocksPtr rl)
 
729
{
 
730
        for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) {
 
731
                xt_spinlock_init_with_autoname(NULL, &rl->rl_groups[i].lg_lock);
 
732
                rl->rl_groups[i].lg_wait_queue = NULL;
 
733
                rl->rl_groups[i].lg_list_size = 0;
 
734
                rl->rl_groups[i].lg_list_in_use = 0;
 
735
                rl->rl_groups[i].lg_list = NULL;
 
736
        }
 
737
        return OK;
 
738
}
 
739
 
 
740
void xt_exit_row_locks(XTRowLocksPtr rl)
 
741
{
 
742
        for (int i=0; i<XT_ROW_LOCK_GROUP_COUNT; i++) {
 
743
                xt_spinlock_free(NULL, &rl->rl_groups[i].lg_lock);
 
744
                rl->rl_groups[i].lg_wait_queue = NULL;
 
745
                rl->rl_groups[i].lg_list_size = 0;
 
746
                rl->rl_groups[i].lg_list_in_use = 0;
 
747
                if (rl->rl_groups[i].lg_list) {
 
748
                        xt_free_ns(rl->rl_groups[i].lg_list);
 
749
                        rl->rl_groups[i].lg_list = NULL;
 
750
                }
 
751
        }
 
752
}
 
753
 
 
754
/*
 
755
 * -----------------------------------------------------------------------
 
756
 * ROW LOCKS, HASH BASED
 
757
 */
 
758
#else // XT_USE_LIST_BASED_ROW_LOCKS
 
759
 
 
760
void XTRowLockList::old_xt_remove_all_locks(struct XTDatabase *db, xtThreadID thd_id)
 
761
{
 
762
#ifdef XT_TRACE_LOCKS
 
763
        xt_ttracef(xt_get_self(), "remove all locks\n");
 
764
#endif
 
765
        if (!bl_count)
 
766
                return;
 
767
 
 
768
        int                                     pgroup;
 
769
        xtTableID                       ptab_id;
 
770
        XTPermRowLockPtr        plock;
 
771
        XTOpenTablePtr          pot = NULL;
 
772
 
 
773
        plock = (XTPermRowLockPtr) &bl_data[bl_count * bl_item_size];
 
774
        for (u_int i=0; i<bl_count; i++) {
 
775
                plock--;
 
776
                pgroup = plock->pr_group;
 
777
                ptab_id = plock->pr_tab_id;
 
778
                if (pot) {
 
779
                        if (pot->ot_table->tab_id == ptab_id)
 
780
                                goto remove_lock;
 
781
                        xt_db_return_table_to_pool_ns(pot);
 
782
                        pot = NULL;
 
783
                }
 
784
 
 
785
                if (!xt_db_open_pool_table_ns(&pot, db, ptab_id)) {
 
786
                        /* Should not happen, but just in case, we just don't
 
787
                         * remove the lock. We will probably end up with a deadlock
 
788
                         * somewhere.
 
789
                         */
 
790
                        xt_log_and_clear_exception_ns();
 
791
                        goto skip_remove_lock;
 
792
                }
 
793
                if (!pot)
 
794
                        /* Can happen of the table has been dropped: */
 
795
                        goto skip_remove_lock;
 
796
 
 
797
                remove_lock:
 
798
#ifdef XT_TRACE_LOCKS
 
799
                xt_ttracef(xt_get_self(), "remove lock group=%d\n", pgroup);
 
800
#endif
 
801
                pot->ot_table->tab_locks.tab_row_locks[pgroup] = NULL;
 
802
                pot->ot_table->tab_locks.tab_lock_perm[pgroup] = 0;
 
803
                skip_remove_lock:;
 
804
        }
 
805
        bl_count = 0;
 
806
 
 
807
        if (pot)
 
808
                xt_db_return_table_to_pool_ns(pot);
 
809
}
 
810
 
 
811
/* Try to lock a row.
 
812
 * This function returns:
 
813
 * XT_NO_LOCK on success.
 
814
 * XT_TEMP_LOCK if there is a temporary lock on the row.
 
815
 * XT_PERM_LOCK if there is a permanent lock in the row.
 
816
 *
 
817
 * If there is a lock on this row, the transaction ID of the
 
818
 * locker is also returned.
 
819
 *
 
820
 * The caller must wait if the row is locked. If the lock is
 
821
 * permanent, then the caller must wait for the transaction to
 
822
 * terminate. If the lock is temporary, then the caller must
 
823
 * wait for the transaction to signal that the lock has been
 
824
 * released.
 
825
 */
 
826
int XTRowLocks::old_xt_set_temp_lock(XTOpenTablePtr ot, xtRowID row, xtXactID *xn_id, XTRowLockListPtr lock_list)
 
827
{
 
828
        int                             group;
 
829
        XTXactDataPtr   xact, my_xact;
 
830
 
 
831
        if (ot->ot_temp_row_lock) {
 
832
                /* Check if we don't already have this temp lock: */
 
833
                if (ot->ot_temp_row_lock == row) {
 
834
                        gl->lw_curr_lock = XT_NO_LOCK;
 
835
                        return XT_NO_LOCK;
 
836
                }
 
837
 
 
838
                xt_make_lock_permanent(ot, lock_list);
 
839
        }
 
840
 
 
841
        my_xact = ot->ot_thread->st_xact_data;
 
842
        group = row % XT_ROW_LOCK_COUNT;
 
843
        if ((xact = tab_row_locks[group])) {
 
844
                if (xact == my_xact)
 
845
                        return XT_NO_LOCK;
 
846
                *xn_id = xact->xd_start_xn_id;
 
847
                return tab_lock_perm[group] ? XT_PERM_LOCK : XT_TEMP_LOCK;
 
848
        }
 
849
 
 
850
        tab_row_locks[row % XT_ROW_LOCK_COUNT] = my_xact;
 
851
 
 
852
#ifdef XT_TRACE_LOCKS
 
853
        xt_ttracef(xt_get_self(), "set temp lock %d group=%d for %s\n", (int) row, (int) row % XT_ROW_LOCK_COUNT, ot->ot_thread->t_name);
 
854
#endif
 
855
        ot->ot_temp_row_lock = row;
 
856
        return XT_NO_LOCK;
 
857
}
 
858
 
 
859
/* Just check if there is a lock on the row.
 
860
 * This function returns:
 
861
 * XT_NO_LOCK if there is no lock.
 
862
 * XT_TEMP_LOCK if there is a temporary lock on the row.
 
863
 * XT_PERM_LOCK if a lock is a permanent lock in the row.
 
864
 */
 
865
int XTRowLocks::old_xt_is_locked(struct XTOpenTable *ot, xtRowID row, xtXactID *xn_id)
 
866
{
 
867
        int                             group;
 
868
        XTXactDataPtr   xact;
 
869
 
 
870
        group = row % XT_ROW_LOCK_COUNT;
 
871
        if ((xact = tab_row_locks[group])) {
 
872
                if (xact == ot->ot_thread->st_xact_data)
 
873
                        return XT_NO_LOCK;
 
874
                *xn_id = xact->xd_start_xn_id;
 
875
                if (tab_lock_perm[group])
 
876
                        return XT_PERM_LOCK;
 
877
                return XT_TEMP_LOCK;
 
878
        }
 
879
        return XT_NO_LOCK;
 
880
}
 
881
 
 
882
void XTRowLocks::old_xt_remove_temp_lock(XTOpenTablePtr ot)
 
883
{
 
884
        int                             group;
 
885
        XTXactDataPtr   xact, my_xact;
 
886
 
 
887
        if (!ot->ot_temp_row_lock)
 
888
                return;
 
889
 
 
890
        my_xact = ot->ot_thread->st_xact_data;
 
891
        group = ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT;
 
892
#ifdef XT_TRACE_LOCKS
 
893
        xt_ttracef(xt_get_self(), "remove temp lock %d group=%d\n", (int) ot->ot_temp_row_lock, (int) ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT);
 
894
#endif
 
895
        ot->ot_temp_row_lock = 0;
 
896
        if ((xact = tab_row_locks[group])) {
 
897
                if (xact == my_xact)
 
898
                        tab_row_locks[group] = NULL;
 
899
        }
 
900
 
 
901
        if (ot->ot_table->tab_db->db_xn_wait_count)
 
902
                xt_xn_wakeup_transactions(ot->ot_table->tab_db, ot->ot_thread);
 
903
}
 
904
 
 
905
xtBool XTRowLocks::old_xt_make_lock_permanent(XTOpenTablePtr ot, XTRowLockListPtr lock_list)
 
906
{
 
907
        int group;
 
908
 
 
909
        if (!ot->ot_temp_row_lock)
 
910
                return OK;
 
911
 
 
912
#ifdef XT_TRACE_LOCKS
 
913
        xt_ttracef(xt_get_self(), "make lock perm %d group=%d\n", (int) ot->ot_temp_row_lock, (int) ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT);
 
914
#endif
 
915
        /* Check if the lock is already permanent: */
 
916
        group = ot->ot_temp_row_lock % XT_ROW_LOCK_COUNT;
 
917
        if (!tab_lock_perm[group]) {
 
918
                XTPermRowLockRec plock;
 
919
 
 
920
                plock.pr_tab_id = ot->ot_table->tab_id;
 
921
                plock.pr_group = group;
 
922
                if (!xt_bl_append(NULL, lock_list, &plock)) {
 
923
                        xt_remove_temp_lock(ot);
 
924
                        return FAILED;
 
925
                }
 
926
                tab_lock_perm[group] = 1;
 
927
        }
 
928
 
 
929
        ot->ot_temp_row_lock = 0;
 
930
        return OK;
 
931
}
 
932
 
 
933
/* Release this lock, and all locks gained after this lock
 
934
 * on this table.
 
935
 *
 
936
 * The locks are only released temporarily. The will be regained
 
937
 * below using regain locks.
 
938
 *
 
939
 * Returns:
 
940
 * XT_NO_LOCK if no lock is released.
 
941
 * XT_PERM_LOCK if a lock is released.
 
942
 *
 
943
 * Note that only permanent locks can be released in this way.
 
944
 * So if the thread has a temporary lock, it will first be made
 
945
 * permanent.
 
946
 *
 
947
 * {RELEASING-LOCKS}
 
948
 * The idea of the releasing locks comes from the fact that each
 
949
 * lock, locks a group of records.
 
950
 * So if T1 has a lock (e.g. when doing SELECT FOR UPDATE),
 
951
 * and then encounters an updated record x
 
952
 * from T2, and it must wait for T2, it firsts releases the
 
953
 * lock, just in case T2 tries to gain a lock on another
 
954
 * record y in the same group, which will cause it to
 
955
 * wait on T1.
 
956
 *
 
957
 * However, there are several problems with releasing
 
958
 * locks.
 
959
 * - It can cause a "live-lock", where another transation
 
960
 * keeps getting in before.
 
961
 * - It may not solve the problem in all cases because
 
962
 * the SELECT FOR UPDATE has locked other record groups
 
963
 * before it encountered record x.
 
964
 * - Further problems occur when locks are granted by
 
965
 * callback:
 
966
 * T1 waits for T2, because it has a lock on record x
 
967
 * T2 releases the lock because it must wait for T3
 
968
 * T1 is granted the lock (but does not know about this yet)
 
969
 * T2 tries to regain lock (after T3 quits) and
 
970
 * must wait for T1 - DEADLOCK
 
971
 *
 
972
 * In general, it does not make sense to release locks
 
973
 * when it can be granted again by a callback.
 
974
 *
 
975
 * TODO: 2 possible solutions:
 
976
 * - Do not lock groups, lock rows.
 
977
 *   UPDATE INTENSION ROW LOCK
 
978
 * - Use multiple lock types:
 
979
 *   UPDATE INTENSION LOCK (required first)
 
980
 *   SHARED UPDATE LOCK (used by INSERT or DELETE)
 
981
 *   EXCLUSIVE UPDATE LOCK (used by SELECT FOR UPDATE)
 
982
 *
 
983
 * Temporary solution. Do not release any locks.
 
984
int XTRowLocks::xt_release_locks(struct XTOpenTable *ot, xtRowID row, XTRowLockListPtr lock_list)
 
985
 */ 
 
986
 
 
987
/*
 
988
 * Regain a lock previously held. This function regains locks
 
989
 * released by xt_release_locks().
 
990
 *
 
991
 * It will return lock_type and xn_id if the row is locked, and therefore
 
992
 * regain cannot continue. In this case, the caller must wait.
 
993
 * It returns XT_NO_LOCK if there are no more locks to be regained.
 
994
 *
 
995
 * Locks are always regained in the order in which they were originally
 
996
 * taken.
 
997
xtBool XTRowLocks::xt_regain_locks(struct XTOpenTable *ot, int *lock_type, xtXactID *xn_id, XTRowLockListPtr lock_list)
 
998
 */
 
999
 
 
1000
xtBool old_xt_init_row_locks(XTRowLocksPtr rl)
 
1001
{
 
1002
        memset(rl->tab_lock_perm, 0, XT_ROW_LOCK_COUNT);
 
1003
        memset(rl->tab_row_locks, 0, XT_ROW_LOCK_COUNT * sizeof(XTXactDataPtr));
 
1004
        return OK;
 
1005
}
 
1006
 
 
1007
void old_xt_exit_row_locks(XTRowLocksPtr XT_UNUSED(rl))
 
1008
{
 
1009
}
 
1010
 
 
1011
#endif // XT_USE_LIST_BASED_ROW_LOCKS
 
1012
 
 
1013
xtPublic xtBool xt_init_row_lock_list(XTRowLockListPtr lock_list)
 
1014
{
 
1015
        lock_list->bl_item_size = sizeof(XTPermRowLockRec);
 
1016
        lock_list->bl_size = 0;
 
1017
        lock_list->bl_count = 0;
 
1018
        lock_list->bl_data = NULL;
 
1019
        return OK;
 
1020
}
 
1021
 
 
1022
xtPublic void xt_exit_row_lock_list(XTRowLockListPtr lock_list)
 
1023
{
 
1024
        xt_bl_set_size(NULL, lock_list, 0);
 
1025
}
 
1026
 
 
1027
/*
 
1028
 * -----------------------------------------------------------------------
 
1029
 * SPIN LOCK
 
1030
 */
 
1031
 
 
1032
#ifdef XT_THREAD_LOCK_INFO
 
1033
xtPublic void xt_spinlock_init(XTThreadPtr self, XTSpinLockPtr spl, const char *n)
 
1034
#else
 
1035
xtPublic void xt_spinlock_init(XTThreadPtr self, XTSpinLockPtr spl)
 
1036
#endif
 
1037
{
 
1038
        (void) self;
 
1039
        spl->spl_lock = 0;
 
1040
#ifdef XT_NO_ATOMICS
 
1041
        xt_init_mutex_with_autoname(self, &spl->spl_mutex);
 
1042
#endif
 
1043
#ifdef DEBUG
 
1044
        spl->spl_locker = 0;
 
1045
#endif
 
1046
#ifdef XT_THREAD_LOCK_INFO
 
1047
        spl->spl_name = n;
 
1048
        xt_thread_lock_info_init(&spl->spl_lock_info, spl);
 
1049
#endif
 
1050
}
 
1051
 
 
1052
xtPublic void xt_spinlock_free(XTThreadPtr XT_UNUSED(self), XTSpinLockPtr spl)
 
1053
{
 
1054
        (void) spl;
 
1055
#ifdef XT_NO_ATOMICS
 
1056
        xt_free_mutex(&spl->spl_mutex);
 
1057
#endif
 
1058
#ifdef XT_THREAD_LOCK_INFO
 
1059
        xt_thread_lock_info_free(&spl->spl_lock_info);
 
1060
#endif
 
1061
}
 
1062
 
 
1063
xtPublic xtBool xt_spinlock_spin(XTSpinLockPtr spl)
 
1064
{
 
1065
        volatile xtWord4        *lck = &spl->spl_lock;
 
1066
 
 
1067
        for (;;) {
 
1068
                for (int i=0; i<10; i++) {
 
1069
                        /* Check the lock variable: */
 
1070
                        if (!*lck) {
 
1071
                                /* Try to get the lock: */
 
1072
                                if (!xt_spinlock_set(spl))
 
1073
                                        goto done_ok;
 
1074
                        }
 
1075
                }
 
1076
 
 
1077
                /* Go to "sleep" */
 
1078
                xt_critical_wait();
 
1079
        }
 
1080
 
 
1081
        done_ok:
 
1082
        return OK;
 
1083
}
 
1084
 
 
1085
#ifdef DEBUG
 
1086
xtPublic void xt_spinlock_set_thread(XTSpinLockPtr spl)
 
1087
{
 
1088
        spl->spl_locker = xt_get_self();
 
1089
}
 
1090
#endif
 
1091
 
 
1092
/*
 
1093
 * -----------------------------------------------------------------------
 
1094
 * READ/WRITE SPIN LOCK
 
1095
 *
 
1096
 * An extremely genius very fast read/write lock based on atomics!
 
1097
 */
 
1098
 
 
1099
#ifdef XT_THREAD_LOCK_INFO
 
1100
xtPublic void xt_spinxslock_init(struct XTThread *XT_UNUSED(self), XTSpinXSLockPtr sxs, const char *name)
 
1101
#else
 
1102
xtPublic void xt_spinxslock_init(struct XTThread *XT_UNUSED(self), XTSpinXSLockPtr sxs)
 
1103
#endif
 
1104
{
 
1105
        sxs->sxs_xlocked = 0;
 
1106
        sxs->sxs_rlock_count = 0;
 
1107
        sxs->sxs_wait_count = 0;
 
1108
#ifdef DEBUG
 
1109
        sxs->sxs_locker = 0;
 
1110
#endif
 
1111
#ifdef XT_THREAD_LOCK_INFO
 
1112
        sxs->sxs_name = name;
 
1113
        xt_thread_lock_info_init(&sxs->sxs_lock_info, sxs);
 
1114
#endif
 
1115
}
 
1116
 
 
1117
xtPublic void xt_spinxslock_free(struct XTThread *XT_UNUSED(self), XTSpinXSLockPtr sxs)
 
1118
{
 
1119
#ifdef XT_THREAD_LOCK_INFO
 
1120
        xt_thread_lock_info_free(&sxs->sxs_lock_info);
 
1121
#else
 
1122
        (void) sxs;
 
1123
#endif
 
1124
}
 
1125
 
 
1126
xtPublic xtBool xt_spinxslock_xlock(XTSpinXSLockPtr sxs, xtBool try_lock, xtThreadID XT_NDEBUG_UNUSED(thd_id))
 
1127
{
 
1128
        register xtWord2 set;
 
1129
 
 
1130
        /* Wait for exclusive locker: */
 
1131
        for (;;) {
 
1132
                set = xt_atomic_tas2(&sxs->sxs_xlocked, 1);
 
1133
                if (!set)
 
1134
                        break;
 
1135
                if (try_lock)
 
1136
                        return FALSE;
 
1137
                xt_yield();
 
1138
        }
 
1139
 
 
1140
#ifdef DEBUG
 
1141
        sxs->sxs_locker = thd_id;
 
1142
#endif
 
1143
 
 
1144
        /* Wait for all the readers to wait! */
 
1145
        while (sxs->sxs_wait_count < sxs->sxs_rlock_count) {
 
1146
                sxs->sxs_xwaiter = 1;
 
1147
                xt_yield(); //*
 
1148
                /* This should not be required, because there is only one thread
 
1149
                 * accessing this value. However, the lock fails if this
 
1150
                 * is not done with an atomic op.
 
1151
                 *
 
1152
                 * This is because threads on other processors have the
 
1153
                 * value in processor cache. So they do not
 
1154
                 * notice that the value has been set to zero.
 
1155
                 * They think it is still 1 and march through
 
1156
                 * the barrier (sxs->sxs_xwaiter < sxs->sxs_xlocked) below.
 
1157
                 *
 
1158
                 * In the meantime, this X locker has gone on thinking
 
1159
                 * all is OK.
 
1160
                 */
 
1161
                xt_atomic_tas2(&sxs->sxs_xwaiter, 0);
 
1162
        }
 
1163
 
 
1164
#ifdef XT_THREAD_LOCK_INFO
 
1165
        xt_thread_lock_info_add_owner(&sxs->sxs_lock_info);
 
1166
#endif
 
1167
        return OK;
 
1168
}
 
1169
 
 
1170
xtPublic xtBool xt_spinxslock_slock(XTSpinXSLockPtr sxs)
 
1171
{
 
1172
        xt_atomic_inc2(&sxs->sxs_rlock_count);
 
1173
 
 
1174
        /* Wait as long as the locker is not waiting: */
 
1175
        while (sxs->sxs_xwaiter < sxs->sxs_xlocked) {
 
1176
                xt_atomic_inc2(&sxs->sxs_wait_count);
 
1177
                while (sxs->sxs_xwaiter < sxs->sxs_xlocked) {
 
1178
                        xt_yield();
 
1179
                }
 
1180
                xt_atomic_dec2(&sxs->sxs_wait_count);
 
1181
        }
 
1182
 
 
1183
#ifdef XT_THREAD_LOCK_INFO
 
1184
        xt_thread_lock_info_add_owner(&sxs->sxs_lock_info);
 
1185
#endif
 
1186
        return OK;
 
1187
}
 
1188
 
 
1189
xtPublic xtBool xt_spinxslock_unlock(XTSpinXSLockPtr sxs, xtBool xlocked)
 
1190
{
 
1191
        if (xlocked) {
 
1192
#ifdef DEBUG
 
1193
                ASSERT_NS(sxs->sxs_locker && sxs->sxs_xlocked);
 
1194
                sxs->sxs_locker = 0;
 
1195
#endif
 
1196
                sxs->sxs_xlocked = 0;
 
1197
        }
 
1198
        else {
 
1199
#ifdef DEBUG
 
1200
                ASSERT_NS(sxs->sxs_rlock_count > 0);
 
1201
#endif
 
1202
                xt_atomic_dec2(&sxs->sxs_rlock_count);
 
1203
        }
 
1204
 
 
1205
#ifdef XT_THREAD_LOCK_INFO
 
1206
        xt_thread_lock_info_release_owner(&sxs->sxs_lock_info);
 
1207
#endif
 
1208
        return OK;
 
1209
}
 
1210
 
 
1211
/*
 
1212
 * -----------------------------------------------------------------------
 
1213
 * FAST READ/WRITE LOCK (BASED ON FAST MUTEX)
 
1214
 */
 
1215
 
 
1216
#ifdef XT_THREAD_LOCK_INFO
 
1217
xtPublic void xt_xsmutex_init(struct XTThread *self, XTMutexXSLockPtr xsm, const char *name)
 
1218
#else
 
1219
xtPublic void xt_xsmutex_init(struct XTThread *self, XTMutexXSLockPtr xsm)
 
1220
#endif
 
1221
{
 
1222
        xt_init_mutex_with_autoname(self, &xsm->xsm_lock);
 
1223
        xt_init_cond(self, &xsm->xsm_xcond);
 
1224
        xt_init_cond(self, &xsm->xsm_rcond);
 
1225
        xsm->xsm_xlocker = 0;
 
1226
        xsm->xsm_rlock_count = 0;
 
1227
        xsm->xsm_rwait_count = 0;
 
1228
#ifdef DEBUG
 
1229
        xsm->xsm_locker = 0;
 
1230
#endif
 
1231
#ifdef XT_THREAD_LOCK_INFO
 
1232
        xsm->xsm_name = name;
 
1233
        xt_thread_lock_info_init(&xsm->xsm_lock_info, xsm);
 
1234
#endif
 
1235
}
 
1236
 
 
1237
xtPublic void xt_xsmutex_free(struct XTThread *XT_UNUSED(self), XTMutexXSLockPtr xsm)
 
1238
{
 
1239
        xt_free_mutex(&xsm->xsm_lock);
 
1240
        xt_free_cond(&xsm->xsm_xcond);
 
1241
        xt_free_cond(&xsm->xsm_rcond);
 
1242
#ifdef XT_THREAD_LOCK_INFO
 
1243
        xt_thread_lock_info_free(&xsm->xsm_lock_info);
 
1244
#endif
 
1245
}
 
1246
 
 
1247
xtPublic xtBool xt_xsmutex_xlock(XTMutexXSLockPtr xsm, xtThreadID thd_id)
 
1248
{
 
1249
        xt_lock_mutex_ns(&xsm->xsm_lock);
 
1250
 
 
1251
        xt_atomic_inc2(&xsm->xsm_xwait_count);
 
1252
 
 
1253
        /* Wait for exclusive locker: */
 
1254
        while (xsm->xsm_xlocker) {
 
1255
                if (!xt_timed_wait_cond_ns(&xsm->xsm_xcond, &xsm->xsm_lock, 10000)) {
 
1256
                        xsm->xsm_xwait_count--;
 
1257
                        xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1258
                        return FAILED;
 
1259
                }
 
1260
        }
 
1261
 
 
1262
        /* GOTCHA: You would think this is not necessary...
 
1263
         * But is does not always work, if a normal insert is used.
 
1264
         * The reason is, I guess, on MMP the assignment is not
 
1265
         * always immediately visible to other processors, because they
 
1266
         * have old versions of this variable in there cache.
 
1267
         *
 
1268
         * But this is required, because the locking mechanism is based
 
1269
         * on:
 
1270
         * Locker: sets xlocker, tests rlock_count
 
1271
         * Reader: incs rlock_count, tests xlocker
 
1272
         *
 
1273
         * The test, in both cases, may not read stale values.
 
1274
         * volatile does not help, because this just turns compiler
 
1275
         * optimisations off.
 
1276
         */
 
1277
        xt_atomic_set4(&xsm->xsm_xlocker, thd_id);
 
1278
 
 
1279
        /* Wait for all the reader to wait! */
 
1280
        while (xsm->xsm_rwait_count < xsm->xsm_rlock_count) {
 
1281
                /* {RACE-WR_MUTEX} Here as well: */
 
1282
                if (!xt_timed_wait_cond_ns(&xsm->xsm_xcond, &xsm->xsm_lock, 100)) {
 
1283
                        xsm->xsm_xwait_count--;
 
1284
                        xsm->xsm_xlocker = 0;
 
1285
                        xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1286
                        return FAILED;
 
1287
                }
 
1288
        }
 
1289
 
 
1290
        xsm->xsm_xwait_count--;
 
1291
#ifdef XT_THREAD_LOCK_INFO
 
1292
        xt_thread_lock_info_add_owner(&xsm->xsm_lock_info);
 
1293
#endif
 
1294
        return OK;
 
1295
}
 
1296
 
 
1297
xtPublic xtBool xt_xsmutex_slock(XTMutexXSLockPtr xsm, xtThreadID XT_UNUSED(thd_id))
 
1298
{
 
1299
        xt_atomic_inc2(&xsm->xsm_rlock_count);
 
1300
 
 
1301
        /* Check if there could be an X locker: */
 
1302
        if (xsm->xsm_xlocker) {
 
1303
                /* I am waiting... */
 
1304
                xt_lock_mutex_ns(&xsm->xsm_lock);
 
1305
                xsm->xsm_rwait_count++;
 
1306
                /* Wake up the xlocker: */
 
1307
                if (xsm->xsm_xlocker && xsm->xsm_rwait_count == xsm->xsm_rlock_count) {
 
1308
                        if (!xt_broadcast_cond_ns(&xsm->xsm_xcond)) {
 
1309
                                xsm->xsm_rwait_count--;
 
1310
                                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1311
                                return FAILED;
 
1312
                        }
 
1313
                }
 
1314
                while (xsm->xsm_xlocker) {
 
1315
                        if (!xt_timed_wait_cond_ns(&xsm->xsm_rcond, &xsm->xsm_lock, 10000)) {
 
1316
                                xsm->xsm_rwait_count--;
 
1317
                                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1318
                                return FAILED;
 
1319
                        }
 
1320
                }
 
1321
                xsm->xsm_rwait_count--;
 
1322
                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1323
        }
 
1324
 
 
1325
#ifdef XT_THREAD_LOCK_INFO
 
1326
        xt_thread_lock_info_add_owner(&xsm->xsm_lock_info);
 
1327
#endif
 
1328
        return OK;
 
1329
}
 
1330
 
 
1331
xtPublic xtBool xt_xsmutex_unlock(XTMutexXSLockPtr xsm, xtThreadID thd_id)
 
1332
{
 
1333
        if (xsm->xsm_xlocker == thd_id) {
 
1334
                xsm->xsm_xlocker = 0;
 
1335
                if (xsm->xsm_rwait_count) {
 
1336
                        if (!xt_broadcast_cond_ns(&xsm->xsm_rcond)) {
 
1337
                                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1338
                                return FAILED;
 
1339
                        }
 
1340
                }
 
1341
                else if (xsm->xsm_xwait_count) {
 
1342
                        /* Wake up any other X or shared lockers: */
 
1343
                        if (!xt_broadcast_cond_ns(&xsm->xsm_xcond)) {
 
1344
                                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1345
                                return FAILED;
 
1346
                        }
 
1347
                }
 
1348
                xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1349
        }
 
1350
        else {
 
1351
                /* Taking the advice from {RACE-WR_MUTEX} I do the decrement
 
1352
                 * after I have a lock!
 
1353
                 */
 
1354
                if (xsm->xsm_xwait_count) {
 
1355
                        xt_lock_mutex_ns(&xsm->xsm_lock);
 
1356
                        xt_atomic_dec2(&xsm->xsm_rlock_count);
 
1357
                        if (xsm->xsm_xwait_count && xsm->xsm_rwait_count == xsm->xsm_rlock_count) {
 
1358
                                /* If the X locker is waiting for me,
 
1359
                                 * then allow him to continue. 
 
1360
                                 */
 
1361
                                if (!xt_broadcast_cond_ns(&xsm->xsm_xcond)) {
 
1362
                                        xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1363
                                        return FAILED;
 
1364
                                }
 
1365
                        }
 
1366
                        xt_unlock_mutex_ns(&xsm->xsm_lock);
 
1367
                }
 
1368
                else
 
1369
                        xt_atomic_dec2(&xsm->xsm_rlock_count);
 
1370
        }
 
1371
 
 
1372
#ifdef XT_THREAD_LOCK_INFO
 
1373
        xt_thread_lock_info_release_owner(&xsm->xsm_lock_info);
 
1374
#endif
 
1375
        return OK;
 
1376
}
 
1377
 
 
1378
/*
 
1379
 * -----------------------------------------------------------------------
 
1380
 * RECURSIVE R/W LOCK (allows X lockers to lock again)
 
1381
 */
 
1382
 
 
1383
#ifdef XT_THREAD_LOCK_INFO
 
1384
void xt_recursivemutex_init(XTThreadPtr self, XTRecursiveMutexPtr rm, const char *name)
 
1385
{
 
1386
        rm->rm_locker = NULL;
 
1387
        rm->rm_lock_count = 0;
 
1388
        xt_init_mutex(self, &rm->rm_mutex, name);
 
1389
}
 
1390
#else
 
1391
xtPublic void xt_recursivemutex_init(XTThreadPtr self, XTRecursiveMutexPtr rm)
 
1392
{
 
1393
        rm->rm_locker = NULL;
 
1394
        rm->rm_lock_count = 0;
 
1395
        xt_init_mutex(self, &rm->rm_mutex);
 
1396
}
 
1397
#endif
 
1398
 
 
1399
xtPublic void xt_recursivemutex_free(XTRecursiveMutexPtr rm)
 
1400
{
 
1401
        xt_free_mutex(&rm->rm_mutex);
 
1402
#ifdef XT_THREAD_LOCK_INFO
 
1403
        xt_thread_lock_info_free(&rm->rm_lock_info);
 
1404
#endif
 
1405
}
 
1406
 
 
1407
xtPublic void xt_recursivemutex_lock(XTThreadPtr self, XTRecursiveMutexPtr rm)
 
1408
{
 
1409
        if (self != rm->rm_locker) {
 
1410
                xt_lock_mutex(self, &rm->rm_mutex);
 
1411
                rm->rm_locker = self;
 
1412
        }
 
1413
        rm->rm_lock_count++;
 
1414
}
 
1415
 
 
1416
xtPublic void xt_recursivemutex_unlock(XTThreadPtr self, XTRecursiveMutexPtr rm)
 
1417
{
 
1418
        ASSERT(self == rm->rm_locker);
 
1419
        ASSERT(rm->rm_lock_count > 0);
 
1420
        rm->rm_lock_count--;
 
1421
        if (!rm->rm_lock_count) {
 
1422
                rm->rm_locker = NULL;
 
1423
                xt_unlock_mutex(self, &rm->rm_mutex);
 
1424
        }
 
1425
}
 
1426
 
 
1427
/*
 
1428
 * -----------------------------------------------------------------------
 
1429
 * RECURSIVE MUTEX (allows lockers to lock again)
 
1430
 */
 
1431
 
 
1432
#ifdef XT_THREAD_LOCK_INFO
 
1433
void xt_recurrwlock_init(struct XTThread *self, XTRecurRWLockPtr rrw, const char *name)
 
1434
{
 
1435
        rrw->rrw_locker = NULL;
 
1436
        rrw->rrw_lock_count = 0;
 
1437
        xt_init_rwlock(self, &rrw->rrw_lock, name);
 
1438
}
 
1439
#else
 
1440
void xt_recurrwlock_init(struct XTThread *self, XTRecurRWLockPtr rrw)
 
1441
{
 
1442
        rrw->rrw_locker = NULL;
 
1443
        rrw->rrw_lock_count = 0;
 
1444
        xt_init_rwlock(self, &rrw->rrw_lock);
 
1445
}
 
1446
#endif
 
1447
 
 
1448
void xt_recurrwlock_free(XTRecurRWLockPtr rrw)
 
1449
{
 
1450
        xt_free_rwlock(&rrw->rrw_lock);
 
1451
#ifdef XT_THREAD_LOCK_INFO
 
1452
        xt_thread_lock_info_free(&rrw->rrw_lock_info);
 
1453
#endif
 
1454
}
 
1455
 
 
1456
void xt_recurrwlock_xlock(struct XTThread *self, XTRecurRWLockPtr rrw)
 
1457
{
 
1458
        if (self != rrw->rrw_locker) {
 
1459
                xt_xlock_rwlock(self, &rrw->rrw_lock);
 
1460
                rrw->rrw_locker = self;
 
1461
        }
 
1462
        rrw->rrw_lock_count++;
 
1463
}
 
1464
 
 
1465
void xt_recurrwlock_slock(struct XTThread *self, XTRecurRWLockPtr rrw)
 
1466
{
 
1467
        xt_slock_rwlock(self, &rrw->rrw_lock);
 
1468
}
 
1469
 
 
1470
void xt_recurrwlock_slock_ns(XTRecurRWLockPtr rrw)
 
1471
{
 
1472
        xt_slock_rwlock_ns(&rrw->rrw_lock);
 
1473
}
 
1474
 
 
1475
void xt_recurrwlock_unxlock(struct XTThread *self, XTRecurRWLockPtr rrw)
 
1476
{
 
1477
        ASSERT(self == rrw->rrw_locker);
 
1478
        ASSERT(rrw->rrw_lock_count > 0);
 
1479
        rrw->rrw_lock_count--;
 
1480
        if (!rrw->rrw_lock_count) {
 
1481
                rrw->rrw_locker = NULL;
 
1482
                xt_unlock_rwlock(self, &rrw->rrw_lock);
 
1483
        }
 
1484
}
 
1485
 
 
1486
void xt_recurrwlock_unslock(struct XTThread *self, XTRecurRWLockPtr rrw)
 
1487
{
 
1488
        xt_unlock_rwlock(self, &rrw->rrw_lock);
 
1489
}
 
1490
 
 
1491
void xt_recurrwlock_unslock_ns(XTRecurRWLockPtr rrw)
 
1492
{
 
1493
        xt_unlock_rwlock_ns(&rrw->rrw_lock);
 
1494
}
 
1495
 
 
1496
/*
 
1497
 * -----------------------------------------------------------------------
 
1498
 * UNIT TESTS
 
1499
 */
 
1500
 
 
1501
#define JOB_MEMCPY                      1
 
1502
#define JOB_SLEEP                       2
 
1503
#define JOB_PRINT                       3
 
1504
#define JOB_INCREMENT           4
 
1505
#define JOB_SNOOZE                      5
 
1506
#define JOB_DOUBLE_INC          6
 
1507
 
 
1508
#define LOCK_PTHREAD_RW         1
 
1509
#define LOCK_PTHREAD_MUTEX      2
 
1510
#define LOCK_XSMUTEX            3
 
1511
#define LOCK_SPINXSLOCK         4
 
1512
#define LOCK_SPINLOCK           5
 
1513
 
 
1514
typedef struct XSLockTest {
 
1515
        u_int                           xs_interations;
 
1516
        xtBool                          xs_which_lock;
 
1517
        xtBool                          xs_which_job;
 
1518
        xtBool                          xs_debug_print;
 
1519
        xt_rwlock_type          xs_plock;
 
1520
        xt_mutex_type           xs_mutex;
 
1521
        XTMutexXSLockRec        xs_fastrwlock;
 
1522
        XTSpinXSLockRec         xs_spinrwlock;
 
1523
        XTSpinLockRec           xs_spinlock;
 
1524
        int                                     xs_progress;
 
1525
        xtWord4                         xs_inc;
 
1526
} XSLockTestRec, *XSLockTestPtr;
 
1527
 
 
1528
static void lck_free_thread_data(XTThreadPtr XT_UNUSED(self), void *XT_UNUSED(data))
 
1529
{
 
1530
}
 
1531
 
 
1532
static void lck_do_job(XTThreadPtr self, int job, XSLockTestPtr data, xtBool reader)
 
1533
{
 
1534
        char b1[2048], b2[2048];
 
1535
 
 
1536
        switch (job) {
 
1537
                case JOB_MEMCPY:
 
1538
                        memcpy(b1, b2, 2048);
 
1539
                        data->xs_inc++;
 
1540
                        break;
 
1541
                case JOB_SLEEP:
 
1542
                        xt_sleep_milli_second(1);
 
1543
                        data->xs_inc++;
 
1544
                        break;
 
1545
                case JOB_PRINT:
 
1546
                        printf("- %s got lock\n", self->t_name);
 
1547
                        xt_sleep_milli_second(10);
 
1548
                        data->xs_inc++;
 
1549
                        break;
 
1550
                case JOB_INCREMENT:
 
1551
                        data->xs_inc++;
 
1552
                        break;
 
1553
                case JOB_SNOOZE:
 
1554
                        xt_sleep_milli_second(10);
 
1555
                        data->xs_inc++;
 
1556
                        break;
 
1557
                case JOB_DOUBLE_INC:
 
1558
                        if (reader) {
 
1559
                                if ((data->xs_inc & 1) != 0)
 
1560
                                        printf("Noooo!\n");
 
1561
                        }
 
1562
                        else {
 
1563
                                data->xs_inc++;
 
1564
                                data->xs_inc++;
 
1565
                        }
 
1566
                        break;
 
1567
        }
 
1568
}
 
1569
 
 
1570
#if 0
 
1571
static void *lck_run_dumper(XTThreadPtr self)
 
1572
{
 
1573
        int state = 0;
 
1574
 
 
1575
        while (state != 1) {
 
1576
                sleep(1);
 
1577
                if (state == 2) {
 
1578
                        xt_dump_trace();
 
1579
                        state = 0;
 
1580
                }
 
1581
        }
 
1582
}
 
1583
#endif
 
1584
 
 
1585
static void *lck_run_reader(XTThreadPtr self)
 
1586
{
 
1587
        XSLockTestRec   *data = (XSLockTestRec *) self->t_data;
 
1588
 
 
1589
        if (data->xs_debug_print)
 
1590
                printf("- %s start\n", self->t_name);
 
1591
        for (u_int i=0; i<data->xs_interations; i++) {
 
1592
                if (data->xs_progress && ((i+1) % data->xs_progress) == 0)
 
1593
                        printf("- %s %d\n", self->t_name, i+1);
 
1594
                if (data->xs_which_lock == LOCK_PTHREAD_RW) {
 
1595
                        xt_slock_rwlock_ns(&data->xs_plock);
 
1596
                        lck_do_job(self, data->xs_which_job, data, TRUE);
 
1597
                        xt_unlock_rwlock_ns(&data->xs_plock);
 
1598
                }
 
1599
                else if (data->xs_which_lock == LOCK_SPINXSLOCK) {
 
1600
                        xt_spinxslock_slock(&data->xs_spinrwlock);
 
1601
                        lck_do_job(self, data->xs_which_job, data, TRUE);
 
1602
                        xt_spinxslock_unlock(&data->xs_spinrwlock, FALSE);
 
1603
                }
 
1604
                else if (data->xs_which_lock == LOCK_XSMUTEX) {
 
1605
                        xt_xsmutex_slock(&data->xs_fastrwlock, self->t_id);
 
1606
                        lck_do_job(self, data->xs_which_job, data, TRUE);
 
1607
                        xt_xsmutex_unlock(&data->xs_fastrwlock, self->t_id);
 
1608
                }
 
1609
                else
 
1610
                        ASSERT(FALSE);
 
1611
        }
 
1612
        if (data->xs_debug_print)
 
1613
                printf("- %s stop\n", self->t_name);
 
1614
        return NULL;
 
1615
}
 
1616
 
 
1617
static void *lck_run_writer(XTThreadPtr self)
 
1618
{
 
1619
        XSLockTestRec   *data = (XSLockTestRec *) self->t_data;
 
1620
 
 
1621
        if (data->xs_debug_print)
 
1622
                printf("- %s start\n", self->t_name);
 
1623
        for (u_int i=0; i<data->xs_interations; i++) {
 
1624
                if (data->xs_progress && ((i+1) % data->xs_progress) == 0)
 
1625
                        printf("- %s %d\n", self->t_name, i+1);
 
1626
                if (data->xs_which_lock == LOCK_PTHREAD_RW) {
 
1627
                        xt_xlock_rwlock_ns(&data->xs_plock);
 
1628
                        lck_do_job(self, data->xs_which_job, data, FALSE);
 
1629
                        xt_unlock_rwlock_ns(&data->xs_plock);
 
1630
                }
 
1631
                else if (data->xs_which_lock == LOCK_SPINXSLOCK) {
 
1632
                        xt_spinxslock_xlock(&data->xs_spinrwlock, FALSE, self->t_id);
 
1633
                        lck_do_job(self, data->xs_which_job, data, FALSE);
 
1634
                        xt_spinxslock_unlock(&data->xs_spinrwlock, TRUE);
 
1635
                }
 
1636
                else if (data->xs_which_lock == LOCK_XSMUTEX) {
 
1637
                        xt_xsmutex_xlock(&data->xs_fastrwlock, self->t_id);
 
1638
                        lck_do_job(self, data->xs_which_job, data, FALSE);
 
1639
                        xt_xsmutex_unlock(&data->xs_fastrwlock, self->t_id);
 
1640
                }
 
1641
                else
 
1642
                        ASSERT(FALSE);
 
1643
        }
 
1644
        if (data->xs_debug_print)
 
1645
                printf("- %s stop\n", self->t_name);
 
1646
        return NULL;
 
1647
}
 
1648
 
 
1649
static void lck_print_test(XSLockTestRec *data)
 
1650
{
 
1651
        switch (data->xs_which_lock) {
 
1652
                case LOCK_PTHREAD_RW:
 
1653
                        printf("pthread read/write");
 
1654
                        break;
 
1655
                case LOCK_PTHREAD_MUTEX:
 
1656
                        printf("pthread mutex");
 
1657
                        break;
 
1658
                case LOCK_SPINLOCK:
 
1659
                        printf("spin mutex");
 
1660
                        break;
 
1661
                case LOCK_SPINXSLOCK:
 
1662
                        printf("spin read/write lock");
 
1663
                        break;
 
1664
                case LOCK_XSMUTEX:
 
1665
                        printf("fast x/s mutex");
 
1666
                        break;
 
1667
        }
 
1668
 
 
1669
        switch (data->xs_which_job) {
 
1670
                case JOB_MEMCPY:
 
1671
                        printf(" MEMCPY 2K");
 
1672
                        break;
 
1673
                case JOB_SLEEP:
 
1674
                        printf(" SLEEP 1/1000s");
 
1675
                        break;
 
1676
                case JOB_PRINT:
 
1677
                        printf(" PRINT DEBUG");
 
1678
                        break;
 
1679
                case JOB_INCREMENT:
 
1680
                        printf(" INCREMENT");
 
1681
                        break;
 
1682
                case JOB_SNOOZE:
 
1683
                        printf(" SLEEP 1/100s");
 
1684
                        break;
 
1685
        }
 
1686
        
 
1687
        printf(" %d interations", data->xs_interations);
 
1688
}
 
1689
 
 
1690
static void *lck_run_mutex_locker(XTThreadPtr self)
 
1691
{
 
1692
        XSLockTestRec *data = (XSLockTestRec *) self->t_data;
 
1693
 
 
1694
        if (data->xs_debug_print)
 
1695
                printf("- %s start\n", self->t_name);
 
1696
        for (u_int i=0; i<data->xs_interations; i++) {
 
1697
                if (data->xs_progress && ((i+1) % data->xs_progress) == 0)
 
1698
                        printf("- %s %d\n", self->t_name, i+1);
 
1699
                if (data->xs_which_lock == LOCK_PTHREAD_MUTEX) {
 
1700
                        xt_lock_mutex_ns(&data->xs_mutex);
 
1701
                        lck_do_job(self, data->xs_which_job, data, FALSE);
 
1702
                        xt_unlock_mutex_ns(&data->xs_mutex);
 
1703
                }
 
1704
                else if (data->xs_which_lock == LOCK_SPINLOCK) {
 
1705
                        xt_spinlock_lock(&data->xs_spinlock);
 
1706
                        lck_do_job(self, data->xs_which_job, data, FALSE);
 
1707
                        xt_spinlock_unlock(&data->xs_spinlock);
 
1708
                }
 
1709
                else
 
1710
                        ASSERT(FALSE);
 
1711
        }
 
1712
        if (data->xs_debug_print)
 
1713
                printf("- %s stop\n", self->t_name);
 
1714
        return NULL;
 
1715
}
 
1716
 
 
1717
typedef struct LockThread {
 
1718
        xtThreadID              id;
 
1719
        XTThreadPtr             ptr;
 
1720
} LockThreadRec, *LockThreadPtr;
 
1721
 
 
1722
static void lck_reader_writer_test(XTThreadPtr self, XSLockTestRec *data, int reader_cnt, int writer_cnt)
 
1723
{
 
1724
        xtWord8                 start;
 
1725
        LockThreadPtr   threads;
 
1726
        int                             thread_cnt = reader_cnt + writer_cnt;
 
1727
        char                    buffer[40];
 
1728
 
 
1729
        //XTThreadPtr dumper = xt_create_daemon(self, "DUMPER");
 
1730
        //xt_run_thread(self, dumper, lck_run_dumper);
 
1731
 
 
1732
        printf("READ/WRITE TEST: ");
 
1733
        lck_print_test(data);
 
1734
        printf(", %d readers, %d writers\n", reader_cnt, writer_cnt);
 
1735
        threads = (LockThreadPtr) xt_malloc(self, thread_cnt * sizeof(LockThreadRec));
 
1736
 
 
1737
        for (int i=0; i<thread_cnt; i++) {
 
1738
                sprintf(buffer, "%s%d", i < reader_cnt ? "READER-" : "WRITER-", i+1);
 
1739
                threads[i].ptr = xt_create_daemon(self, buffer);
 
1740
                threads[i].id = threads[i].ptr->t_id;
 
1741
                xt_set_thread_data(threads[i].ptr, data, lck_free_thread_data);
 
1742
        }
 
1743
 
 
1744
        start = xt_trace_clock();
 
1745
        for (int i=0; i<reader_cnt; i++)
 
1746
                xt_run_thread(self, threads[i].ptr, lck_run_reader);
 
1747
        for (int i=reader_cnt; i<thread_cnt; i++)
 
1748
                xt_run_thread(self, threads[i].ptr, lck_run_writer);
 
1749
 
 
1750
        for (int i=0; i<thread_cnt; i++)
 
1751
                xt_wait_for_thread_to_exit(threads[i].id, TRUE);
 
1752
        printf("----- %d reader, %d writer time=%s\n", reader_cnt, writer_cnt, xt_trace_clock_diff(buffer, start));
 
1753
 
 
1754
        xt_free(self, threads);
 
1755
        printf("TEST RESULT = %d\n", data->xs_inc);
 
1756
 
 
1757
        //xt_wait_for_thread_to_exit(dumper, TRUE);
 
1758
}
 
1759
 
 
1760
static void lck_mutex_lock_test(XTThreadPtr self, XSLockTestRec *data, int thread_cnt)
 
1761
{
 
1762
        xtWord8                 start;
 
1763
        LockThreadPtr   threads;
 
1764
        char                    buffer[40];
 
1765
 
 
1766
        printf("LOCK MUTEX TEST: ");
 
1767
        lck_print_test(data);
 
1768
        printf(", %d threads\n", thread_cnt);
 
1769
        threads = (LockThreadPtr) xt_malloc(self, thread_cnt * sizeof(LockThreadRec));
 
1770
 
 
1771
        for (int i=0; i<thread_cnt; i++) {
 
1772
                sprintf(buffer, "THREAD%d", i+1);
 
1773
                threads[i].ptr = xt_create_daemon(self, buffer);
 
1774
                threads[i].id = threads[i].ptr->t_id;
 
1775
                xt_set_thread_data(threads[i].ptr, data, lck_free_thread_data);
 
1776
        }
 
1777
 
 
1778
        start = xt_trace_clock();
 
1779
        for (int i=0; i<thread_cnt; i++)
 
1780
                xt_run_thread(self, threads[i].ptr, lck_run_mutex_locker);
 
1781
 
 
1782
        for (int i=0; i<thread_cnt; i++)
 
1783
                xt_wait_for_thread_to_exit(threads[i].id, TRUE);
 
1784
        printf("----- %d threads time=%s\n", thread_cnt, xt_trace_clock_diff(buffer, start));
 
1785
 
 
1786
        xt_free(self, threads);
 
1787
        printf("TEST RESULT = %d\n", data->xs_inc);
 
1788
}
 
1789
 
 
1790
xtPublic void xt_unit_test_read_write_locks(XTThreadPtr self)
 
1791
{
 
1792
        XSLockTestRec   data;
 
1793
 
 
1794
        memset(&data, 0, sizeof(data));
 
1795
 
 
1796
        printf("TEST: xt_unit_test_read_write_locks\n");
 
1797
        printf("size of XTMutexXSLockRec = %d\n", (int) sizeof(XTMutexXSLockRec));
 
1798
        printf("size of pthread_cond_t = %d\n", (int) sizeof(pthread_cond_t));
 
1799
        printf("size of pthread_mutex_t = %d\n", (int) sizeof(pthread_mutex_t));
 
1800
        xt_init_rwlock_with_autoname(self, &data.xs_plock);
 
1801
        xt_spinxslock_init_with_autoname(self, &data.xs_spinrwlock);
 
1802
        xt_xsmutex_init_with_autoname(self, &data.xs_fastrwlock);
 
1803
 
 
1804
        /**
 
1805
        data.xs_interations = 10;
 
1806
        data.xs_which_lock = ; // LOCK_PTHREAD_RW, LOCK_SPINXSLOCK, LOCK_XSMUTEX
 
1807
        data.xs_which_job = JOB_PRINT;
 
1808
        data.xs_debug_print = TRUE;
 
1809
        data.xs_progress = 0;
 
1810
        lck_reader_writer_test(self, &data, 4, 0);
 
1811
        lck_reader_writer_test(self, &data, 0, 2);
 
1812
        lck_reader_writer_test(self, &data, 1, 1);
 
1813
        lck_reader_writer_test(self, &data, 4, 2);
 
1814
        **/
 
1815
 
 
1816
        /**
 
1817
        data.xs_interations = 4000;
 
1818
        data.xs_which_lock = ; // LOCK_PTHREAD_RW, LOCK_SPINXSLOCK, LOCK_XSMUTEX
 
1819
        data.xs_which_job = JOB_SLEEP;
 
1820
        data.xs_debug_print = TRUE;
 
1821
        data.xs_progress = 200;
 
1822
        lck_reader_writer_test(self, &data, 4, 0);
 
1823
        lck_reader_writer_test(self, &data, 0, 2);
 
1824
        lck_reader_writer_test(self, &data, 1, 1);
 
1825
        lck_reader_writer_test(self, &data, 4, 2);
 
1826
        **/
 
1827
 
 
1828
        // LOCK_PTHREAD_RW, LOCK_SPINXSLOCK, LOCK_XSMUTEX
 
1829
        /**/
 
1830
        data.xs_interations = 100000;
 
1831
        data.xs_which_lock = LOCK_XSMUTEX;
 
1832
        data.xs_which_job = JOB_DOUBLE_INC; // JOB_INCREMENT, JOB_DOUBLE_INC
 
1833
        data.xs_debug_print = FALSE;
 
1834
        data.xs_progress = 0;
 
1835
        lck_reader_writer_test(self, &data, 10, 0);
 
1836
        data.xs_which_lock = LOCK_XSMUTEX;
 
1837
        lck_reader_writer_test(self, &data, 10, 0);
 
1838
        //lck_reader_writer_test(self, &data, 0, 5);
 
1839
        //lck_reader_writer_test(self, &data, 10, 0);
 
1840
        //lck_reader_writer_test(self, &data, 10, 5);
 
1841
        /**/
 
1842
 
 
1843
        /**/
 
1844
        data.xs_interations = 10000;
 
1845
        data.xs_which_lock = LOCK_XSMUTEX;
 
1846
        data.xs_which_job = JOB_MEMCPY;
 
1847
        data.xs_debug_print = FALSE;
 
1848
        data.xs_progress = 0;
 
1849
        lck_reader_writer_test(self, &data, 10, 0);
 
1850
        data.xs_which_lock = LOCK_XSMUTEX;
 
1851
        lck_reader_writer_test(self, &data, 10, 0);
 
1852
        //lck_reader_writer_test(self, &data, 0, 5);
 
1853
        //lck_reader_writer_test(self, &data, 10, 0);
 
1854
        //lck_reader_writer_test(self, &data, 10, 5);
 
1855
        /**/
 
1856
 
 
1857
        /**/
 
1858
        data.xs_interations = 1000;
 
1859
        data.xs_which_lock = LOCK_XSMUTEX;
 
1860
        data.xs_which_job = JOB_SLEEP; // JOB_SLEEP, JOB_SNOOZE
 
1861
        data.xs_debug_print = FALSE;
 
1862
        data.xs_progress = 0;
 
1863
        lck_reader_writer_test(self, &data, 10, 0);
 
1864
        data.xs_which_lock = LOCK_XSMUTEX;
 
1865
        lck_reader_writer_test(self, &data, 10, 0);
 
1866
        /**/
 
1867
 
 
1868
        xt_free_rwlock(&data.xs_plock);
 
1869
        xt_spinxslock_free(self, &data.xs_spinrwlock);
 
1870
        xt_xsmutex_free(self, &data.xs_fastrwlock);
 
1871
}
 
1872
 
 
1873
xtPublic void xt_unit_test_mutex_locks(XTThreadPtr self)
 
1874
{
 
1875
        XSLockTestRec   data;
 
1876
 
 
1877
        memset(&data, 0, sizeof(data));
 
1878
 
 
1879
        printf("TEST: xt_unit_test_mutex_locks\n");
 
1880
        xt_spinlock_init_with_autoname(self, &data.xs_spinlock);
 
1881
        xt_init_mutex_with_autoname(self, &data.xs_mutex);
 
1882
 
 
1883
        /**/
 
1884
        data.xs_interations = 10;
 
1885
        data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX
 
1886
        data.xs_which_job = JOB_PRINT;
 
1887
        data.xs_debug_print = TRUE;
 
1888
        data.xs_progress = 0;
 
1889
        data.xs_inc = 0;
 
1890
        lck_mutex_lock_test(self, &data, 2);
 
1891
        /**/
 
1892
 
 
1893
        /**/
 
1894
        data.xs_interations = 100000;
 
1895
        data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX
 
1896
        data.xs_which_job = JOB_INCREMENT;
 
1897
        data.xs_debug_print = FALSE;
 
1898
        data.xs_progress = 0;
 
1899
        data.xs_inc = 0;
 
1900
        lck_mutex_lock_test(self, &data, 10);
 
1901
        /**/
 
1902
 
 
1903
        /**/
 
1904
        data.xs_interations = 10000;
 
1905
        data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX
 
1906
        data.xs_which_job = JOB_MEMCPY;
 
1907
        data.xs_debug_print = FALSE;
 
1908
        data.xs_progress = 0;
 
1909
        data.xs_inc = 0;
 
1910
        lck_mutex_lock_test(self, &data, 10);
 
1911
        /**/
 
1912
 
 
1913
        /**/
 
1914
        data.xs_interations = 1000;
 
1915
        data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX
 
1916
        data.xs_which_job = JOB_SLEEP;
 
1917
        data.xs_debug_print = FALSE;
 
1918
        data.xs_progress = 0;
 
1919
        data.xs_inc = 0;
 
1920
        lck_mutex_lock_test(self, &data, 10);
 
1921
        /**/
 
1922
 
 
1923
        /**/
 
1924
        data.xs_interations = 100;
 
1925
        data.xs_which_lock = LOCK_SPINLOCK; // LOCK_SPINLOCK, LOCK_PTHREAD_MUTEX
 
1926
        data.xs_which_job = JOB_SNOOZE;
 
1927
        data.xs_debug_print = FALSE;
 
1928
        data.xs_progress = 0;
 
1929
        data.xs_inc = 0;
 
1930
        lck_mutex_lock_test(self, &data, 10);
 
1931
        /**/
 
1932
 
 
1933
        xt_spinlock_free(self, &data.xs_spinlock);
 
1934
        xt_free_mutex(&data.xs_mutex);
 
1935
}
 
1936
 
 
1937
xtPublic void xt_unit_test_create_threads(XTThreadPtr self)
 
1938
{
 
1939
        XTThreadPtr             threads[10];
 
1940
 
 
1941
        printf("TEST: xt_unit_test_create_threads\n");
 
1942
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1943
 
 
1944
        /* Create some threads: */
 
1945
        threads[0] = xt_create_daemon(self, "test0");
 
1946
        printf("thread = %d\n", threads[0]->t_id);
 
1947
        threads[1] = xt_create_daemon(self, "test1");
 
1948
        printf("thread = %d\n", threads[1]->t_id);
 
1949
        threads[2] = xt_create_daemon(self, "test2");
 
1950
        printf("thread = %d\n", threads[2]->t_id);
 
1951
        threads[3] = xt_create_daemon(self, "test3");
 
1952
        printf("thread = %d\n", threads[3]->t_id);
 
1953
        threads[4] = xt_create_daemon(self, "test4");
 
1954
        printf("thread = %d\n", threads[4]->t_id);
 
1955
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1956
 
 
1957
        /* Max stays the same: */
 
1958
        xt_free_thread(threads[3]);
 
1959
        xt_free_thread(threads[2]);
 
1960
        xt_free_thread(threads[1]);
 
1961
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1962
 
 
1963
        /* Fill in the gaps: */
 
1964
        threads[1] = xt_create_daemon(self, "test1");
 
1965
        printf("thread = %d\n", threads[1]->t_id);
 
1966
        threads[2] = xt_create_daemon(self, "test2");
 
1967
        printf("thread = %d\n", threads[2]->t_id);
 
1968
        threads[3] = xt_create_daemon(self, "test3");
 
1969
        printf("thread = %d\n", threads[3]->t_id);
 
1970
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1971
 
 
1972
        /* And add one: */
 
1973
        threads[5] = xt_create_daemon(self, "test5");
 
1974
        printf("thread = %d\n", threads[5]->t_id);
 
1975
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1976
 
 
1977
        /* Max stays the same: */
 
1978
        xt_free_thread(threads[3]);
 
1979
        xt_free_thread(threads[2]);
 
1980
        xt_free_thread(threads[1]);
 
1981
        xt_free_thread(threads[4]);
 
1982
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1983
 
 
1984
        /* Recalculate the max: */
 
1985
        xt_free_thread(threads[5]);
 
1986
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1987
 
 
1988
        /* Fill in the gaps: */
 
1989
        threads[1] = xt_create_daemon(self, "test1");
 
1990
        printf("thread = %d\n", threads[1]->t_id);
 
1991
        threads[2] = xt_create_daemon(self, "test2");
 
1992
        printf("thread = %d\n", threads[2]->t_id);
 
1993
        threads[3] = xt_create_daemon(self, "test3");
 
1994
        printf("thread = %d\n", threads[3]->t_id);
 
1995
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
1996
 
 
1997
        xt_free_thread(threads[3]);
 
1998
        xt_free_thread(threads[2]);
 
1999
        xt_free_thread(threads[1]);
 
2000
        xt_free_thread(threads[0]);
 
2001
        printf("current max threads = %d, in use = %d\n", xt_thr_current_max_threads, xt_thr_current_thread_count);
 
2002
}
 
2003
 
 
2004
#ifdef UNUSED_CODE
 
2005
int XTRowLocks::xt_release_locks(struct XTOpenTable *ot, xtRowID row, XTRowLockListPtr lock_list)
 
2006
{
 
2007
        if (ot->ot_temp_row_lock)
 
2008
                xt_make_lock_permanent(ot, lock_list);
 
2009
 
 
2010
        if (!lock_list->bl_count)
 
2011
                return XT_NO_LOCK;
 
2012
 
 
2013
        int                                     group, pgroup;
 
2014
        XTXactDataPtr           xact;
 
2015
        xtTableID                       tab_id, ptab_id;
 
2016
        XTPermRowLockPtr        plock;
 
2017
        XTOpenTablePtr          pot = NULL;
 
2018
        XTRowLocksPtr           row_locks;
 
2019
 
 
2020
        /* Do I have the lock? */
 
2021
        group = row % XT_ROW_LOCK_COUNT;
 
2022
        if (!(xact = tab_row_locks[group]))
 
2023
                /* There is no lock: */
 
2024
                return XT_NO_LOCK;
 
2025
 
 
2026
        if (xact != ot->ot_thread->st_xact_data)
 
2027
                /* There is a lock but it does not belong to me! */
 
2028
                return XT_NO_LOCK;
 
2029
 
 
2030
        tab_id = ot->ot_table->tab_id;
 
2031
        plock = (XTPermRowLockPtr) &lock_list->bl_data[lock_list->bl_count * lock_list->bl_item_size];
 
2032
        lock_list->rll_release_point = lock_list->bl_count;
 
2033
        for (u_int i=0; i<lock_list->bl_count; i++) {
 
2034
                plock--;
 
2035
 
 
2036
                pgroup = plock->pr_group;
 
2037
                ptab_id = plock->pr_tab_id;
 
2038
 
 
2039
                if (ptab_id == tab_id)
 
2040
                        row_locks = this;
 
2041
                else {
 
2042
                        if (pot) {
 
2043
                                if (pot->ot_table->tab_id == ptab_id)
 
2044
                                        goto remove_lock;
 
2045
                                xt_db_return_table_to_pool_ns(pot);
 
2046
                                pot = NULL;
 
2047
                        }
 
2048
 
 
2049
                        if (!xt_db_open_pool_table_ns(&pot, ot->ot_table->tab_db, tab_id)) {
 
2050
                                /* Should not happen, but just in case, we just don't
 
2051
                                 * remove the lock. We will probably end up with a deadlock
 
2052
                                 * somewhere.
 
2053
                                 */
 
2054
                                xt_log_and_clear_exception_ns();
 
2055
                                goto skip_remove_lock;
 
2056
                        }
 
2057
                        if (!pot)
 
2058
                                /* Can happen of the table has been dropped: */
 
2059
                                goto skip_remove_lock;
 
2060
 
 
2061
                        remove_lock:
 
2062
                        row_locks = &pot->ot_table->tab_locks;
 
2063
                }
 
2064
 
 
2065
#ifdef XT_TRACE_LOCKS
 
2066
                xt_ttracef(xt_get_self(), "release lock group=%d\n", pgroup);
 
2067
#endif
 
2068
                row_locks->tab_row_locks[pgroup] = NULL;
 
2069
                row_locks->tab_lock_perm[pgroup] = 0;
 
2070
                skip_remove_lock:;
 
2071
 
 
2072
                lock_list->rll_release_point--;
 
2073
                if (tab_id == ptab_id && group == pgroup)
 
2074
                        break;
 
2075
        }
 
2076
 
 
2077
        if (pot) 
 
2078
                xt_db_return_table_to_pool_ns(pot);
 
2079
        return XT_PERM_LOCK;
 
2080
}
 
2081
 
 
2082
xtBool XTRowLocks::xt_regain_locks(struct XTOpenTable *ot, int *lock_type, xtXactID *xn_id, XTRowLockListPtr lock_list)
 
2083
{
 
2084
        int                                     group;
 
2085
        XTXactDataPtr           xact, my_xact;
 
2086
        XTPermRowLockPtr        plock;
 
2087
        xtTableID                       tab_id;
 
2088
        XTOpenTablePtr          pot = NULL;
 
2089
        XTRowLocksPtr           row_locks = NULL;
 
2090
        XTTableHPtr                     tab = NULL;
 
2091
 
 
2092
        for (u_int i=lock_list->rll_release_point; i<lock_list->bl_count; i++) {
 
2093
                plock = (XTPermRowLockPtr) &lock_list->bl_data[i * lock_list->bl_item_size];
 
2094
 
 
2095
                my_xact = ot->ot_thread->st_xact_data;
 
2096
                group = plock->pr_group;
 
2097
                tab_id = plock->pr_tab_id;
 
2098
 
 
2099
                if (tab_id == ot->ot_table->tab_id) {
 
2100
                        row_locks = this;
 
2101
                        tab = ot->ot_table;
 
2102
                }
 
2103
                else {
 
2104
                        if (pot) {
 
2105
                                if (tab_id == pot->ot_table->tab_id)
 
2106
                                        goto gain_lock;
 
2107
                                xt_db_return_table_to_pool_ns(pot);
 
2108
                                pot = NULL;
 
2109
                        }
 
2110
 
 
2111
                        if (!xt_db_open_pool_table_ns(&pot, ot->ot_table->tab_db, tab_id))
 
2112
                                return FAILED;
 
2113
                        if (!pot)
 
2114
                                goto no_gain_lock;
 
2115
                        
 
2116
                        gain_lock:
 
2117
                        tab = pot->ot_table;
 
2118
                        row_locks = &tab->tab_locks;
 
2119
                        no_gain_lock:;
 
2120
                }
 
2121
 
 
2122
#ifdef XT_TRACE_LOCKS
 
2123
                xt_ttracef(xt_get_self(), "regain lock group=%d\n", group);
 
2124
#endif
 
2125
                XT_TAB_ROW_WRITE_LOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread);
 
2126
                if ((xact = row_locks->tab_row_locks[group])) {
 
2127
                        if (xact != my_xact) {
 
2128
                                *xn_id = xact->xd_start_xn_id;
 
2129
                                *lock_type = row_locks->tab_lock_perm[group] ? XT_PERM_LOCK : XT_TEMP_LOCK;
 
2130
                                goto done;
 
2131
                        }
 
2132
                }
 
2133
                else
 
2134
                        row_locks->tab_row_locks[group] = my_xact;
 
2135
                row_locks->tab_lock_perm[group] = 1;
 
2136
                XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread);
 
2137
                lock_list->rll_release_point++;
 
2138
        }
 
2139
        *lock_type = XT_NO_LOCK;
 
2140
        return OK;
 
2141
 
 
2142
        done:
 
2143
        XT_TAB_ROW_UNLOCK(&tab->tab_row_rwlock[group % XT_ROW_RWLOCKS], ot->ot_thread);
 
2144
        return OK;
 
2145
}
 
2146
 
 
2147
#endif