~ubuntu-branches/ubuntu/trusty/gnuradio/trusty

« back to all changes in this revision

Viewing changes to omnithread/solaris.cc

  • Committer: Bazaar Package Importer
  • Author(s): Kamal Mostafa
  • Date: 2010-03-13 07:46:01 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100313074601-zjsa893a87bozyh7
Tags: 3.2.2.dfsg-1ubuntu1
* Fix build for Ubuntu lucid (LP: #260406)
  - add binary package dep for libusrp0, libusrp2-0: adduser
  - debian/rules clean: remove pre-built Qt moc files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//                              Package : omnithread
 
2
// omnithread/solaris.cc        Created : 7/94 tjr
 
3
//
 
4
//    Copyright (C) 1994-1999 AT&T Laboratories Cambridge
 
5
//
 
6
//    This file is part of the omnithread library
 
7
//
 
8
//    The omnithread library is free software; you can redistribute it and/or
 
9
//    modify it under the terms of the GNU Library General Public
 
10
//    License as published by the Free Software Foundation; either
 
11
//    version 2 of the License, or (at your option) any later version.
 
12
//
 
13
//    This library is distributed in the hope that it will be useful,
 
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
//    Library General Public License for more details.
 
17
//
 
18
//    You should have received a copy of the GNU Library General Public
 
19
//    License along with this library; if not, write to the Free
 
20
//    Software Foundation, Inc., 51 Franklin Street, Boston, MA  
 
21
//    02110-1301, USA
 
22
//
 
23
//
 
24
// Implementation of OMNI thread abstraction for solaris threads.
 
25
//
 
26
 
 
27
#include <stdlib.h>
 
28
#include <errno.h>
 
29
#include <gnuradio/omnithread.h>
 
30
 
 
31
#define DB(x) // x 
 
32
// #include <iostream> or #include <iostream.h> if DB is on.
 
33
 
 
34
#define THROW_ERRORS(x) { int rc = (x); \
 
35
                          if (rc != 0) throw omni_thread_fatal(rc); }
 
36
 
 
37
 
 
38
 
 
39
///////////////////////////////////////////////////////////////////////////
 
40
//
 
41
// Mutex
 
42
//
 
43
///////////////////////////////////////////////////////////////////////////
 
44
 
 
45
 
 
46
omni_mutex::omni_mutex(void)
 
47
{
 
48
    THROW_ERRORS(mutex_init(&sol_mutex, USYNC_THREAD, 0));
 
49
}
 
50
 
 
51
omni_mutex::~omni_mutex(void)
 
52
{
 
53
    THROW_ERRORS(mutex_destroy(&sol_mutex));
 
54
}
 
55
 
 
56
void
 
57
omni_mutex::lock(void)
 
58
{
 
59
    THROW_ERRORS(mutex_lock(&sol_mutex));
 
60
}
 
61
 
 
62
void
 
63
omni_mutex::unlock(void)
 
64
{
 
65
    THROW_ERRORS(mutex_unlock(&sol_mutex));
 
66
}
 
67
 
 
68
 
 
69
 
 
70
///////////////////////////////////////////////////////////////////////////
 
71
//
 
72
// Condition variable
 
73
//
 
74
///////////////////////////////////////////////////////////////////////////
 
75
 
 
76
 
 
77
omni_condition::omni_condition(omni_mutex* m) : mutex(m)
 
78
{
 
79
    THROW_ERRORS(cond_init(&sol_cond, USYNC_THREAD, 0));
 
80
}
 
81
 
 
82
omni_condition::~omni_condition(void)
 
83
{
 
84
    THROW_ERRORS(cond_destroy(&sol_cond));
 
85
}
 
86
 
 
87
void
 
88
omni_condition::wait(void)
 
89
{
 
90
    THROW_ERRORS(cond_wait(&sol_cond, &mutex->sol_mutex));
 
91
}
 
92
 
 
93
int
 
94
omni_condition::timedwait(unsigned long secs, unsigned long nanosecs)
 
