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