|
Urbi SDK Remote for C++
2.7.5
|
00001 /* 00002 * Copyright (C) 2005-2011, Gostai S.A.S. 00003 * 00004 * This software is provided "as is" without warranty of any kind, 00005 * either expressed or implied, including but not limited to the 00006 * implied warranties of fitness for a particular purpose. 00007 * 00008 * See the LICENSE file for more information. 00009 */ 00010 00012 00013 #include <iostream> 00014 #include <sstream> 00015 #include <list> 00016 00017 #include <boost/date_time/gregorian/gregorian.hpp> 00018 #include <boost/date_time/posix_time/posix_time.hpp> 00019 00020 #include <libport/containers.hh> 00021 #include <libport/debug.hh> 00022 #include <libport/escape.hh> 00023 #include <libport/foreach.hh> 00024 #include <libport/io-stream.hh> 00025 #include <libport/lexical-cast.hh> 00026 #include <libport/unistd.h> 00027 00028 #include <libport/debug.hh> 00029 #include <libport/format.hh> 00030 00031 #include <liburbi/compatibility.hh> 00032 00033 #include <urbi/uexternal.hh> 00034 #include <urbi/umessage.hh> 00035 #include <urbi/uobject.hh> 00036 #include <urbi/ustarter.hh> 00037 #include <urbi/usyncclient.hh> 00038 #include <urbi/uvalue-serialize.hh> 00039 #include <urbi/uvar.hh> 00040 #include <urbi/ucontext-factory.hh> 00041 #include <libuobject/remote-ucontext-impl.hh> 00042 00043 GD_CATEGORY(Urbi.LibUObject); 00044 00045 #define REQUIRE(Cond, ...) \ 00046 do { \ 00047 if (!(Cond)) \ 00048 { \ 00049 msg.client.printf(__VA_ARGS__); \ 00050 GD_FERROR("Message content: %s", *msg.value); \ 00051 return URBI_CONTINUE; \ 00052 } \ 00053 } while (false) 00054 00055 class HookPoint: public urbi::UObject 00056 { 00057 public: 00058 HookPoint(const std::string&n, urbi::impl::UContextImpl* impl) 00059 : UObject(n, impl) 00060 { 00061 UBindFunction(HookPoint, init); 00062 } 00063 int init() 00064 { 00065 return 1; 00066 } 00067 }; 00068 namespace urbi 00069 { 00070 UObjectMode running_mode() 00071 { 00072 return MODE_REMOTE; 00073 } 00074 00075 namespace impl 00076 { 00077 namespace 00078 { 00081 static 00082 void 00083 eval_call(UTable& t, UList& args) 00084 { 00085 if (UTable::callbacks_type* cs = t.find0(args[1])) 00086 { 00087 args.setOffset(2); 00088 foreach (UGenericCallback* c, *cs) 00089 c->eval(args); 00090 args.setOffset(0); 00091 } 00092 } 00093 } 00094 00095 typedef boost::unordered_map<std::string, impl::UContextImpl*> 00096 contexts_type; 00097 static contexts_type contexts; 00098 00099 impl::UContextImpl* 00100 makeRemoteContext(const std::string& host, const std::string& port) 00101 { 00102 return new impl::RemoteUContextImpl( 00103 new USyncClient(host, lexical_cast<unsigned>(port))); 00104 } 00105 00106 impl::UContextImpl* 00107 getRemoteContext(const std::string& host, const std::string& port) 00108 { 00109 std::string key = host + ':' + port; 00110 contexts_type::iterator i = contexts.find(key); 00111 if (i != contexts.end()) 00112 return i->second; 00113 return contexts[key] = makeRemoteContext(host, port); 00114 } 00115 00116 class SerializedUrbiscriptStreamBuffer: public libport::StreamBuffer 00117 { 00118 public: 00119 SerializedUrbiscriptStreamBuffer(RemoteUContextImpl* backend) 00120 : backend_(backend) 00121 { 00122 } 00123 protected: 00124 virtual size_t read(char*, size_t) 00125 { 00126 return 0; 00127 } 00128 virtual void write(char* buffer, size_t size) 00129 { 00130 int p = size-1; 00131 while (p && (buffer[p]==' ' || buffer[p] == '\n')) --p; 00132 GD_FINFO_TRACE( 00133 "Flushing %s bytes of serialized urbiscript ending with '%s'", size, 00134 buffer[p]); 00135 if (!strchr(",;|&", buffer[p])) 00136 GD_FWARN("Serialized message may be incomplete: %s", 00137 std::string(buffer, size)); 00138 char code = UEM_EVAL; 00139 std::string msg(buffer, size); 00140 backend_->backend_->startPack(); 00141 *backend_->oarchive << code << msg; 00142 backend_->backend_->flush(); 00143 backend_->backend_->endPack(); 00144 } 00145 private: 00146 RemoteUContextImpl* backend_; 00147 }; 00148 /*---------------------. 00149 | RemoteUContextImpl. | 00150 `---------------------*/ 00151 00152 RemoteUContextImpl::RemoteUContextImpl(USyncClient* client) 00153 : backend_(client) 00154 , closed_(false) 00155 , dummyUObject(0) 00156 , enableRTP(true) 00157 , dispatchDepth(0) 00158 , outputStream(client) 00159 , dataSent(false) 00160 , serializationMode(false) 00161 , oarchive(0) 00162 , sharedRTP_(0) 00163 { 00164 rtpSend = 0; 00165 rtpSendGrouped = 0; 00166 hookPointName_ = libport::format("hookPoint_%s_%s", 00167 getFilteredHostname(), 00168 #ifdef __UCLIBC__ 00169 "default" 00170 #else 00171 getpid() 00172 #endif 00173 ); 00174 backend_->setCallback(callback(*this, &RemoteUContextImpl::dispatcher), 00175 externalModuleTag.c_str()); 00176 backend_->setClientErrorCallback(callback(*this, 00177 &RemoteUContextImpl::clientError)); 00178 00179 typedef long long int us_t; 00180 UMessage* m = backend_->syncGet( 00181 "[System.timeReference.year," 00182 "System.timeReference.month," 00183 "System.timeReference.day," 00184 "System.timeReference.us," 00185 // New versions of Urbi register "Urbi" as a component name, 00186 // but keep backward compatibility on "Urbi SDK". So use the 00187 // latter for a good while. 00188 "PackageInfo.components[\"Urbi SDK\"].major," 00189 "PackageInfo.components[\"Urbi SDK\"].minor," 00190 "PackageInfo.components[\"Urbi SDK\"].subMinor," 00191 "PackageInfo.components[\"Urbi SDK\"].patch," 00192 "]" 00193 ); 00194 int year = (*m->value->list)[0]; 00195 int month = (*m->value->list)[1]; 00196 int day = (*m->value->list)[2]; 00197 int us = (*m->value->list)[3]; 00198 version = libport::PackageInfo::Version((*m->value->list)[4], 00199 (*m->value->list)[5], 00200 (*m->value->list)[6], 00201 (*m->value->list)[7]); 00202 // Compatibility for wire protocol 2.3-2.4. 00203 URBI_SEND_COMMAND_C 00204 (*outputStream, 00205 "if (!Object.hasSlot(\"uvalueSerialize\"))\n" 00206 " function Object.uvalueSerialize() { this }"); 00207 // Compatibility for versions < 2.7 00208 URBI_SEND_COMMAND_C 00209 (*outputStream, 00210 "if (!UObject.hasSlot(\"syncGet\"))\n" 00211 " function UObject.syncGet(exp, tag)\n" 00212 " {\n" 00213 " try { Channel.new(tag) << eval(exp) }\n" 00214 " catch (var e) { lobby.send(\"!!! \" + e, tag) }\n" 00215 " }"); 00216 00217 boost::posix_time::ptime now 00218 (boost::posix_time::microsec_clock::local_time()); 00219 boost::posix_time::ptime ref(boost::gregorian::date(year, month, day), 00220 boost::posix_time::microseconds(us)); 00221 libport::utime_reference_set 00222 (libport::utime() - (now - ref).total_microseconds()); 00223 GD_FINFO_DEBUG("Remote kernel reference timestamp: %s.", 00224 to_simple_string(ref)); 00225 GD_FINFO_DEBUG("Remote kernel version: %s", version); 00226 // Connect hookPoint 00227 setCurrentContext(this); 00228 new HookPoint(hookPointName_, const_cast<RemoteUContextImpl*>(this)); 00229 URBI_SEND_COMMAND_C(*outputStream, "var hookPoint = " 00230 + hookPointName_+"|"); 00231 } 00232 00233 RemoteUContextImpl::~RemoteUContextImpl() 00234 {} 00235 00236 std::string RemoteUContextImpl::hookPointName() 00237 { 00238 return hookPointName_; 00239 } 00240 00241 USyncClient* 00242 RemoteUContextImpl::getClient() 00243 { 00244 return backend_; 00245 } 00246 00247 UObject* 00248 RemoteUContextImpl::getDummyUObject() 00249 { 00250 if (!dummyUObject) 00251 dummyUObject = new UObject(0, this); 00252 return dummyUObject; 00253 } 00254 00255 void RemoteUContextImpl::uobject_unarmorAndSend(const char* a) 00256 { 00257 if (!serializationMode) 00258 unarmorAndSend(a, backend_); 00259 else 00260 { 00261 backend_->startPack(); 00262 size_t len = strlen(a); 00263 if (2 <= len && a[0] == '(') 00264 *outputStream << std::string(a+1, len-2); 00265 else 00266 *outputStream << std::string(a, len); 00267 markDataSent(); 00268 backend_->endPack(); 00269 } 00270 } 00271 00272 void RemoteUContextImpl::send(const char* a) 00273 { 00274 if (closed_) 00275 GD_FWARN("Write on closed remote context: \"%s\"", libport::escape(a)); 00276 else 00277 { 00278 backend_->startPack(); 00279 *outputStream << a; 00280 outputStream->flush(); 00281 backend_->endPack(); 00282 } 00283 } 00284 00285 void RemoteUContextImpl::send(const void* buf, size_t size) 00286 { 00287 if (closed_) 00288 GD_FWARN("Write on closed remote context: \"%s\"", 00289 libport::escape(std::string((const char*) buf, size))); 00290 else 00291 { 00292 backend_->startPack(); 00293 outputStream->rdbuf()->sputn(static_cast<const char*> (buf), size); 00294 outputStream->flush(); 00295 backend_->endPack(); 00296 } 00297 } 00298 00299 UObjectMode RemoteUContextImpl::getRunningMode() const 00300 { 00301 return MODE_REMOTE; 00302 } 00303 00304 UTable& 00305 RemoteUContextImpl::tableByName(const std::string& n) 00306 { 00307 #define CHECK(v) if (n == #v) return v##map##_ 00308 CHECK(access); 00309 CHECK(event); 00310 CHECK(eventend); 00311 CHECK(function); 00312 CHECK(monitor); 00313 #undef CHECK 00314 if (n == "var" || n =="var_onrequest") 00315 return monitormap_; 00316 if (n == "varaccess") 00317 return accessmap_; 00318 throw std::runtime_error("unexpected table name: " + n); 00319 } 00320 00321 std::pair<int, int> 00322 RemoteUContextImpl::kernelVersion() const 00323 { 00324 backend_->waitForKernelVersion(true); 00325 return std::make_pair(backend_->kernelMajor(), 00326 backend_->kernelMinor()); 00327 } 00328 00329 void 00330 RemoteUContextImpl::instanciated(UObject*) 00331 { 00332 // Protect our initialization code against rescoping by ','. 00333 send(";"); 00334 } 00335 00336 00337 void 00338 RemoteUContextImpl::lock() 00339 { 00340 } 00341 00342 void 00343 RemoteUContextImpl::unlock() 00344 { 00345 } 00346 00347 boost::asio::io_service& 00348 RemoteUContextImpl::getIoService() 00349 { 00350 return backend_->get_io_service(); 00351 } 00352 00353 /*--------------------. 00354 | RemoteUObjectImpl. | 00355 `--------------------*/ 00356 00357 RemoteUObjectImpl::~RemoteUObjectImpl() 00358 {} 00359 00361 void RemoteUObjectImpl::initialize(UObject* owner) 00362 { 00363 static int uid = 0; 00364 this->owner_ = owner; 00365 RemoteUContextImpl* ctx = dynamic_cast<RemoteUContextImpl*>(owner_->ctx_); 00366 //We were called by UObject base constructor. 00367 period = -1; 00368 if (owner->__name == "_dummy") 00369 return; 00370 bool fromcxx = owner_->__name.empty(); 00371 if (fromcxx) 00372 owner_->__name = "uob_" + getFilteredHostname() + string_cast(++uid); 00373 LockableOstream* client = ctx->outputStream; 00374 URBI_SEND_PIPED_COMMAND_C(*client, 00375 "class " << owner_->__name << "{}"); 00376 URBI_SEND_PIPED_COMMAND_C(*client, 00377 "external object " << owner_->__name); 00378 // Bind update, we need it since we use a dummy message locally generated 00379 // to trigger the periodic call. 00380 createUCallback(*owner, 0, "function", owner, &UObject::update, 00381 owner->__name + ".update"); 00382 00383 // At this point the child class constructor is called, and will 00384 // also send piped commands. 00385 // Then the starter will call instanciated() which will send a semicolon. 00386 // ...unless instanciation was made from c++. 00387 if (fromcxx) 00388 { // Delay calls to register functions until UObject constructor finishes, 00389 // othewrise typeid is wrong. 00390 ctx->addCleanup(boost::bind(&RemoteUContextImpl::instanciated, 00391 ctx, owner)); 00392 ctx->addCleanup(boost::bind(&UContextImpl::registerObject, ctx, owner)); 00393 } 00394 else 00395 owner_->ctx_->registerObject(owner); 00396 } 00397 00399 void 00400 RemoteUObjectImpl::clean() 00401 { 00402 RemoteUContextImpl& ctx = dynamic_cast<RemoteUContextImpl&> 00403 (*(owner_->ctx_)); 00404 00405 if (updateHandler) 00406 { 00407 updateHandler->cancel(); 00408 updateHandler.reset(); 00409 } 00410 00411 ctx.monitormap().clean(owner_->__name); 00412 ctx.accessmap().clean(owner_->__name); 00413 ctx.functionmap().clean(owner_->__name); 00414 ctx.eventmap().clean(owner_->__name); 00415 ctx.eventendmap().clean(owner_->__name); 00416 00417 if (owner_->objecthub) 00418 owner_->objecthub->members.remove(owner_); 00419 } 00420 00421 void 00422 RemoteUObjectImpl::setUpdate(ufloat t) 00423 { 00424 if (updateHandler) 00425 { 00426 updateHandler->cancel(); 00427 updateHandler.reset(); 00428 } 00429 period = t; 00430 onUpdate(); 00431 } 00432 00433 void 00434 RemoteUObjectImpl::onUpdate() 00435 { 00436 if (0 < period) 00437 { 00438 RemoteUContextImpl& ctx = 00439 dynamic_cast<RemoteUContextImpl&>(*(owner_->ctx_)); 00440 UMessage m(*ctx.backend_); 00441 m.type = MESSAGE_DATA; 00442 m.tag = externalModuleTag; 00443 m.value = new UValue(UList()); 00444 m.value->list->push_back(UEM_EVALFUNCTION); 00445 m.value->list->push_back(owner_->__name + ".update__0"); 00446 m.value->list->push_back(""); 00447 // This is potentialy not the worker thread, cannot call dispatcher() 00448 // synchronously. 00449 ctx.getClient()->notifyCallbacks(m); 00450 updateHandler = 00451 libport::asyncCall(boost::bind(&RemoteUObjectImpl::onUpdate, this), 00452 useconds_t(period * 1000)); 00453 } 00454 } 00455 00456 void RemoteUContextImpl::yield() const 00457 { 00458 yield_until(libport::utime()); 00459 } 00460 00461 void RemoteUContextImpl::yield_until(libport::utime_t deadline) const 00462 { 00463 // Ensure processEvents is called at least once. 00464 while (true) 00465 { 00466 bool processed = 00467 dynamic_cast<USyncClient*>(backend_)->processEvents(0); 00468 if (deadline < libport::utime()) 00469 return; 00470 if (!processed) 00471 usleep(0); 00472 } 00473 } 00474 00475 void RemoteUContextImpl::yield_until_things_changed() const 00476 { 00477 while (true) 00478 { 00479 if (dynamic_cast<USyncClient*>(backend_)->processEvents(0)) 00480 return; 00481 usleep(0); 00482 } 00483 } 00484 00485 void RemoteUContextImpl::side_effect_free_set(bool) 00486 {} 00487 00488 bool RemoteUContextImpl::side_effect_free_get() const 00489 { 00490 return false; 00491 } 00492 00493 static void 00494 call_result(RemoteUContextImpl* ctx, std::string var, 00495 const UValue& retval, const std::exception* e) 00496 { 00497 GD_FINFO_DUMP("... dispatch %s done", var); 00498 // var is empty for internally generated messages (such as update()) 00499 if (var.empty()) 00500 return; 00501 // This method can be called by a thread from the Thread Pool because 00502 // it is used as a callback function. Thus we have to declare the 00503 // category for the debugger used by the current thread. 00504 if (e) 00505 { 00506 URBI_SEND_COMMA_COMMAND_C 00507 (*ctx->outputStream, 00508 "Global.UObject.funCall(\"" << var << "\", " 00509 << "Exception.new(\"" 00510 << "Exception while calling remote bound method: " 00511 << libport::escape(e->what()) 00512 << "\"))"); 00513 } 00514 else 00515 { 00516 if (ctx->serializationMode) 00517 { 00518 char type = UEM_REPLY; 00519 ctx->outputStream->flush(); 00520 *ctx->oarchive << type << var << retval; 00521 ctx->backend_->flush(); 00522 } 00523 else 00524 switch (retval.type) 00525 { 00526 case DATA_BINARY: 00527 // Send it 00528 // URBI_SEND_COMMAND does not now how to send binary since it 00529 // depends on the kernel version. 00530 ctx->backend_->startPack(); 00531 *ctx->backend_ << "Global.UObject.funCall(\"" << var << "\", "; 00532 ctx->backend_->send(retval); 00533 *ctx->backend_ << "),\n"; 00534 ctx->backend_->endPack(); 00535 ctx->backend_->flush(); 00536 break; 00537 00538 case DATA_VOID: 00539 URBI_SEND_COMMAND_C 00540 (*ctx->outputStream, 00541 "Global.UObject.funCall(\"" << var << "\")"); 00542 break; 00543 00544 default: 00545 URBI_SEND_COMMA_COMMAND_C 00546 (*ctx->outputStream, 00547 "Global.UObject.funCall(\"" << var << "\", " << retval << ")"); 00548 break; 00549 } 00550 } 00551 } 00552 00553 UCallbackAction 00554 RemoteUContextImpl::dispatcher(const UMessage& msg) 00555 { 00556 if (closed_) 00557 return URBI_CONTINUE; 00558 00559 //check message type 00560 REQUIRE(msg.type == MESSAGE_DATA, 00561 "Component Error: unknown message content, type %d\n", 00562 msg.type); 00563 REQUIRE(msg.value->type == DATA_LIST, 00564 "Component Error: unknown message content, value type %d\n", 00565 msg.value->type); 00566 00567 UList& array = *msg.value->list; 00568 GD_FINFO_DUMP("Dispatching %s, first %s", array, array[0]); 00569 REQUIRE(array[0].type == DATA_DOUBLE, 00570 "Component Error: invalid server message type %d\n", 00571 array[0].type); 00572 00573 FINALLY(((unsigned int& , dispatchDepth)), dispatchDepth--); 00574 dispatchDepth++; 00575 setCurrentContext(this); 00576 switch ((USystemExternalMessage)(int)array[0]) 00577 { 00578 case UEM_ASSIGNVALUE: 00579 REQUIRE(array.size() == 4, 00580 "Component Error: invalid number " 00581 "of arguments in the server message: %lu (expected 4)\n", 00582 static_cast<unsigned long>(array.size())); 00583 assignMessage(array[1], array[2], array[3]); 00584 break; 00585 00586 case UEM_EVALFUNCTION: 00587 REQUIRE(3 <= array.size(), 00588 "Component Error: invalid number " 00589 "of arguments in the server message: %lu\n", 00590 static_cast<unsigned long>(array.size())); 00591 REQUIRE(array[2].type == DATA_STRING, 00592 "Component Error, argument 2 to function call is not a" 00593 "stirng\n"); 00594 evalFunctionMessage(array[1], array[2], array); 00595 break; 00596 00597 case UEM_EMITEVENT: 00598 eval_call(eventmap(), array); 00599 break; 00600 00601 case UEM_ENDEVENT: 00602 eval_call(eventendmap(), array); 00603 break; 00604 00605 case UEM_NEW: 00606 { 00607 impl::UContextImpl::CleanupStack s_(*this); 00608 objects_type::iterator i = objects.find(std::string(array[2])); 00609 REQUIRE(i != objects.end(), 00610 "No such objects %s\n", std::string(array[2]).c_str()); 00611 baseURBIStarter* bsa = i->second->cloner; 00612 REQUIRE(bsa, "Object %s has no cloner", std::string(array[2]).c_str()); 00613 GD_FINFO_DEBUG("instantiating from %s (%s), name: %s", bsa, array[2], 00614 array[1]); 00615 bsa->instanciate(this, (std::string) array[1]); 00616 } 00617 break; 00618 00619 case UEM_DELETE: 00620 { 00621 impl::UContextImpl::CleanupStack s_(*this); 00622 objects_type::iterator i = objects.find(std::string(array[1])); 00623 if (i == objects.end()) 00624 GD_FWARN("delete: no such object: %s", array[1]); 00625 else 00626 { 00627 delete i->second; 00628 objects.erase(i); 00629 if (objects.size() == 1 ) 00630 { 00631 // All the instances have been deleted, except the hookpoint we 00632 // created automaticaly, we're done with this. 00633 // remote. 00634 GD_INFO_TRACE("Last instance deleted, quit"); 00635 exit(0); 00636 } 00637 } 00638 } 00639 break; 00640 00641 case UEM_INIT: 00642 init(); 00643 // switch to binary mode 00644 if (!getenv("URBI_TEXT_MODE") 00645 && version >= libport::PackageInfo::Version(2, 6, 0, 13)) 00646 { 00647 GD_INFO_TRACE("Switching to binary mode"); 00648 setSerializationMode(true); 00649 } 00650 break; 00651 00652 case UEM_TIMER: 00653 { 00654 std::string cbname = array[1]; 00655 TimerMap::iterator i = timerMap.find(cbname); 00656 if (i != timerMap.end()) 00657 i->second.second->call(); 00658 } 00659 break; 00660 00661 case UEM_NORTP: 00662 GD_WARN("Disabling RTP as requested by engine"); 00663 enableRTP = false; 00664 break; 00665 00666 case UEM_SETRTP: 00667 REQUIRE(array.size() == 3, 00668 "Component Error: invalid number " 00669 "of arguments in the server message: %lu (expected 3)\n", 00670 static_cast<unsigned long>(array.size())); 00671 setRTPMessage(array[1], array[2]); 00672 break; 00673 00674 case UEM_SETLOCAL: 00675 { 00676 REQUIRE(array.size() == 3, 00677 "Component Error: invalid number " 00678 "of arguments in the server message: %lu (expected 3)\n", 00679 static_cast<unsigned long>(array.size())); 00680 std::string name = array[1]; 00681 bool state = array[2]; 00682 GD_FINFO_LOG("Set local mode to %s on %s", state, name); 00683 { 00684 libport::BlockLock bl(tableLock); 00685 if (std::list<UVar*> *us = varmap().find0(name)) 00686 { 00687 foreach(UVar* v, *us) 00688 v->set_local(state); 00689 } 00690 } 00691 } 00692 break; 00693 00694 default: 00695 REQUIRE(false, 00696 "Component Error: unknown server message type number %d\n", 00697 (int)array[0]); 00698 } 00699 00700 // Send a terminating ';' since code send by the UObject API uses '|'. 00701 // But only in outermost dispatch call 00702 GD_FINFO_DUMP("Flush check: depth %s, data sent %s", dispatchDepth, 00703 dataSent); 00704 if (dispatchDepth == 1 && dataSent) 00705 { 00706 URBI_SEND_COMMAND_C(*outputStream, ""); 00707 dataSent = false; 00708 } 00709 return URBI_CONTINUE; 00710 } 00711 00712 void 00713 RemoteUContextImpl::assignMessage(const std::string& name, 00714 const UValue& v, time_t ts, 00715 bool bypass, 00716 UValue* val, time_t* timestamp) 00717 { 00718 libport::BlockLock bl(tableLock); 00719 std::list<UVar*> *us = 0; 00720 bool cachedVal = val; 00721 // Fetch storage UValue if it was not given to us 00722 if (!val) 00723 { 00724 us = varmap().find0(name); // Do not make this call if cachedVal 00725 if (us && !us->empty()) 00726 { 00727 // Get first UVarImpl to get pointers to val and timestamp 00728 RemoteUVarImpl* vimpl = 00729 static_cast<RemoteUVarImpl*>(us->front()->impl_); 00730 val = vimpl->value_; 00731 timestamp = vimpl->timestamp_; 00732 } 00733 } 00734 if (val) 00735 { 00736 val->set(v, bypass); 00737 *timestamp = ts; 00738 } 00739 // Process notifyChange 00740 if (UTable::callbacks_type* cs = monitormap().find0(name)) 00741 { 00742 foreach (UGenericCallback *c, *cs) 00743 { 00744 // test of return value here 00745 UList u; 00746 u.array.push_back(new UValue()); 00747 u[0].storage = c->target; 00748 c->eval(u); 00749 } 00750 } 00751 /* Reset val to empty uvalue in bypass mode 00752 * if val was not given to us as argument, maybe it was destroyed since 00753 * we calculated it. So check that at least one UVar is still present. 00754 */ 00755 if (bypass && (cachedVal || (us && !us->empty()))) 00756 { // Reset to void 00757 val->set(UValue()); 00758 } 00759 } 00760 00761 void 00762 RemoteUContextImpl::evalFunctionMessage(const std::string& name, 00763 const std::string& var, 00764 UList& args) 00765 { 00766 GD_FINFO_DUMP("dispatch call %s = %s...", var, name); 00767 UGenericCallback* cb = 0; 00768 { 00769 libport::BlockLock bl(tableLock); 00770 UTable::callbacks_type funs = functionmap()[name]; 00771 UTable::callbacks_type::iterator i = funs.begin(); 00772 if (i == funs.end()) 00773 throw std::runtime_error("no callback found"); 00774 cb = *i; 00775 } 00776 args.setOffset(3); 00777 cb->eval(args, 00778 boost::bind(&call_result, this, var, _1, _2)); 00779 GD_INFO_DUMP("dispatch call over, async call_result"); 00780 } 00781 00782 void 00783 RemoteUContextImpl::setRTPMessage(const std::string& varname, 00784 int state) 00785 { 00786 libport::BlockLock bl(tableLock); 00787 if (std::list<UVar*> *us = varmap().find0(varname)) 00788 { 00789 foreach (UVar* u, *us) 00790 { 00791 u->useRTP(state?UVar::RTP_YES: UVar::RTP_NO); 00792 } 00793 } 00794 } 00795 00796 void 00797 RemoteUContextImpl::newUObjectClass(baseURBIStarter* s) 00798 { 00799 s->instanciate(this); 00800 } 00801 void 00802 RemoteUContextImpl::newUObjectHubClass(baseURBIStarterHub* s) 00803 { 00804 s->instanciate(this); 00805 } 00806 00807 /*---------------------. 00808 | UObjects accessors. | 00809 `---------------------*/ 00810 00811 TimerHandle RemoteUContextImpl::setTimer(UTimerCallback* cb) 00812 { 00813 cb->call(); 00814 libport::AsyncCallHandler h = 00815 libport::asyncCall(boost::bind(&RemoteUContextImpl::onTimer, this, cb), 00816 useconds_t(cb->period * 1000)); 00817 libport::BlockLock bl(mapLock); 00818 std::string cbname = "timer" + string_cast(cb); 00819 timerMap[cbname] = std::make_pair(h, cb); 00820 return TimerHandle(new std::string(cbname)); 00821 } 00822 00823 void 00824 RemoteUContextImpl::onTimer(UTimerCallback* cb) 00825 { 00826 std::string cbname = "timer" + string_cast(cb); 00827 { 00828 libport::BlockLock bl(mapLock); 00829 if (!libport::mhas(timerMap, cbname)) 00830 return; 00831 } 00832 backend_->notifyCallbacks 00833 (UMessage(*backend_, 0, externalModuleTag, 00834 libport::format("[%s,\"%s\"]", UEM_TIMER, cbname))); 00835 00836 libport::BlockLock bl(mapLock); 00837 libport::AsyncCallHandler h = 00838 libport::asyncCall(boost::bind(&RemoteUContextImpl::onTimer, this, cb), 00839 useconds_t(cb->period * 1000)); 00840 timerMap[cbname] = std::make_pair(h, cb); 00841 } 00842 00843 bool 00844 RemoteUObjectImpl::removeTimer(TimerHandle h) 00845 { 00846 if (!h) 00847 return false; 00848 RemoteUContextImpl* ctx = dynamic_cast<RemoteUContextImpl*>(owner_->ctx_); 00849 libport::BlockLock bl(ctx->mapLock); 00850 // Should not happen, but you never know... 00851 if (!libport::mhas(ctx->timerMap, *h)) 00852 return false; 00853 ctx->timerMap[*h].first->cancel(); 00854 ctx->timerMap.erase(*h); 00855 h.reset(); 00856 return true; 00857 } 00858 00859 void 00860 RemoteUContextImpl::call(const std::string& object, 00861 const std::string& method, 00862 UAutoValue v1, 00863 UAutoValue v2, 00864 UAutoValue v3, 00865 UAutoValue v4, 00866 UAutoValue v5, 00867 UAutoValue v6) 00868 { 00869 std::stringstream s; 00870 s << object << "." << method <<"("; 00871 #define CHECK(v) if (v.type != DATA_VOID) s << v << "," 00872 CHECK(v1); CHECK(v2); CHECK(v3); CHECK(v4); 00873 CHECK(v5); CHECK(v6); 00874 #undef CHECK 00875 std::string r = s.str(); 00876 if (v1.type != DATA_VOID) 00877 r = r.substr(0, r.length() - 1); 00878 r += ')'; 00879 URBI_SEND_COMMA_COMMAND_C(*outputStream, r); 00880 markDataSent(); 00881 } 00882 00883 void 00884 RemoteUContextImpl::declare_event(const UEvent* owner) 00885 { 00886 // Event may or may not already exist. 00887 std::string r = "try{var " + owner->get_name() + " = Event.new()}" 00888 " catch(var e) {}"; 00889 URBI_SEND_PIPED_COMMAND_C(*outputStream, r); 00890 markDataSent(); 00891 } 00892 00893 void 00894 RemoteUContextImpl::emit(const std::string& object, 00895 UAutoValue& v1, 00896 UAutoValue& v2, 00897 UAutoValue& v3, 00898 UAutoValue& v4, 00899 UAutoValue& v5, 00900 UAutoValue& v6, 00901 UAutoValue& v7) 00902 { 00903 if (serializationMode) 00904 { 00905 UAutoValue* vals[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7}; 00906 int i = 0; 00907 while (i<7 && vals[i]->type != DATA_VOID) 00908 ++i; 00909 outputStream->flush(); 00910 char code = UEM_EMITEVENT; 00911 *oarchive << code << object << i; 00912 for (int t=0; t<i; ++t) 00913 *oarchive << *(UValue*)vals[t]; 00914 backend_->flush(); 00915 return; 00916 } 00917 std::stringstream s; 00918 s << object << "!("; 00919 #define CHECK(v) if (v.type != DATA_VOID) s << v << "," 00920 CHECK(v1); CHECK(v2); CHECK(v3); CHECK(v4); 00921 CHECK(v5); CHECK(v6); CHECK(v7); 00922 #undef CHECK 00923 std::string r = s.str(); 00924 if (v1.type != DATA_VOID) 00925 r = r.substr(0, r.length() - 1); 00926 r += ')'; 00927 URBI_SEND_COMMAND_C(*outputStream, r); 00928 markDataSent(); 00929 } 00930 00931 UValue 00932 RemoteUContextImpl::localCall(const std::string& object, 00933 const std::string& method, 00934 UAutoValue v1, 00935 UAutoValue v2, 00936 UAutoValue v3, 00937 UAutoValue v4, 00938 UAutoValue v5, 00939 UAutoValue v6, 00940 UAutoValue v7, 00941 UAutoValue v8) 00942 { 00943 UAutoValue* vals[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8}; 00944 int nargs = 0; 00945 while (nargs<8 && vals[nargs]->type != DATA_VOID) 00946 ++nargs; 00947 std::string name = object + "." + method +"__" + string_cast(nargs); 00948 UList l; 00949 { 00950 // We do not copy the UValues, so do not let the UList destroy them. 00951 FINALLY(((UList&, l)), l.array.clear()); 00952 for (int i=0; i<nargs; ++i) 00953 l.array.push_back(vals[i]); 00954 UGenericCallback* cb; 00955 { 00956 libport::BlockLock bl(tableLock); 00957 UTable::callbacks_type tmpfun = functionmap()[name]; 00958 UTable::callbacks_type::iterator tmpfunit = tmpfun.begin(); 00959 if (tmpfunit == tmpfun.end()) 00960 throw std::runtime_error("no callback found for " + object +"::" 00961 + method + " with " + string_cast(nargs) 00962 +" arguments"); 00963 cb = *tmpfunit; 00964 } 00965 return cb->__evalcall(l); 00966 } 00967 } 00968 00969 UVarImpl* 00970 RemoteUContextImpl::getVarImpl() 00971 { 00972 return new RemoteUVarImpl(); 00973 } 00974 00975 UObjectImpl* 00976 RemoteUContextImpl::getObjectImpl() 00977 { 00978 return new RemoteUObjectImpl(); 00979 } 00980 00981 UGenericCallbackImpl* 00982 RemoteUContextImpl::getGenericCallbackImpl() 00983 { 00984 return new RemoteUGenericCallbackImpl(); 00985 } 00986 00987 /*-------------. 00988 | UObjectHub. | 00989 `-------------*/ 00990 00991 void 00992 RemoteUContextImpl::setHubUpdate(UObjectHub*, ufloat) 00993 { 00994 // nothing happend in remote mode... 00995 } 00996 void 00997 RemoteUContextImpl::removeHub(UObjectHub*) 00998 { 00999 } 01000 void 01001 RemoteUContextImpl::registerHub(UObjectHub*) 01002 { 01003 } 01004 01005 UCallbackAction 01006 RemoteUContextImpl::clientError(const UMessage&) 01007 { 01008 GD_INFO_TRACE("clientError on remote context"); 01009 if (closed_) 01010 { 01011 GD_WARN("ClientError already processed"); 01012 return URBI_CONTINUE; 01013 } 01014 impl::UContextImpl::CleanupStack s_(*this); 01015 closed_ = true; 01016 /* Destroy everything 01017 * We must remove each object from the hash right after deleting it 01018 * to prevent getUObject requests on deleted items from dtor of other 01019 * uobjects. 01020 * Clearing first then deleting might make some UObject fail, since 01021 * getUObject would return 0 for perfectly valid and accessible UObjects. 01022 */ 01023 while (!objects.empty()) 01024 { 01025 objects_type::iterator i = objects.begin(); 01026 GD_FINFO_TRACE("Destroying object %s", i->second); 01027 delete i->second; 01028 objects.erase(i); 01029 } 01030 01031 while (!hubs.empty()) 01032 { 01033 hubs_type::iterator i = hubs.begin(); 01034 GD_FINFO_TRACE("Destroying hub %s", i->second); 01035 delete i->second; 01036 hubs.erase(i); 01037 } 01038 return URBI_CONTINUE; 01039 } 01040 01041 void RemoteUContextImpl::setSerializationMode(bool mode) 01042 { 01043 if (mode == serializationMode) 01044 return; 01045 if (!mode) 01046 throw std::runtime_error("Serialization mode can not be undone"); 01047 serializationMode = mode; 01048 // Notify the kernel, in the current mode. 01049 // Do not use call, we must be foreground. 01050 // Do not send any other message until we get a reply. 01051 backend_->lockQueue(); 01052 const char* tag = "remotecontext_setmode"; 01053 send(libport::format("binaryMode(%s, \"%s\");\n", mode, tag)); 01054 delete backend_->waitForTag(tag, 0); 01055 // Change the urbiscript outputstream to one that encapsulates 01056 // in UValue and serializes. 01057 if (mode) 01058 { 01059 if (!oarchive) 01060 oarchive = new libport::serialize::BinaryOSerializer(*backend_); 01061 outputStream = 01062 new LockableOstream(new SerializedUrbiscriptStreamBuffer(this)); 01063 } 01064 else 01065 { 01066 // Reset outputstream to the USyncClient. 01067 delete outputStream->rdbuf(); 01068 delete outputStream; 01069 outputStream = backend_; 01070 } 01071 } 01072 01073 UMessage* 01074 RemoteUContextImpl::syncGet(const std::string& exp, 01075 libport::utime_t timeout) 01076 { 01077 static int counter = 0; 01078 counter++; 01079 std::string tag = "remotecontext_" + string_cast(counter); 01080 backend_->lockQueue(); 01081 call("UObject", "syncGet", exp, tag); 01082 return backend_->waitForTag(tag, timeout); 01083 } 01084 01085 void 01086 RemoteUContextImpl::markDataSent() 01087 { 01088 if (backend_->isCallbackThread() && dispatchDepth) 01089 dataSent = true; 01090 else // we were not called by dispatch: send the terminating ';' ourselve. 01091 URBI_SEND_COMMAND_C((*outputStream), ""); 01092 } 01093 } // namespace urbi::impl 01094 01095 /* 01096 FIXME: find out where it is used 01097 std::string 01098 baseURBIStarter::getFullName(const std::string& name) const 01099 { 01100 if (local) 01101 return name + "_" + getClientConnectionID(outputStream); 01102 else 01103 return name; 01104 }*/ 01105 } // namespace urbi