00001 // 00002 // plumbing - C++ wrapper facades for Berkeley sockets 00003 // Copyright (C) 2009 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify it 00006 // under the terms of the GNU General Public License, version 3, as published 00007 // by the Free Software Foundation. 00008 // 00009 // This program is distributed in the hope that it will be useful, but WITHOUT 00010 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00012 // more details. 00013 // 00014 // You should have received a copy of the GNU General Public License along with 00015 // this program. If not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 #include <algorithm> 00019 00020 #include <libplumbing/at/service.h> 00021 #include <libplumbing/at/job.h> 00022 00023 00024 plumbing::at_service::~at_service() 00025 { 00026 for (queue_t::iterator it = queue.begin(); it != queue.end(); ++it) 00027 { 00028 it->job->death_subscribe(0); 00029 } 00030 } 00031 00032 00033 plumbing::at_service::at_service() 00034 { 00035 } 00036 00037 00038 void 00039 plumbing::at_service::register_job_delta(const time_value &secs, at_job *job) 00040 { 00041 register_job(time_value::now() + secs, job); 00042 } 00043 00044 00045 void 00046 plumbing::at_service::register_job(const time_value &when, at_job *job) 00047 { 00048 // 00049 // We want the job to unregister itself, 00050 // if its destructor is executed. 00051 // 00052 job->death_subscribe(this); 00053 00054 queue_item item; 00055 item.when = when; 00056 item.job = job; 00057 00058 // 00059 // We don't even check to see if it is there twice, because that is 00060 // OK (dumb, but OK). Unless it kills itself. 00061 // 00062 for (queue_t::iterator it = queue.begin(); it != queue.end(); ++it) 00063 { 00064 if (item.when < it->when) 00065 { 00066 queue.insert(it, item); 00067 return; 00068 } 00069 } 00070 queue.push_back(item); 00071 } 00072 00073 00074 void 00075 plumbing::at_service::unregister_job(at_job *job) 00076 { 00077 // 00078 // Recall that a job can be present more than once. We look for 00079 // more than one instance (especially of this is being called 00080 // from the job's destructor). 00081 // 00082 for (;;) 00083 { 00084 queue_t::iterator it = queue.begin(); 00085 for (; it != queue.end(); ++it) 00086 { 00087 if (job == it->job) 00088 break; 00089 } 00090 if (it == queue.end()) 00091 return; 00092 queue.erase(it); 00093 } 00094 } 00095 00096 00097 plumbing::time_value 00098 plumbing::at_service::get_maximum_sleep() 00099 const 00100 { 00101 if (queue.empty()) 00102 return time_value(60); 00103 time_value now = time_value::now(); 00104 00105 // 00106 // Because we keep the queue sorted, we only ever need to look at 00107 // the first job in the queue. 00108 // 00109 time_value when = queue.front().when; 00110 if (when <= now) 00111 return time_value(0); 00112 return (when - now); 00113 } 00114 00115 00116 void 00117 plumbing::at_service::process() 00118 { 00119 for (;;) 00120 { 00121 if (queue.empty()) 00122 return; 00123 00124 // 00125 // Get the current time, and see if first job's time has come. 00126 // 00127 time_value now = time_value::now(); 00128 time_value when = queue.front().when; 00129 if (when > now) 00130 return; 00131 00132 // 00133 // Take the job off the front of the queue *before* we execute 00134 // it. This makes the logic simple to re-register itself, or 00135 // for it to delete itself. 00136 // 00137 queue_item item = queue.front(); 00138 queue.pop_front(); 00139 item.job->process(); 00140 00141 // 00142 // We are not responsible for invoking operator delete on the 00143 // job object. 00144 // 00145 } 00146 } 00147 00148 00149 // vim: ts=4:et