00001
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <errno.h>
00029 #include <math.h>
00030 #include "gridlabd.h"
00031 #include "comm.h"
00032
00033 unsigned int64 Message::next_id = 0;
00034
00036
00037 Queue::Queue(void)
00038 {
00039 gl_verbose("creating queue %x", this);
00040 first = last = NULL;
00041 }
00042 Queue::~Queue(void)
00043 {
00044 gl_verbose("destroying queue %x", this);
00045 while (first!=NULL)
00046 {
00047 Message *next = first->get_next();
00048 delete first;
00049 first = next;
00050 }
00051 }
00052 void Queue::add(Message *msg)
00053 {
00054
00055 if (first==NULL)
00056 first = last = msg;
00057 else
00058 {
00059 msg->set_prev(last);
00060 last->set_next(msg);
00061 }
00062 msg->set_next(NULL);
00063 gl_verbose("message %"FMT_INT64"d '%-8.8s%s' added to queue %x", msg->get_id(), msg->get_data(), msg->get_size()>8?"...":"", this);
00064 }
00065 Message *Queue::peek(void)
00066 {
00067 return first;
00068 }
00069 Message *Queue::take(Message *msg)
00070 {
00071 if (msg==NULL)
00072 msg = first;
00073 if (msg==NULL)
00074 return NULL;
00075 Message *prev = msg->get_prev();
00076 Message *next = msg->get_next();
00077 if (prev!=NULL)
00078 prev->set_next(next);
00079 else
00080 first = next;
00081 if (next!=NULL)
00082 next->set_prev(prev);
00083 else
00084 last = prev;
00085 return msg;
00086 }
00087 Message *Queue::next(Message *msg)
00088 {
00089 return msg?msg->get_next():first;
00090 }
00091
00092 Message *Queue::drop(Message *msg, bool reverse)
00093 {
00094 Message *prev = msg->get_prev();
00095 Message *next = msg->get_next();
00096 if (msg!=NULL)
00097 delete take(msg);
00098 return reverse?prev:next;
00099 }
00100
00101 TIMESTAMP Queue::next_delivery_time(void)
00102 {
00103 return first ? first->get_deliverytime() : TS_NEVER;
00104 }
00105
00107
00108 CLASS *comm::oclass = NULL;
00109 comm *comm::defaults = NULL;
00110
00111 void comm::route(Message *msg)
00112 {
00113 msg->set_deliverytime((TIMESTAMP)(gl_randomvalue(rtype,a,b)/TS_SECOND)+OBJECTHDR(this)->clock);
00114 DATETIME dt;
00115 char ts[64]="unknown time";
00116 gl_localtime(msg->get_deliverytime(),&dt);
00117 gl_strtime(&dt,ts,sizeof(ts));
00118 gl_verbose("message %"FMT_INT64"d from %x to %x will be delivered at %s", msg->get_id(), msg->get_src(), msg->get_dst(), ts);
00119 queue.add(msg);
00120 }
00121
00122 void comm::route(comm *net, Message *msg)
00123 {
00124 net->queue.add(msg);
00125 }
00126
00128 comm::comm(MODULE *mod)
00129 : queue()
00130 {
00131
00132 if (oclass==NULL)
00133 {
00134
00135 oclass = gl_register_class(mod,"comm",sizeof(comm),PC_PRETOPDOWN);
00136
00137
00138 if (gl_publish_variable(oclass,
00139 PT_char256,"latency", PADDR(latency),
00140 PT_double,"reliability[pu]", PADDR(reliability),
00141 PT_double,"bitrate[b/s]",PADDR(bitrate),
00142 PT_double,"timeout[s]",PADDR(timeout),
00143 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00144
00145
00146 strcpy(latency,"random.degenerate(0)");
00147 reliability=1.0;
00148 bitrate=0.0;
00149 timeout=60;
00150 defaults = this;
00151 }
00152 }
00153
00155 int comm::create()
00156 {
00157
00158 memcpy(this,defaults,sizeof(comm));
00159
00160
00161 return 1;
00162 }
00163
00165 int comm::init(OBJECT *parent)
00166 {
00167 char32 rt;
00168 if (sscanf(latency,"%31[^(](%lf,%lf)",rt,&a,&b)==3)
00169 rtype = gl_randomtype(rt);
00170 else if (sscanf(latency,"%31[^(](%f)",rt,&a)==2)
00171 {
00172 b=0;
00173 rtype = gl_randomtype(rt);
00174 }
00175 else
00176 {
00177 gl_error("latency distribution '%s' is not valid", latency);
00178 return 0;
00179 }
00180
00181 return 1;
00182 }
00183
00185 TIMESTAMP comm::sync(TIMESTAMP t0)
00186 {
00187 if (queue.is_empty())
00188 return TS_NEVER;
00189 Message *msg=NULL;
00190 while ((msg=queue.next(msg))!=NULL)
00191 {
00192 if (msg->get_deliverytime()<=t0)
00193 {
00194 DATETIME dt;
00195 char ts[64]="unknown time";
00196 gl_localtime(t0,&dt);
00197 gl_strtime(&dt,ts,sizeof(ts));
00198 gl_verbose("message %"FMT_INT64"d delivered at %s", msg->get_id(), ts);
00199 queue.take(msg)->get_dst()->deliver(msg);
00200 }
00201 else if (msg->get_deliverytime()<=t0+timeout*TS_SECOND)
00202 {
00203 DATETIME dt;
00204 char ts[64];
00205 gl_localtime(t0,&dt);
00206 gl_strtime(&dt,ts,sizeof(ts));
00207 gl_warning("message %"FMT_INT64"d delivery timeout at %s", msg->get_id(), ts);
00208 msg = queue.drop(msg,true);
00209 }
00210 }
00211 return queue.next_delivery_time();
00212 }
00213
00215
00217 EXPORT int create_comm(OBJECT **obj, OBJECT *parent)
00218 {
00219 *obj = gl_create_object(comm::oclass);
00220 if (*obj!=NULL)
00221 return OBJECTDATA(*obj,comm)->create();
00222 return 0;
00223 }
00224
00225 EXPORT int init_comm(OBJECT *obj)
00226 {
00227 if (obj!=NULL)
00228 return OBJECTDATA(obj,comm)->init(obj->parent);
00229 return 0;
00230 }
00231
00232 EXPORT TIMESTAMP sync_comm(OBJECT *obj, TIMESTAMP t0)
00233 {
00234 TIMESTAMP t1 = OBJECTDATA(obj,comm)->sync(t0);
00235 obj->clock = t0;
00236 return t1;
00237 }
00238
00240
00242