plotter: require double buffering
[debian/gnuradio] / gnuradio-core / src / lib / runtime / gr_scheduler_thread.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_scheduler_thread.h>
28 #include <iostream>
29 #include <stdio.h>
30
31 #ifdef HAVE_SIGNAL_H
32 #include <signal.h>
33 #endif
34
35 #define GR_SCHEDULER_THREAD_DEBUG 0
36
37 gr_scheduler_thread::gr_scheduler_thread(gr_block_vector_t graph) :
38   omni_thread(NULL, PRIORITY_NORMAL),
39   d_sts(gr_make_single_threaded_scheduler(graph))
40 {
41 }
42
43 gr_scheduler_thread::~gr_scheduler_thread()
44 {
45 }
46
47 void gr_scheduler_thread::start()
48 {
49   if (GR_SCHEDULER_THREAD_DEBUG)
50     std::cout << "gr_scheduler_thread::start() "
51               << this << std::endl;
52   start_undetached();
53 }
54
55 void *
56 gr_scheduler_thread::run_undetached(void *arg)
57 {
58   // This is the first code to run in the new thread context.
59
60   /*
61    * In general, on a *nix system, any thread of a process can receive
62    * any asynchronous signal.
63    *
64    * http://www.serpentine.com/blog/threads-faq/mixing-threads-and-signals-unix/
65    * http://www.linuxjournal.com/article/2121
66    * 
67    * We really don't want to be handling asynchronous signals such
68    * as SIGINT and SIGHUP here.  We mask them off in the signal
69    * processing threads so that they'll get handled by the mainline
70    * thread.  We leave the synchronous signals SIGQUIT, SIGBUS,
71    * SIGILL, SIGSEGV etc alone
72    *
73    * FIXME? It might be better to mask them all off in the parent
74    * thread then dedicate a single thread to handling all signals
75    * using sigwait.
76    */
77 #if defined(HAVE_PTHREAD_SIGMASK) || defined(HAVE_SIGPROCMASK)
78   sigset_t old_set;
79   sigset_t new_set;
80   int r;
81   sigemptyset(&new_set);
82   sigaddset(&new_set, SIGINT);
83   sigaddset(&new_set, SIGHUP);
84   sigaddset(&new_set, SIGPIPE);
85   sigaddset(&new_set, SIGALRM);
86   sigaddset(&new_set, SIGCHLD);
87
88 #ifdef HAVE_PTHREAD_SIGMASK
89   r = pthread_sigmask(SIG_BLOCK, &new_set, &old_set);
90   if (r != 0)
91     perror("pthread_sigmask");
92 #else
93   r = sigprocmask(SIG_BLOCK, &new_set, &old_set);
94   if (r != 0)
95     perror("sigprocmask");
96 #endif
97 #endif
98   // Run the single-threaded scheduler
99   d_sts->run();
100   return 0;
101 }
102
103 void
104 gr_scheduler_thread::stop()
105 {
106   if (0 && GR_SCHEDULER_THREAD_DEBUG)           // FIXME not safe to call from signal handler
107     std::cout << "gr_scheduler_thread::stop() "
108               << this << std::endl;
109   d_sts->stop();
110 }