Changeset 6201

Show
Ignore:
Timestamp:
08/28/07 18:42:11
Author:
eb
Message:

trial fix for ticket:137. Merged -r6196:6200 from eb/signal to trunk

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gnuradio/trunk/configure.ac

    r6044 r6201  
    131131AC_CHECK_FUNCS([mmap select socket strcspn strerror strspn getpagesize sysconf]) 
    132132AC_CHECK_FUNCS([snprintf gettimeofday nanosleep sched_setscheduler]) 
    133 AC_CHECK_FUNCS([modf sqrt sigaction sigprocmask]) 
     133AC_CHECK_FUNCS([modf sqrt sigaction sigprocmask pthread_sigmask]) 
    134134AC_CHECK_FUNCS([sched_setaffinity]) 
    135135 
  • gnuradio/trunk/gnuradio-core/src/lib/runtime/gr_hier_block2.h

    r6194 r6201  
    6161  void connect(gr_basic_block_sptr src, int src_port,  
    6262               gr_basic_block_sptr dst, int dst_port); 
     63 
    6364  void disconnect(gr_basic_block_sptr src, int src_port, 
    6465                  gr_basic_block_sptr dst, int dst_port); 
     66 
     67  /*! 
     68   * Lock a flowgraph in preparation for reconfiguration.  When an equal 
     69   * number of calls to lock() and unlock() have occurred, the flowgraph 
     70   * will be restarted automatically. 
     71   * 
     72   * N.B. lock() and unlock() cannot be called from a flowgraph thread 
     73   * (E.g., gr_block::work method) or deadlock will occur when 
     74   * reconfiguration happens. 
     75   */ 
    6576  virtual void lock(); 
     77 
     78  /*! 
     79   * Lock a flowgraph in preparation for reconfiguration.  When an equal 
     80   * number of calls to lock() and unlock() have occurred, the flowgraph 
     81   * will be restarted automatically. 
     82   * 
     83   * N.B. lock() and unlock() cannot be called from a flowgraph thread 
     84   * (E.g., gr_block::work method) or deadlock will occur when 
     85   * reconfiguration happens. 
     86   */ 
    6687  virtual void unlock(); 
    6788 
  • gnuradio/trunk/gnuradio-core/src/lib/runtime/gr_scheduler_thread.cc

    r6193 r6201  
    5555gr_scheduler_thread::run_undetached(void *arg) 
    5656{ 
    57   // First code to run in new thread context 
     57  // This is the first code to run in the new thread context. 
    5858 
    59   // Mask off SIGINT in this thread to gaurantee mainline thread gets signal 
    60 #ifdef HAVE_SIGPROCMASK 
     59  /* 
     60   * In general, on a *nix system, any thread of a process can receive 
     61   * any asynchronous signal. 
     62   * 
     63   * http://www.serpentine.com/blog/threads-faq/mixing-threads-and-signals-unix/ 
     64   * http://www.linuxjournal.com/article/2121 
     65   *  
     66   * We really don't want to be handling asynchronous signals such 
     67   * as SIGINT and SIGHUP here.  We mask them off in the signal 
     68   * processing threads so that they'll get handled by the mainline 
     69   * thread.  We leave the synchronous signals SIGQUIT, SIGBUS, 
     70   * SIGILL, SIGSEGV etc alone 
     71   * 
     72   * FIXME? It might be better to mask them all off in the parent 
     73   * thread then dedicate a single thread to handling all signals 
     74   * using sigwait. 
     75   */ 
     76#if defined(HAVE_PTHREAD_SIGMASK) || defined(HAVE_SIGPROCMASK) 
    6177  sigset_t old_set; 
    6278  sigset_t new_set; 
     79  int r; 
    6380  sigemptyset(&new_set); 
    6481  sigaddset(&new_set, SIGINT); 
    65   sigprocmask(SIG_BLOCK, &new_set, &old_set); 
     82  sigaddset(&new_set, SIGHUP); 
     83  sigaddset(&new_set, SIGPIPE); 
     84  sigaddset(&new_set, SIGALRM); 
     85  sigaddset(&new_set, SIGCHLD); 
     86 
     87#ifdef HAVE_PTHREAD_SIGMASK 
     88  r = pthread_sigmask(SIG_BLOCK, &new_set, &old_set); 
     89  if (r != 0) 
     90    perror("pthread_sigmask"); 
     91#else 
     92  r = sigprocmask(SIG_BLOCK, &new_set, &old_set); 
     93  if (r != 0) 
     94    perror("sigprocmask"); 
     95#endif 
    6696#endif 
    6797  // Run the single-threaded scheduler 
     
    73103gr_scheduler_thread::stop() 
    74104{ 
    75   if (GR_SCHEDULER_THREAD_DEBUG) 
     105  if (0 && GR_SCHEDULER_THREAD_DEBUG)          // FIXME not safe to call from signal handler 
    76106    std::cout << "gr_scheduler_thread::stop() " 
    77107              << this << std::endl; 
  • gnuradio/trunk/gnuradio-core/src/lib/runtime/gr_top_block.cc

    r6187 r6201  
    4747gr_top_block::~gr_top_block() 
    4848{ 
     49  stop(); 
     50  wait(); 
     51     
    4952  delete d_impl; 
    5053} 
  • gnuradio/trunk/gnuradio-core/src/lib/runtime/gr_top_block.h

    r6187 r6201  
    4848 
    4949  /*! 
    50    * Start the enclosed flowgraph.  Creates an undetached scheduler thread for 
    51    * each flow graph partition. Returns to caller once created. 
     50   * \brief The simple interface to running a flowgraph. 
     51   * 
     52   * Calls start() then wait().  Used to run a flowgraph that will stop 
     53   * on its own, or to run a flowgraph indefinitely until SIGINT is 
     54   * received. 
     55   */ 
     56  void run(); 
     57 
     58  /*! 
     59   * Start the contained flowgraph.  Creates one or more threads to 
     60   * execute the flow graph.  Returns to the caller once the threads 
     61   * are created. 
    5262   */ 
    5363  void start(); 
    5464   
    5565  /*! 
    56    * Stop the running flowgraph.  Tells each created scheduler thread 
    57    * to exit, then returns to caller. 
     66   * Stop the running flowgraph.  Notifies each thread created by the 
     67   * scheduler to shutdown, then returns to caller. 
    5868   */ 
    5969  void stop(); 
    6070 
    6171  /*! 
    62    * Wait for a stopped flowgraph to complete.  Joins each completed 
    63    * thread. 
     72   * Wait for a flowgraph to complete.  Flowgraphs complete when 
     73   * either (1) all blocks indicate that they are done (typically only 
     74   * when using gr.file_source, or gr.head, or (2) after stop() has been 
     75   * called to request shutdown. 
    6476   */ 
    6577  void wait(); 
    66  
    67   /*! 
    68    * Calls start(), then wait().  Used to run a flowgraph that will stop 
    69    * on its own, or to run a flowgraph indefinitely until SIGKILL is 
    70    * received(). 
    71    */ 
    72   void run(); 
    7378 
    7479  /*! 
     
    7782   * will be restarted automatically. 
    7883   * 
    79    * N.B. lock() and unlock() cannot be called from a flowgraph thread or 
    80    * deadlock will occur when reconfiguration happens. 
     84   * N.B. lock() and unlock() cannot be called from a flowgraph thread 
     85   * (E.g., gr_block::work method) or deadlock will occur when 
     86   * reconfiguration happens. 
    8187   */ 
    8288  virtual void lock(); 
     
    8793   * will be restarted automatically. 
    8894   * 
    89    * N.B. lock() and unlock() cannot be called from a flowgraph thread or 
    90    * deadlock will occur when reconfiguration happens. 
     95   * N.B. lock() and unlock() cannot be called from a flowgraph thread 
     96   * (E.g., gr_block::work method) or deadlock will occur when 
     97   * reconfiguration happens. 
    9198   */ 
    9299  virtual void unlock(); 
  • gnuradio/trunk/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc

    r6194 r6201  
    3333#include <stdexcept> 
    3434#include <iostream> 
     35#include <string.h> 
    3536 
    3637#define GR_TOP_BLOCK_IMPL_DEBUG 0 
     
    3839static gr_top_block_impl *s_impl = 0; 
    3940 
    40 // Make a vector of gr_block from a vector of gr_basic_block 
    41 static 
    42 gr_block_vector_t 
    43 make_gr_block_vector(gr_basic_block_vector_t &blocks) 
     41/*! 
     42 * Make a vector of gr_block from a vector of gr_basic_block 
     43 * 
     44 * Pass-by-value to avoid problem with possible asynchronous modification 
     45 */ 
     46static gr_block_vector_t 
     47make_gr_block_vector(gr_basic_block_vector_t blocks) 
    4448{ 
    4549  gr_block_vector_t result; 
     
    5256 
    5357// FIXME: This prevents using more than one gr_top_block instance 
     58 
    5459static void  
    5560runtime_sigint_handler(int signum) 
    5661{ 
    57   if (GR_TOP_BLOCK_IMPL_DEBUG) 
    58     std::cout << "SIGINT received, calling stop()" << std::endl; 
     62  if (GR_TOP_BLOCK_IMPL_DEBUG){ 
     63    char *msg = "SIGINT received, calling stop()\n"; 
     64    ::write(1, msg, strlen(msg));       // write is OK to call from signal handler 
     65  } 
    5966 
    6067  if (s_impl) 
    6168    s_impl->stop(); 
    6269} 
     70 
     71// ---------------------------------------------------------------- 
    6372 
    6473gr_top_block_impl::gr_top_block_impl(gr_top_block *owner)  
     
    6877    d_lock_count(0) 
    6978{ 
     79  if (s_impl) 
     80    throw std::logic_error("gr_top_block_impl: multiple simultaneous gr_top_block's"); 
     81 
    7082  s_impl = this; 
    7183} 
     
    116128} 
    117129 
     130/* 
     131 * N.B. as currently implemented, it is possible that this may be 
     132 * invoked by the SIGINT handler which is fragile as hell... 
     133 */ 
    118134void 
    119135gr_top_block_impl::stop() 
    120136{ 
    121   if (GR_TOP_BLOCK_IMPL_DEBUG) 
    122     std::cout << "stop: entered" << std::endl; 
     137  if (GR_TOP_BLOCK_IMPL_DEBUG){ 
     138    char *msg = "stop: entered\n"; 
     139    ::write(1, msg, strlen(msg)); 
     140  } 
    123141 
    124142  for (gr_scheduler_thread_viter_t p = d_threads.begin(); p != d_threads.end(); p++) { 
    125     if (GR_TOP_BLOCK_IMPL_DEBUG) 
    126       std::cout << "stop: stopping thread " << (*p) << std::endl; 
    127     (*p)->stop(); 
    128   } 
    129  
     143    if (*p) 
     144      (*p)->stop(); 
     145  } 
    130146  d_running = false; 
    131147}