95
{
 
96
    timespec rqts = { secs, nanosecs };
 
97
 
 
98
 again:
 
99
    int rc = cond_timedwait(&sol_cond, &mutex->sol_mutex, &rqts);
 
100
 
 
101
    if (rc == 0)
 
102
        return 1;
 
103
 
 
104
    if (rc == EINTR)
 
105
        goto again;
 
106
 
 
107
    if (rc == ETIME)
 
108
        return 0;
 
109
 
 
110
    throw omni_thread_fatal(rc);
 
111
}
 
112
 
 
113
void
 
114
omni_condition::signal(void)
 
115
{
 
116
    THROW_ERRORS(cond_signal(&sol_cond));
 
117
}
 
118
 
 
119
void
 
120
omni_condition::broadcast(void)
 
121
{
 
122
    THROW_ERRORS(cond_broadcast(&sol_cond));
 
123
}
 
124
 
 
125
 
 
126
 
 
127
///////////////////////////////////////////////////////////////////////////
 
128
//
 
129
// Counting semaphore
 
130
//
 
131
///////////////////////////////////////////////////////////////////////////
 
132
 
 
133
 
 
134
omni_semaphore::omni_semaphore(unsigned int initial)
 
135
{
 
136
    THROW_ERRORS(sema_init(&sol_sem, initial, USYNC_THREAD, NULL));
 
137
}
 
138
 
 
139
omni_semaphore::~omni_semaphore(void)
 
140
{
 
141
    THROW_ERRORS(sema_destroy(&sol_sem));
 
142
}
 
143
 
 
144
void
 
145
omni_semaphore::wait(void)
 
146
{
 
147
    THROW_ERRORS(sema_wait(&sol_sem));
 
148
}
 
149
 
 
150
void
 
151
omni_semaphore::post(void)
 
152
{
 
153
    THROW_ERRORS(sema_post(&sol_sem));
 
154
}
 
155
 
 
156
 
 
157
 
 
158
///////////////////////////////////////////////////////////////////////////
 
159
//
 
160
// Thread
 
161
//
 
162
///////////////////////////////////////////////////////////////////////////
 
163
 
 
164
 
 
165
//
 
166
// Static variables
 
167
//
 
168
 
 
169
int omni_thread::init_t::count = 0;
 
170
 
 
171
omni_mutex* omni_thread::next_id_mutex;
 
172
int omni_thread::next_id = 0;
 
173
 
 
174
static thread_key_t self_key;
 
175
 
 
176
static size_t stack_size = 0;
 
177
 
 
178
//
 
179
// Initialisation function (gets called before any user code).
 
180
//
 
181
 
 
182
omni_thread::init_t::init_t(void)
 
183
{
 
184
    if (count++ != 0)   // only do it once however many objects get created.
 
185
        return;
 
186
 
 
187
    DB(cerr << "omni_thread::init: solaris implementation initialising\n");
 
188
 
 
189
    THROW_ERRORS(thr_keycreate(&self_key, NULL));
 
190
 
 
191
    next_id_mutex = new omni_mutex;
 
192
 
 
193
    //
 
194
    // Create object for this (i.e. initial) thread.
 
195
    //
 
196
 
 
197
    omni_thread* t = new omni_thread;
 
198
 
 
199
    t->_state = STATE_RUNNING;
 
200
 
 
201
    t->sol_thread = thr_self();
 
202
 
 
203
    DB(cerr << "initial thread " << t->id() << " sol_thread " << t->sol_thread
 
204
       << endl);
 
205
 
 
206
    THROW_ERRORS(thr_setspecific(self_key, (void*)t));
 
207
 
 
208
    THROW_ERRORS(thr_setprio(t->sol_thread, sol_priority(PRIORITY_NORMAL)));
 
209
}
 
210
 
 
211
 
 
212
//
 
213
// Wrapper for thread creation.
 
214
//
 
215
 
 
216
extern "C" void*
 
217
omni_thread_wrapper(void* ptr)
 
