00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00033 #include <s3fc/s3_periodic_notifier.h>
00034 #include <s3fc/s3_exception.h>
00035
00036 #include <sstream>
00037 #include <algorithm>
00038
00039 #ifdef _WIN32
00040
00041 #define NOMINMAX
00042 #include <wtypes.h>
00043 #include <winbase.h>
00044 #endif
00045
00046 s3_periodic_notifier::event_loop* s3_periodic_notifier::ev_loop = 0;
00047 s3_mutex s3_periodic_notifier::ev_loop_lock;
00048
00049
00050 s3_periodic_notifier::event_loop::event_loop()
00051 {
00052
00053 start();
00054 }
00055
00056
00057 s3_periodic_notifier::event_loop::~event_loop()
00058 {
00059 request_terminate();
00060 wait_on_exit();
00061
00062 }
00063
00064
00065 void s3_periodic_notifier::event_loop::add_client(s3_periodic_notifier* n_id)
00066 {
00067 state_lock.lock();
00068
00069 if ( is_client(n_id) )
00070 {
00071 state_lock.unlock();
00072
00073 std::stringstream str;
00074 str << "Client [" << n_id << "] already in list";
00075 throw s3_generic_exception("s3_periodic_notifier::event_loop::"
00076 "add_client()", str.str());
00077 }
00078
00079 client_list[n_id] = 0;
00080 state_lock.unlock();
00081 }
00082
00083
00084 void s3_periodic_notifier::event_loop::remove_client(s3_periodic_notifier* n_id)
00085 {
00086 state_lock.lock();
00087
00088 if ( ! is_client(n_id) )
00089 {
00090 state_lock.unlock();
00091
00092 std::stringstream str;
00093 str << "Client [" << n_id << "] not in list";
00094 throw s3_generic_exception("s3_periodic_notifier::event_loop::"
00095 "remove_client()", str.str());
00096 }
00097
00098 client_list.erase(n_id);
00099 state_lock.unlock();
00100 }
00101
00102
00103 void s3_periodic_notifier::event_loop::set_period(s3_periodic_notifier* n_id,
00104 const period_t& n_period)
00105 {
00106 state_lock.lock();
00107
00108 if ( ! is_client(n_id) )
00109 {
00110 state_lock.unlock();
00111
00112 std::stringstream str;
00113 str << "Client [" << n_id << "] not in list";
00114 throw s3_generic_exception("s3_periodic_notifier::event_loop::"
00115 "set_period()", str.str());
00116 }
00117
00118 client_list[n_id] = n_period;
00119 state_lock.unlock();
00120 }
00121
00122
00123 bool s3_periodic_notifier::event_loop::clients() const
00124 {
00125 bool c;
00126 state_lock.lock();
00127 c = ( client_list.size() > 0 ) ;
00128 state_lock.unlock();
00129 return c;
00130 }
00131
00132
00133
00134 bool s3_periodic_notifier::event_loop::is_client(s3_periodic_notifier* n_id)
00135 {
00136 return (client_list.count(n_id) != 0);
00137 }
00138
00139
00140 void s3_periodic_notifier::event_loop::main_loop()
00141 {
00142
00143
00144
00145
00146
00147
00148
00149
00150 const int interval_size_ms = 100;
00151
00152 const int interval_size_ns = 1000000 * interval_size_ms;
00153
00154
00155
00156
00157 unsigned long interval_cnt = 0;
00158
00159
00160 long delta_ns;
00161 #ifdef _WIN32
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 DWORD msecs_to_sleep = 0;
00174 #else
00175
00176
00177 timespec ts;
00178 #endif
00179
00180 while(true)
00181 {
00182 if (test_terminate()) break;
00183 #ifdef _WIN32
00184
00185
00186 DWORD current_time = GetTickCount();
00187
00188
00189
00190
00191 msecs_to_sleep = interval_size_ms - (current_time % interval_size_ms);
00192
00193 Sleep(msecs_to_sleep);
00194 #else
00195
00196 clock_gettime(CLOCK_REALTIME, &ts);
00197
00198
00199 delta_ns = interval_size_ns - (ts.tv_nsec % ( interval_size_ns ));
00200
00201
00202 ts.tv_sec = 0;
00203 ts.tv_nsec = delta_ns;
00204 nanosleep(&ts, 0);
00205 #endif
00206
00207 interval_cnt++;
00208
00209
00210 state_lock.lock();
00211 for (list_t::iterator ptr = client_list.begin();
00212 ptr != client_list.end();
00213 ptr++)
00214 {
00215
00216 period_t cp_ms = ptr->second;
00217 if ( cp_ms > 0 )
00218 {
00219 if ((cp_ms/interval_size_ms) == 0)
00220
00221 {
00222 ptr->first->notify();
00223 }
00224
00225 else if ((interval_cnt % (cp_ms/interval_size_ms)) == 0)
00226 {
00227 ptr->first->notify();
00228 }
00229 }
00230 }
00231 state_lock.unlock();
00232 }
00233 }
00234
00235
00236 s3_periodic_notifier::s3_periodic_notifier(period_t n_period_ms) :
00237 period_ms(n_period_ms),
00238 enabled(false)
00239 {
00240 ev_loop_lock.lock();
00241 if ( ev_loop == 0 )
00242 {
00243 ev_loop = new event_loop();
00244 }
00245 ev_loop->add_client(this);
00246 ev_loop->set_period(this, n_period_ms);
00247 ev_loop_lock.unlock();
00248 }
00249
00250
00251
00252 s3_periodic_notifier::~s3_periodic_notifier()
00253 {
00254 ev_loop_lock.lock();
00255 ev_loop->remove_client(this);
00256
00257 if (! ev_loop->clients())
00258 {
00259 delete ev_loop;
00260 ev_loop = 0;
00261 }
00262 ev_loop_lock.unlock();
00263 }
00264
00265
00266 void s3_periodic_notifier::enable()
00267 {
00268 state_lock.lock();
00269 enabled = true;
00270 state_lock.unlock();
00271 }
00272
00273
00274 void s3_periodic_notifier::disable()
00275 {
00276 state_lock.lock();
00277 enabled = false;
00278 state_lock.unlock();
00279 }
00280
00281
00282 void s3_periodic_notifier::set_period(period_t n_period_ms)
00283 {
00284 state_lock.lock();
00285 period_ms = n_period_ms;
00286 ev_loop->set_period(this, n_period_ms);
00287 state_lock.unlock();
00288 }
00289
00290
00291 void s3_periodic_notifier::subscribe(s3_semaphore& sem)
00292 {
00293 state_lock.lock();
00294
00295
00296 if ( is_subscribed(sem) )
00297 {
00298 state_lock.unlock();
00299
00300 std::stringstream str;
00301 str << "Semaphore at [" << &sem << "] already subscribed";
00302 throw s3_generic_exception("s3_periodic_notifier::subscribe()",
00303 str.str());
00304 }
00305 notification_list.push_back(&sem);
00306 state_lock.unlock();
00307 }
00308
00309
00310 void s3_periodic_notifier::unsubscribe(s3_semaphore& sem)
00311 {
00312 state_lock.lock();
00313
00314
00315 if ( ! is_subscribed(sem) )
00316 {
00317 state_lock.unlock();
00318
00319 std::stringstream str;
00320 str << "Semaphore at [" << &sem << "] not subscribed";
00321 throw s3_generic_exception("s3_periodic_notifier::unsubscribe()",
00322 str.str());
00323 }
00324 notification_list.erase(std::find(notification_list.begin(),
00325 notification_list.end(),
00326 &sem));
00327 state_lock.unlock();
00328 }
00329
00330
00331 void s3_periodic_notifier::notify()
00332 {
00333 state_lock.lock();
00334
00335 if ( enabled )
00336 {
00337 for (std::list<s3_semaphore*>::iterator ptr = notification_list.begin();
00338 ptr != notification_list.end();
00339 ptr++)
00340 {
00341 (*ptr)->post();
00342 }
00343 }
00344 state_lock.unlock();
00345 }
00346
00347
00348 bool s3_periodic_notifier::is_subscribed(s3_semaphore& sem){
00349 return ( std::find(notification_list.begin(),
00350 notification_list.end(),
00351 &sem) != notification_list.end() );
00352 }
00353