Urbi SDK Remote for C++  2.7.5
uobject.cc
Go to the documentation of this file.
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