218
{
 
219
    omni_thread* me = (omni_thread*)ptr;
 
220
 
 
221
    DB(cerr << "omni_thread::wrapper: thread " << me->id()
 
222
       << " started\n");
 
223
 
 
224
    THROW_ERRORS(thr_setspecific(self_key, me));
 
225
 
 
226
    //
 
227
    // Now invoke the thread function with the given argument.
 
228
    //
 
229
 
 
230
    if (me->fn_void != NULL) {
 
231
        (*me->fn_void)(me->thread_arg);
 
232
        omni_thread::exit();
 
233
    }
 
234
 
 
235
    if (me->fn_ret != NULL) {
 
236
        void* return_value = (*me->fn_ret)(me->thread_arg);
 
237
        omni_thread::exit(return_value);
 
238
    }
 
239
 
 
240
    if (me->detached) {
 
241
        me->run(me->thread_arg);
 
242
        omni_thread::exit();
 
243
    } else {
 
244
        void* return_value = me->run_undetached(me->thread_arg);
 
245
        omni_thread::exit(return_value);
 
246
    }
 
247
 
 
248
    // should never get here.
 
249
 
 
250
    return NULL;
 
251
}
 
252
 
 
253
 
 
254
//
 
255
// Constructors for omni_thread - set up the thread object but don't
 
256
// start it running.
 
257
//
 
258
 
 
259
// construct a detached thread running a given function.
 
260
 
 
261
omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
 
262
{
 
263
    common_constructor(arg, pri, 1);
 
264
    fn_void = fn;
 
265
    fn_ret = NULL;
 
266
}
 
267
 
 
268
// construct an undetached thread running a given function.
 
269
 
 
270
omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
 
271
{
 
272
    common_constructor(arg, pri, 0);
 
273
    fn_void = NULL;
 
274
    fn_ret = fn;
 
275
}
 
276
 
 
277
// construct a thread which will run either run() or run_undetached().
 
278
 
 
279
omni_thread::omni_thread(void* arg, priority_t pri)
 
280
{
 
281
    common_constructor(arg, pri, 1);
 
282
    fn_void = NULL;
 
283
    fn_ret = NULL;
 
284
}
 
285
 
 
286
// common part of all constructors.
 
287
 
 
288
void
 
289
omni_thread::common_constructor(void* arg, priority_t pri, int det)
 
290
{
 
291
    _state = STATE_NEW;
 
292
    _priority = pri;
 
293
 
 
294
    next_id_mutex->lock();
 
295
    _id = next_id++;
 
296
    next_id_mutex->unlock();
 
297
 
 
298
    thread_arg = arg;
 
299
    detached = det;     // may be altered in start_undetached()
 
300
 
 
301
    _dummy       = 0;
 
302
    _values      = 0;
 
303
    _value_alloc = 0;
 
304
    // sol_thread is set up in initialisation routine or start().
 
305
}
 
306
 
 
307
 
 
308
//
 
309
// Destructor for omni_thread.
 
310
//
 
311
 
 
312
omni_thread::~omni_thread(void)
 
313
{
 
314
    DB(cerr << "destructor called for thread " << id() << endl);
 
315
    if (_values) {
 
316
        for (key_t i=0; i < _value_alloc; i++) {
 
317
            if (_values[i]) {
 
318
                delete _values[i];
 
319
            }
 
320
        }
 
321
        delete [] _values;
 
322
    }
 
323
}
 
324
 
 
325
 
 
326
//
 
327
// Start the thread
 
328
//
 
329
 
 
330
void
 
331
omni_thread::start(void)
 
332
{
 
333
    long flags = 0;
 
334
 
 
335
    if (detached)
 
336
        flags |= THR_DETACHED;
 
337
 
 
338
    omni_mutex_lock l(mutex);
 
339
 
 
340
    if (_state != STATE_NEW)
 
341
        throw omni_thread_invalid();
 
342
 
 
343
    THROW_ERRORS(thr_create(0, stack_size, omni_thread_wrapper, (void*)this, flags,
 
344
                            &sol_thread));
 
345
 
 
346
    _state = STATE_RUNNING;
 
347
 
 
348
    THROW_ERRORS(thr_setprio(sol_thread, sol_priority(_priority)));
 
349
}
 
