GNU Radio 3.3.0 C++ API
|
00001 /* -*- c++ -*- */ 00002 /* 00003 * Copyright 2006,2009,2010 Free Software Foundation, Inc. 00004 * 00005 * This file is part of GNU Radio. 00006 * 00007 * GNU Radio is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 3, or (at your option) 00010 * any later version. 00011 * 00012 * GNU Radio is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with GNU Radio; see the file COPYING. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, 00020 * Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #ifndef _CIRCULAR_LINKED_LIST_H_ 00024 #define _CIRCULAR_LINKED_LIST_H_ 00025 00026 #include <gruel/thread.h> 00027 #include <stdexcept> 00028 00029 #define __INLINE__ inline 00030 00031 #ifndef DO_DEBUG 00032 #define DO_DEBUG 0 00033 #endif 00034 00035 #if DO_DEBUG 00036 #define DEBUG(X) do{X} while(0); 00037 #else 00038 #define DEBUG(X) do{} while(0); 00039 #endif 00040 00041 template <class T> class s_both; 00042 00043 template <class T> class s_node 00044 { 00045 typedef s_node<T>* s_node_ptr; 00046 00047 private: 00048 T d_object; 00049 bool d_available; 00050 s_node_ptr d_prev, d_next; 00051 s_both<T>* d_both; 00052 00053 public: 00054 s_node (T l_object, 00055 s_node_ptr l_prev = NULL, 00056 s_node_ptr l_next = NULL) 00057 : d_object (l_object), d_available (TRUE), d_prev (l_prev), 00058 d_next (l_next), d_both (0) {}; 00059 00060 __INLINE__ s_node (s_node_ptr l_prev, s_node_ptr l_next = NULL) { 00061 s_node ((T) NULL, l_prev, l_next); }; 00062 __INLINE__ s_node () { s_node (NULL, NULL, NULL); }; 00063 __INLINE__ ~s_node () {}; 00064 00065 void remove () { 00066 d_prev->next (d_next); 00067 d_next->prev (d_prev); 00068 d_prev = d_next = this; 00069 }; 00070 00071 void insert_before (s_node_ptr l_next) { 00072 if (l_next) { 00073 s_node_ptr l_prev = l_next->prev (); 00074 d_next = l_next; 00075 d_prev = l_prev; 00076 l_prev->next (this); 00077 l_next->prev (this); 00078 } else 00079 d_next = d_prev = this; 00080 }; 00081 00082 void insert_after (s_node_ptr l_prev) { 00083 if (l_prev) { 00084 s_node_ptr l_next = l_prev->next (); 00085 d_prev = l_prev; 00086 d_next = l_next; 00087 l_next->prev (this); 00088 l_prev->next (this); 00089 } else 00090 d_prev = d_next = this; 00091 }; 00092 00093 __INLINE__ T object () { return (d_object); }; 00094 __INLINE__ void object (T l_object) { d_object = l_object; }; 00095 __INLINE__ bool available () { return (d_available); }; 00096 __INLINE__ void set_available () { d_available = TRUE; }; 00097 __INLINE__ void set_available (bool l_avail) { d_available = l_avail; }; 00098 __INLINE__ void set_not_available () { d_available = FALSE; }; 00099 __INLINE__ s_node_ptr next () { return (d_next); }; 00100 __INLINE__ s_node_ptr prev () { return (d_prev); }; 00101 __INLINE__ s_both<T>* both () { return (d_both); }; 00102 __INLINE__ void next (s_node_ptr l_next) { d_next = l_next; }; 00103 __INLINE__ void prev (s_node_ptr l_prev) { d_prev = l_prev; }; 00104 __INLINE__ void both (s_both<T>* l_both) { d_both = l_both; }; 00105 }; 00106 00107 template <class T> class circular_linked_list { 00108 typedef s_node<T>* s_node_ptr; 00109 00110 private: 00111 s_node_ptr d_current, d_iterate, d_available, d_inUse; 00112 size_t d_n_nodes, d_n_used; 00113 gruel::mutex* d_internal; 00114 gruel::condition_variable* d_ioBlock; 00115 00116 public: 00117 circular_linked_list (size_t n_nodes) { 00118 if (n_nodes == 0) 00119 throw std::runtime_error ("circular_linked_list(): n_nodes == 0"); 00120 00121 d_iterate = NULL; 00122 d_n_nodes = n_nodes; 00123 d_n_used = 0; 00124 s_node_ptr l_prev, l_next; 00125 d_inUse = d_current = l_next = l_prev = NULL; 00126 00127 l_prev = new s_node<T> (); 00128 l_prev->set_available (); 00129 l_prev->next (l_prev); 00130 l_prev->prev (l_prev); 00131 if (n_nodes > 1) { 00132 l_next = new s_node<T> (l_prev, l_prev); 00133 l_next->set_available (); 00134 l_next->next (l_prev); 00135 l_next->prev (l_prev); 00136 l_prev->next (l_next); 00137 l_prev->prev (l_next); 00138 if (n_nodes > 2) { 00139 size_t n = n_nodes - 2; 00140 while (n-- > 0) { 00141 d_current = new s_node<T> (l_prev, l_next); 00142 d_current->set_available (); 00143 d_current->prev (l_prev); 00144 d_current->next (l_next); 00145 l_prev->next (d_current); 00146 l_next->prev (d_current); 00147 l_next = d_current; 00148 d_current = NULL; 00149 } 00150 } 00151 } 00152 d_available = d_current = l_prev; 00153 d_ioBlock = new gruel::condition_variable (); 00154 d_internal = new gruel::mutex (); 00155 }; 00156 00157 ~circular_linked_list () { 00158 iterate_start (); 00159 s_node_ptr l_node = iterate_next (); 00160 while (l_node) { 00161 delete l_node; 00162 l_node = iterate_next (); 00163 } 00164 delete d_ioBlock; 00165 d_ioBlock = NULL; 00166 delete d_internal; 00167 d_internal = NULL; 00168 d_available = d_inUse = d_iterate = d_current = NULL; 00169 d_n_used = d_n_nodes = 0; 00170 }; 00171 00172 s_node_ptr find_next_available_node () { 00173 gruel::scoped_lock l (*d_internal); 00174 // find an available node 00175 s_node_ptr l_node = d_available; 00176 DEBUG (std::cerr << "w "); 00177 while (! l_node) { 00178 DEBUG (std::cerr << "x" << std::endl); 00179 // the ioBlock condition will automatically unlock() d_internal 00180 d_ioBlock->wait (l); 00181 // and lock() is here 00182 DEBUG (std::cerr << "y" << std::endl); 00183 l_node = d_available; 00184 } 00185 DEBUG (std::cerr << "::f_n_a_n: #u = " << num_used() 00186 << ", node = " << l_node << std::endl); 00187 // remove this one from the current available list 00188 if (num_available () == 1) { 00189 // last one, just set available to NULL 00190 d_available = NULL; 00191 } else 00192 d_available = l_node->next (); 00193 l_node->remove (); 00194 // add is to the inUse list 00195 if (! d_inUse) 00196 d_inUse = l_node; 00197 else 00198 l_node->insert_before (d_inUse); 00199 d_n_used++; 00200 l_node->set_not_available (); 00201 return (l_node); 00202 }; 00203 00204 void make_node_available (s_node_ptr l_node) { 00205 if (!l_node) return; 00206 gruel::scoped_lock l (*d_internal); 00207 DEBUG (std::cerr << "::m_n_a: #u = " << num_used() 00208 << ", node = " << l_node << std::endl); 00209 // remove this node from the inUse list 00210 if (num_used () == 1) { 00211 // last one, just set inUse to NULL 00212 d_inUse = NULL; 00213 } else 00214 d_inUse = l_node->next (); 00215 l_node->remove (); 00216 // add this node to the available list 00217 if (! d_available) 00218 d_available = l_node; 00219 else 00220 l_node->insert_before (d_available); 00221 d_n_used--; 00222 00223 DEBUG (std::cerr << "s" << d_n_used); 00224 // signal the condition when new data arrives 00225 d_ioBlock->notify_one (); 00226 DEBUG (std::cerr << "t "); 00227 }; 00228 00229 __INLINE__ void iterate_start () { d_iterate = d_current; }; 00230 00231 s_node_ptr iterate_next () { 00232 #if 0 00233 // lock the mutex for thread safety 00234 gruel::scoped_lock l (*d_internal); 00235 #endif 00236 s_node_ptr l_this = NULL; 00237 if (d_iterate) { 00238 l_this = d_iterate; 00239 d_iterate = d_iterate->next (); 00240 if (d_iterate == d_current) 00241 d_iterate = NULL; 00242 } 00243 return (l_this); 00244 }; 00245 00246 __INLINE__ T object () { return (d_current->d_object); }; 00247 __INLINE__ void object (T l_object) { d_current->d_object = l_object; }; 00248 __INLINE__ size_t num_nodes () { return (d_n_nodes); }; 00249 __INLINE__ size_t num_used () { return (d_n_used); }; 00250 __INLINE__ void num_used (size_t l_n_used) { d_n_used = l_n_used; }; 00251 __INLINE__ size_t num_available () { return (d_n_nodes - d_n_used); }; 00252 __INLINE__ void num_used_inc (void) { 00253 if (d_n_used < d_n_nodes) ++d_n_used; 00254 }; 00255 __INLINE__ void num_used_dec (void) { 00256 if (d_n_used != 0) --d_n_used; 00257 // signal the condition that new data has arrived 00258 d_ioBlock->notify_one (); 00259 }; 00260 __INLINE__ bool in_use () { return (d_n_used != 0); }; 00261 }; 00262 00263 template <class T> class s_both 00264 { 00265 private: 00266 s_node<T>* d_node; 00267 void* d_this; 00268 public: 00269 __INLINE__ s_both (s_node<T>* l_node, void* l_this) 00270 : d_node (l_node), d_this (l_this) {}; 00271 __INLINE__ ~s_both () {}; 00272 __INLINE__ s_node<T>* node () { return (d_node); }; 00273 __INLINE__ void* This () { return (d_this); }; 00274 __INLINE__ void set (s_node<T>* l_node, void* l_this) { 00275 d_node = l_node; d_this = l_this;}; 00276 }; 00277 00278 #endif /* _CIRCULAR_LINKED_LIST_H_ */