diff --git a/utils/solvers/c++/GmshSocket.h b/utils/solvers/c++/GmshSocket.h index 78641b7f057a8708339642186cb36d3d902682f4..1e1986eec3dff71a14997ce2ff33699fa64f5261 100644 --- a/utils/solvers/c++/GmshSocket.h +++ b/utils/solvers/c++/GmshSocket.h @@ -27,7 +27,6 @@ #ifndef _GMSH_SOCKET_H_ #define _GMSH_SOCKET_H_ -//#include "GmshConfig.h" #include <string> #include <stdio.h> #include <stdlib.h> @@ -62,25 +61,30 @@ class GmshSocket{ // receive data from a machine with a different byte ordering, and // we swap the bytes in the payload) enum MessageType{ - GMSH_START = 1, - GMSH_STOP = 2, - GMSH_INFO = 10, - GMSH_WARNING = 11, - GMSH_ERROR = 12, - GMSH_PROGRESS = 13, - GMSH_MERGE_FILE = 20, - GMSH_PARSE_STRING = 21, - GMSH_VERTEX_ARRAY = 22, - GMSH_PARAMETER = 23, - GMSH_PARAMETER_QUERY = 24, - GMSH_PARAM_QUERY_ALL = 25, - GMSH_PARAM_QUERY_END = 26, - GMSH_SPEED_TEST = 30, - GMSH_OPTION_1 = 100, - GMSH_OPTION_2 = 101, - GMSH_OPTION_3 = 102, - GMSH_OPTION_4 = 103, - GMSH_OPTION_5 = 104}; + GMSH_START = 1, + GMSH_STOP = 2, + GMSH_INFO = 10, + GMSH_WARNING = 11, + GMSH_ERROR = 12, + GMSH_PROGRESS = 13, + GMSH_MERGE_FILE = 20, + GMSH_PARSE_STRING = 21, + GMSH_VERTEX_ARRAY = 22, + GMSH_PARAMETER = 23, + GMSH_PARAMETER_QUERY = 24, + GMSH_PARAMETER_QUERY_ALL = 25, + GMSH_PARAMETER_QUERY_END = 26, + GMSH_CONNECT = 27, + GMSH_OLPARSE = 28, + GMSH_PARAMETER_NOT_FOUND = 29, + GMSH_SPEED_TEST = 30, + GMSH_PARAMETER_CLEAR = 31, + GMSH_PARAMETER_UPDATE = 32, + GMSH_OPTION_1 = 100, + GMSH_OPTION_2 = 101, + GMSH_OPTION_3 = 102, + GMSH_OPTION_4 = 103, + GMSH_OPTION_5 = 104}; protected: // the socket descriptor int _sock; @@ -150,10 +154,10 @@ class GmshSocket{ WSACleanup(); #endif } - // utility function to wait for some data to read on a socket (if - // seconds and microseconds == 0 we check for available data and - // return immediately, i.e., we do polling). Returns 0 when data is - // available. + // Wait for some data to read on the socket (if seconds and microseconds == 0 + // we check for available data and return immediately, i.e., we do + // polling). Returns 1 when data is available, 0 when nothing happened before + // the time delay, -1 on error. int Select(int seconds, int microseconds, int socket=-1) { int s = (socket < 0) ? _sock : socket; @@ -163,8 +167,8 @@ class GmshSocket{ fd_set rfds; FD_ZERO(&rfds); FD_SET(s, &rfds); - // select checks all IO descriptors between 0 and its first arg, - // minus 1... hence the +1 below + // select checks all IO descriptors between 0 and its first arg, minus 1; + // hence the +1 below return select(s + 1, &rfds, NULL, NULL, &tv); } void SendMessage(int type, int length, const void *msg) @@ -195,7 +199,7 @@ class GmshSocket{ int ReceiveHeader(int *type, int *len, int *swap) { *swap = 0; - if(_ReceiveData(type, sizeof(int))){ + if(_ReceiveData(type, sizeof(int)) > 0){ if(*type < 0) return 0; if(*type > 65535){ // the data comes from a machine with different endianness and @@ -203,7 +207,7 @@ class GmshSocket{ *swap = 1; _SwapBytes((char*)type, sizeof(int), 1); } - if(_ReceiveData(len, sizeof(int))){ + if(_ReceiveData(len, sizeof(int)) > 0){ if(*len < 0) return 0; if(*swap) _SwapBytes((char*)len, sizeof(int), 1); return 1; @@ -318,8 +322,10 @@ class GmshServer : public GmshSocket{ public: GmshServer() : GmshSocket(), _portno(-1) {} virtual ~GmshServer(){} - virtual int SystemCall(const char *str) = 0; - virtual int NonBlockingWait(int socket, double waitint, double timeout) = 0; + virtual int NonBlockingSystemCall(const char *str) = 0; + virtual int NonBlockingWait(double waitint, double timeout, int socket=-1) = 0; + // start the client by launching "command" (command is supposed to contain + // '%s' where the socket name should appear) int Start(const char *command, const char *sockname, double timeout) { if(!sockname) throw "Invalid (null) socket name"; @@ -361,7 +367,7 @@ class GmshServer : public GmshSocket{ #if !defined(WIN32) || defined(__CYGWIN__) if(tmpsock < 0) #else - if(tmpsock == INVALID_SOCKET) + if(tmpsock == (int)INVALID_SOCKET) #endif throw "Couldn't create socket"; // bind the socket to its name @@ -376,7 +382,7 @@ class GmshServer : public GmshSocket{ } if(!_portno){ // retrieve name if randomly assigned port socklen_t addrlen = sizeof(addr_in); - int rc = getsockname(tmpsock, (struct sockaddr *)&addr_in, &addrlen); + getsockname(tmpsock, (struct sockaddr *)&addr_in, &addrlen); _portno = ntohs(addr_in.sin_port); int pos = _sockname.find(':'); // remove trailing ' ' or '0' char tmp[256]; @@ -386,13 +392,9 @@ class GmshServer : public GmshSocket{ } if(command && strlen(command)){ - // we assume that the command line always ends with the socket name - std::string cmd(command); - cmd += " " + _sockname; -#if !defined(WIN32) - cmd += " &"; -#endif - SystemCall(cmd.c_str()); // start the solver + char cmd[1024]; + sprintf(cmd, command, _sockname.c_str()); + NonBlockingSystemCall(cmd); // starts the solver } else{ timeout = 0.; // no command launched: don't set a timeout @@ -406,7 +408,7 @@ class GmshServer : public GmshSocket{ } // wait until we get data - int ret = NonBlockingWait(tmpsock, 0.001, timeout); + int ret = NonBlockingWait(0.001, timeout, tmpsock); if(ret){ CloseSocket(tmpsock); if(ret == 2){ diff --git a/utils/solvers/c++/onelab.h b/utils/solvers/c++/onelab.h index 2160cf9513589b80353e9b45df3081d0fa0671ea..e528447c4216bbda603b2e7f57293e3c1ca9d0b2 100644 --- a/utils/solvers/c++/onelab.h +++ b/utils/solvers/c++/onelab.h @@ -1,4 +1,4 @@ -// OneLab - Copyright (C) 2011-2012 ULg-UCL +// OneLab - Copyright (C) 2011-2013 ULg-UCL // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -22,7 +22,8 @@ // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE // OF THIS SOFTWARE. // -// Please report all bugs and problems to the public mailing list <gmsh@geuz.org>. +// Please report all bugs and problems to the public mailing list +// <gmsh@geuz.org>. #ifndef _ONELAB_H_ #define _ONELAB_H_ @@ -630,6 +631,35 @@ namespace onelab{ std::set<string*, parameterLessThan> _strings; std::set<region*, parameterLessThan> _regions; std::set<function*, parameterLessThan> _functions; + // delete a parameter from the parameter space + template <class T> bool _clear(const std::string &name, + const std::string &client, + std::set<T*, parameterLessThan> &ps) + { + if(name.empty() && client.size()){ + for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++){ + T *p = *it; + if(p->hasClient(client)){ + ps.erase(it); + delete p; + } + } + } + else{ + T tmp(name); + typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp); + if(it != ps.end()){ + T *p = *it; + if(client.empty() || p->hasClient(client)){ + ps.erase(it); + delete p; + return true; + } + } + } + return false; + } // set a parameter in the parameter space; if it already exists, update it // (adding new clients if necessary). This needs to be locked to avoid race // conditions when several clients try to set a parameter at the same time. @@ -672,7 +702,7 @@ namespace onelab{ } return true; } - void _getAllParameters(std::set<parameter*> &ps) const + void _getAllParameters(std::set<parameter*, parameterLessThan> &ps) const { ps.insert(_numbers.begin(), _numbers.end()); ps.insert(_strings.begin(), _strings.end()); @@ -682,16 +712,25 @@ namespace onelab{ public: parameterSpace(){} ~parameterSpace(){ clear(); } - void clear() + void clear(const std::string &name="", const std::string &client="") { - std::set<parameter*> ps; - _getAllParameters(ps); - for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) - delete *it; - _numbers.clear(); - _strings.clear(); - _regions.clear(); - _functions.clear(); + if(name.empty() && client.empty()){ + std::set<parameter*, parameterLessThan> ps; + _getAllParameters(ps); + for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++) + delete *it; + _numbers.clear(); + _strings.clear(); + _regions.clear(); + _functions.clear(); + } + else{ + bool done = _clear(name, client, _numbers); + if(!done) done = _clear(name, client, _strings); + if(!done) done = _clear(name, client, _regions); + if(!done) done = _clear(name, client, _functions); + } } bool set(const number &p, const std::string &client=""){ return _set(p, client, _numbers); } @@ -711,14 +750,15 @@ namespace onelab{ const std::string &client=""){ return _get(ps, name, client, _functions); } unsigned int getNumParameters() { - return _numbers.size() + _strings.size() + _regions.size() + _functions.size(); + return (int)(_numbers.size() + _strings.size() + _regions.size() + _functions.size()); } // check if at least one parameter depends on the given client bool hasClient(const std::string &client) const { - std::set<parameter*> ps; + std::set<parameter*, parameterLessThan> ps; _getAllParameters(ps); - for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) + for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++) if((*it)->hasClient(client)) return true; return false; } @@ -726,9 +766,10 @@ namespace onelab{ // parameters that depend on a given client) bool getChanged(const std::string &client="") const { - std::set<parameter*> ps; + std::set<parameter*, parameterLessThan> ps; _getAllParameters(ps); - for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++){ + for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++){ if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged()){ return true; } @@ -739,9 +780,10 @@ namespace onelab{ // parameters that depend on a given client) bool setChanged(bool changed, const std::string &client="") { - std::set<parameter*> ps; + std::set<parameter*, parameterLessThan> ps; _getAllParameters(ps); - for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++) + for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin(); + it != ps.end(); it++) if(client.empty() || (*it)->hasClient(client)) (*it)->setChanged(changed); return true; @@ -751,9 +793,10 @@ namespace onelab{ std::vector<std::string> toChar(const std::string &client="") const { std::vector<std::string> s; - std::set<parameter*> ps; + std::set<parameter*, parameterLessThan> ps; _getAllParameters(ps); - for(std::set<parameter*>::const_iterator it = ps.begin(); it != ps.end(); it++) + for(std::set<parameter*, parameterLessThan>::const_iterator it = ps.begin(); + it != ps.end(); it++) if(client.empty() || (*it)->hasClient(client)) s.push_back((*it)->toChar()); return s; @@ -813,6 +856,7 @@ namespace onelab{ virtual void sendMergeFileRequest(const std::string &msg){} virtual void sendParseStringRequest(const std::string &msg){} virtual void sendVertexArray(const std::string &msg){} + virtual bool clear(const std::string &name) = 0; virtual bool set(const number &p) = 0; virtual bool set(const string &p) = 0; virtual bool set(const region &p) = 0; @@ -889,7 +933,10 @@ namespace onelab{ if(!_server) _server = new server(address); return _server; } - void clear(){ _parameterSpace.clear(); } + void clear(const std::string &name="", const std::string &client="") + { + _parameterSpace.clear(name, client); + } template <class T> bool set(const T &p, const std::string &client="") { return _parameterSpace.set(p, client); @@ -902,7 +949,7 @@ namespace onelab{ typedef std::map<std::string, client*>::iterator citer; citer firstClient(){ return _clients.begin(); } citer lastClient(){ return _clients.end(); } - int getNumClients() { return _clients.size(); }; + int getNumClients() { return (int)_clients.size(); }; citer findClient(const std::string &name){ return _clients.find(name); } void registerClient(client *c) { @@ -962,6 +1009,11 @@ namespace onelab{ { server::instance()->unregisterClient(this); } + virtual bool clear(const std::string &name="") + { + server::instance()->clear(name); + return true; + } virtual bool set(const number &p){ return _set(p); } virtual bool set(const string &p){ return _set(p); } virtual bool set(const function &p){ return _set(p); } @@ -1006,10 +1058,8 @@ namespace onelab{ void setPid(int pid){ _pid = pid; } GmshServer *getGmshServer(){ return _gmshServer; } void setGmshServer(GmshServer *server){ _gmshServer = server; } - #ifndef SWIG - virtual bool run(); - virtual bool kill(); - #endif + virtual bool run() = 0; + virtual bool kill() = 0; }; // The remote part of a network client. @@ -1035,8 +1085,8 @@ namespace onelab{ std::string msg = p.toChar(); if (name.size()) _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY, msg.size(), &msg[0]); - else //get all parameters - _gmshClient->SendMessage(GmshSocket::GMSH_PARAM_QUERY_ALL, msg.size(), &msg[0]); + else // get all parameters + _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY_ALL, msg.size(), &msg[0]); while(1){ // stop if we have no communications for 5 minutes @@ -1065,17 +1115,21 @@ namespace onelab{ ps.push_back(p); return true; } - if(type == GmshSocket::GMSH_PARAM_QUERY_ALL){ + if(type == GmshSocket::GMSH_PARAMETER_QUERY_ALL){ T p; p.fromChar(msg); ps.push_back(p); // do NOT return until all parameters have been downloaded } - else if(type == GmshSocket::GMSH_PARAM_QUERY_END){ + else if(type == GmshSocket::GMSH_PARAMETER_QUERY_END){ + // all parameters have been sent + return true; + } + else if(type == GmshSocket::GMSH_PARAMETER_NOT_FOUND){ + // parameter not found return true; } else if(type == GmshSocket::GMSH_INFO){ - // parameter not found or all aparameters have been sent return true; } else{ @@ -1109,6 +1163,14 @@ namespace onelab{ } GmshClient *getGmshClient(){ return _gmshClient; } virtual bool isNetworkClient(){ return true; } + virtual bool clear(const std::string &name="") + { + if(!_gmshClient) return false; + std::string msg = name; + if(msg.empty()) msg = "*"; + _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_CLEAR, msg.size(), &msg[0]); + return true; + } virtual bool set(const number &p){ return _set(p); } virtual bool set(const string &p){ return _set(p); } virtual bool set(const function &p){ return _set(p); }