350
 
 
351
 
 
352
//
 
353
// Start a thread which will run the member function run_undetached().
 
354
//
 
355
 
 
356
void
 
357
omni_thread::start_undetached(void)
 
358
{
 
359
    if ((fn_void != NULL) || (fn_ret != NULL))
 
360
        throw omni_thread_invalid();
 
361
 
 
362
    detached = 0;
 
363
    start();
 
364
}
 
365
 
 
366
 
 
367
//
 
368
// join - simply check error conditions & call thr_join.
 
369
//
 
370
 
 
371
void
 
372
omni_thread::join(void** status)
 
373
{
 
374
    mutex.lock();
 
375
 
 
376
    if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
 
377
        mutex.unlock();
 
378
        throw omni_thread_invalid();
 
379
    }
 
380
 
 
381
    mutex.unlock();
 
382
 
 
383
    if (this == self())
 
384
        throw omni_thread_invalid();
 
385
 
 
386
    if (detached)
 
387
        throw omni_thread_invalid();
 
388
 
 
389
    DB(cerr << "omni_thread::join: doing thr_join\n");
 
390
 
 
391
    THROW_ERRORS(thr_join(sol_thread, (thread_t *)NULL, status));
 
392
 
 
393
    DB(cerr << "omni_thread::join: thr_join succeeded\n");
 
394
 
 
395
    delete this;
 
396
}
 
397
 
 
398
 
 
399
//
 
400
// Change this thread's priority.
 
401
//
 
402
 
 
403
void
 
404
omni_thread::set_priority(priority_t pri)
 
405
{
 
406
    omni_mutex_lock l(mutex);
 
407
 
 
408
    if (_state != STATE_RUNNING)
 
409
        throw omni_thread_invalid();
 
410
 
 
411
    _priority = pri;
 
412
 
 
413
    THROW_ERRORS(thr_setprio(sol_thread, sol_priority(pri)));
 
414
}
 
415
 
 
416
 
 
417
//
 
418
// create - construct a new thread object and start it running.  Returns thread
 
419
// object if successful, null pointer if not.
 
420
//
 
421
 
 
422
// detached version
 
423
 
 
424
omni_thread*
 
425
omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
 
426
{
 
427
    omni_thread* t = new omni_thread(fn, arg, pri);
 
428
 
 
429
    t->start();
 
430
 
 
431
    return t;
 
432
}
 
433
 
 
434
// undetached version
 
435
 
 
436
omni_thread*
 
437
omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
 
438
{
 
439
    omni_thread* t = new omni_thread(fn, arg, pri);
 
440
 
 
441
    t->start();
 
442
 
 
443
    return t;
 
444
}
 
445
 
 
446
 
 
447
//
 
448
// exit() _must_ lock the mutex even in the case of a detached thread.  This is
 
449
// because a thread may run to completion before the thread that created it has
 
450
// had a chance to get out of start().  By locking the mutex we ensure that the
 
451
// creating thread must have reached the end of start() before we delete the
 
452
// thread object.  Of course, once the call to start() returns, the user can
 
453
// still incorrectly refer to the thread object, but that's their problem.
 
454
//
 
455
 
 
456
void
 
457
omni_thread::exit(void* return_value)
 
458
{
 
459
    omni_thread* me = self();
 
460
 
 
461
    if (me)
 
462
      {
 
463
        me->mutex.lock();
 
464
 
 
465
        me->_state = STATE_TERMINATED;
 
466
 
 
467
        me->mutex.unlock();
 
468
 
 
469
        DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
 
470
           << me->detached << " return value " << return_value << endl);
 
471
 
 
472
        if (me->detached)
 
473
          delete me;
 
474
      }
 
475
    else
 
476
      {
 
477
        DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
 
478
      }
 
479
 
 
480
    thr_exit(return_value);
 
481
}
 
482
 
 
483
 
 
484
omni_thread*
 
485
omni_thread::self(void)
 
