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