00001 /* 00002 * Copyright (C) 2009, Edmundo Albuquerque de Souza e Silva. 00003 * 00004 * This file may be distributed under the terms of the Q Public License 00005 * as defined by Trolltech AS of Norway and appearing in the file 00006 * LICENSE.QPL included in the packaging of this file. 00007 * 00008 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING 00009 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00010 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, 00011 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 00012 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 00013 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 00014 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 * 00016 * Thanks: Jose Renato Santos 00017 * 00018 */ 00019 00020 /////////////////////////////////////////////////////////////////////////////// 00021 // rioqueue.cpp -- singlely linked fifo queue primitives for pthreads 00022 /////////////////////////////////////////////////////////////////////////////// 00023 00024 // assumes Get only called from a single thread, Put can be called 00025 // from any thread. RioQueueEle is just a single forward link, 00026 // any real use would have more structure after this... 00027 00028 // (Could write a cover class for type safety for a specific element 00029 // (type... 00030 00031 #include <rioqueue.h> 00032 00033 #include <stddef.h> // for offsetof macro 00034 00035 #include <td4list.h> 00036 00037 #include <iostream> 00038 00039 #include "RioError.h" 00040 00041 /////////////////////////////////////////////////////////////////////////////// 00042 RioQueue::RioQueue() 00043 { 00044 m_waitflag = 0; 00045 m_Signal = 0; 00046 m_first = NULL; 00047 m_last = VIRTORG(m_first, RioQueueEle, linkf); 00048 m_sync = NULL; 00049 } 00050 /////////////////////////////////////////////////////////////////////////////// 00051 RioQueue::~RioQueue() 00052 { 00053 } 00054 00055 /////////////////////////////////////////////////////////////////////////////// 00056 // Test - Return true if there is any element available. 00057 bool RioQueue::Test() 00058 { 00059 bool Result; 00060 m_cond.Lock(); 00061 00062 if( (m_sync == 0) && (m_first == 0) ) 00063 Result = false; 00064 else 00065 Result = true; 00066 m_cond.Unlock(); 00067 00068 return Result; 00069 } 00070 00071 /////////////////////////////////////////////////////////////////////////////// 00072 // Put -- add element to end of queue 00073 void RioQueue::Put(RioQueueEle *ep) 00074 { 00075 m_cond.Lock(); 00076 ep->linkf = 0; 00077 m_last->linkf = ep; 00078 m_last = ep; 00079 00080 #ifdef RIO_DEBUG2 00081 // imprime os ponteiros da lista. 00082 RioQueueEle *Elem; 00083 Elem = m_first; 00084 RioErr << "RioQueue::Put ponteiros atualmente na lista: " << hex; 00085 while( Elem != NULL ) 00086 { 00087 RioErr << "0x" << ( unsigned long ) Elem << " "; 00088 Elem = Elem ->linkf; 00089 } 00090 RioErr << endl << ". O ponteiro inserido foi o 0x" << ( unsigned long ) ep 00091 << dec << endl; 00092 #endif 00093 00094 if(m_waitflag) 00095 { 00096 m_cond.Signal(); 00097 m_waitflag = 0; 00098 } 00099 m_cond.Unlock(); 00100 } 00101 00102 00103 /////////////////////////////////////////////////////////////////////////////// 00104 // Get -- Wait for element available on queue and get first one when available 00105 RioQueueEle *RioQueue::Get() 00106 { 00107 RioQueueEle *ep; 00108 00109 while(m_sync == 0) 00110 { 00111 m_cond.Lock(); 00112 00113 #ifdef RIO_DEBUG2 00114 // imprime os ponteiros da lista. 00115 RioQueueEle *Elem; 00116 Elem = m_first; 00117 RioErr << "RioQueue::Get ponteiros atualmente na lista: " << hex; 00118 while( Elem != NULL ) 00119 { 00120 RioErr << "0x" << ( unsigned long ) Elem << " "; 00121 Elem = Elem ->linkf; 00122 } 00123 RioErr << dec << endl; 00124 #endif 00125 00126 while(m_first == 0) 00127 { 00128 if(m_Signal) 00129 { 00130 m_Signal = 0; 00131 m_cond.Unlock(); 00132 return 0; 00133 } 00134 m_waitflag = 1; 00135 m_cond.Wait(); 00136 } 00137 00138 m_sync = m_first; // take whole list on async queue 00139 m_first = 0; 00140 m_last = VIRTORG(m_first, RioQueueEle, linkf); 00141 m_waitflag = 0; 00142 00143 m_cond.Unlock(); 00144 } 00145 00146 ep = m_sync; 00147 m_sync = ep->linkf; 00148 return ep; 00149 } 00150 00151 /////////////////////////////////////////////////////////////////////////////// 00152 // Signal -- Force a thread blocked on Get() to unblock if there is 00153 // such a thread. Get() will return 0 in this case 00154 void RioQueue::Signal() 00155 { 00156 m_cond.Lock(); 00157 if(m_waitflag) 00158 { 00159 // Set flag that causes Get() to stop waiting element and to return a 00160 // null pointer 00161 m_Signal = 1; 00162 // Signal condition variable to unblock thread waiting on Get() 00163 m_cond.Signal(); 00164 m_waitflag = 0; 00165 } 00166 m_cond.Unlock(); 00167 } 00168