486
{
 
487
    omni_thread* me;
 
488
 
 
489
    THROW_ERRORS(thr_getspecific(self_key, (void**)&me));
 
490
 
 
491
    if (!me) {
 
492
      // This thread is not created by omni_thread::start because it
 
493
      // doesn't has a class omni_thread instance attached to its key.
 
494
      DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
 
495
    }
 
496
 
 
497
    return me;
 
498
}
 
499
 
 
500
 
 
501
void
 
502
omni_thread::yield(void)
 
503
{
 
504
    thr_yield();
 
505
}
 
506
 
 
507
 
 
508
void
 
509
omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
 
510
{
 
511
    timespec rqts = { secs, nanosecs };
 
512
    timespec remain;
 
513
    while (nanosleep(&rqts, &remain)) {
 
514
      if (errno == EINTR) {
 
515
        rqts.tv_sec  = remain.tv_sec;
 
516
        rqts.tv_nsec = remain.tv_nsec;
 
517
        continue;
 
518
      }
 
519
      else
 
520
        throw omni_thread_fatal(errno);
 
521
    }
 
522
}
 
523
 
 
524
 
 
525
void
 
526
omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
 
527
                      unsigned long rel_sec, unsigned long rel_nsec)
 
528
{
 
529
    timespec abs;
 
530
    clock_gettime(CLOCK_REALTIME, &abs);
 
531
    abs.tv_nsec += rel_nsec;
 
532
    abs.tv_sec += rel_sec + abs.tv_nsec / 1000000000;
 
533
    abs.tv_nsec = abs.tv_nsec % 1000000000;
 
534
    *abs_sec = abs.tv_sec;
 
535
    *abs_nsec = abs.tv_nsec;
 
536
}
 
537
 
 
538
 
 
539
int
 
540
omni_thread::sol_priority(priority_t pri)
 
541
{
 
542
    switch (pri) {
 
543
 
 
544
    case PRIORITY_LOW:
 
545
        return 0;
 
546
 
 
547
    case PRIORITY_NORMAL:
 
548
        return 1;
 
549
 
 
550
    case PRIORITY_HIGH:
 
551
        return 2;
 
552
    }
 
553
 
 
554
    throw omni_thread_invalid();
 
555
}
 
556
 
 
557
 
 
558
void
 
559
omni_thread::stacksize(unsigned long sz)
 
560
{
 
561
  stack_size = sz;
 
562
}
 
563
 
 
564
unsigned long
 
565
omni_thread::stacksize()
 
566
{
 
567
  return stack_size;
 
568
}
 
569
 
 
570
 
 
571
//
 
572
// Dummy thread
 
573
//
 
574
 
 
575
#error This dummy thread code is not tested. It might work if you're lucky.
 
576
 
 
577
class omni_thread_dummy : public omni_thread {
 
578
public:
 
579
  inline omni_thread_dummy() : omni_thread()
 
580
  {
 
581
    _dummy = 1;
 
582
    _state = STATE_RUNNING;
 
583
    sol_thread = thr_self();
 
584
    THROW_ERRORS(thr_setspecific(self_key, (void*)this));
 
585
  }
 
586
  inline ~omni_thread_dummy()
 
587
  {
 
588
    THROW_ERRORS(thr_setspecific(self_key, 0));
 
589
  }
 
590
};
 
591
 
 
592
omni_thread*
 
593
omni_thread::create_dummy()
 
594
{
 
595
  if (omni_thread::self())
 
596
    throw omni_thread_invalid();
 
597
 
 
598
  return new omni_thread_dummy;
 
599
}
 
600
 
 
601
void
 
602
omni_thread::release_dummy()
 
603
{
 
604
  omni_thread* self = omni_thread::self();
 
605
  if (!self || !self->_dummy)
 
606
    throw omni_thread_invalid();
 
607
 
 
608
  omni_thread_dummy* dummy = (omni_thread_dummy*)self;
 
609
  delete dummy;
 
610
}
 
611
 
 
612
 
 
613
#define INSIDE_THREAD_IMPL_CC
 
614
#include "threaddata.cc"
 
615
#undef INSIDE_THREAD_IMPL_CC