root/juggler/tags/1.0.5/Environment/vjEnvironmentManager.cpp

Revision 7539, 13.5 kB (checked in by anonymous, 7 years ago)

This commit was manufactured by cvs2svn to create tag
'RELENG_1_0_5_RELEASE'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998, 1999, 2000 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  * -----------------------------------------------------------------
26  * File:          $RCSfile$
27  * Date modified: $Date$
28  * Version:       $Revision$
29  * -----------------------------------------------------------------
30  *
31  *************** <auto-copyright.pl END do not edit this line> ***************/
32
33
34 // implementation of Environment Manager
35 //
36 // author: Christopher Just
37
38
39 #include <Environment/vjEnvironmentManager.h>
40 #include <Kernel/vjKernel.h>
41 #include <Environment/vjConnect.h>
42 #include <Performance/vjPerfDataBuffer.h>
43 #include <Config/vjChunkDescDB.h>
44 #include <Config/vjConfigChunkDB.h>
45 #include <Config/vjParseUtil.h>
46 #include <Environment/vjTimedUpdate.h>
47
48 #include <Kernel/vjConfigManager.h>
49
50 vjEnvironmentManager::vjEnvironmentManager():
51                           connections(),
52                           perf_buffers(),
53                           connections_mutex(),
54                           perf_buffers_mutex() {
55
56     /* I want some hardcoded defaults, yes? */
57     Port = 4450;
58     listen_thread = NULL;
59     listen_socket = NULL;
60     configured_to_accept = false;
61     perf_refresh_time = 500;
62
63     perf_target_name = "";
64     perf_target = NULL;
65     current_perf_config = NULL;
66 }
67
68
69
70 vjEnvironmentManager::~vjEnvironmentManager() {
71     rejectConnections();
72     connections_mutex.acquire();
73     killConnections();
74     connections_mutex.release();
75 }
76
77
78
79 bool vjEnvironmentManager::isAccepting() {
80     return (listen_thread != NULL);
81 }
82
83
84
85 void vjEnvironmentManager::addPerfDataBuffer (vjPerfDataBuffer *b) {
86     vjDEBUG (vjDBG_PERFORMANCE, 4) << "EM adding perf data buffer " << b->getName().c_str() << "\n"
87                                    << vjDEBUG_FLUSH;
88     perf_buffers_mutex.acquire();
89     perf_buffers.push_back(b);
90     activatePerfBuffers();
91     perf_buffers_mutex.release();
92 }
93
94
95
96
97 void vjEnvironmentManager::removePerfDataBuffer (vjPerfDataBuffer *b) {
98     std::vector<vjPerfDataBuffer*>::iterator it;
99
100     vjDEBUG (vjDBG_PERFORMANCE, 4) << "EM removing perf data buffer " << b->getName().c_str()
101                                    << "\n" << vjDEBUG_FLUSH;
102
103     perf_buffers_mutex.acquire();
104     b->deactivate();
105     if (perf_target)
106         perf_target->removeTimedUpdate (b);
107     // this is one of those things I really hate:
108     for (it = perf_buffers.begin(); it != perf_buffers.end(); it++) {
109         if (*it == b) {
110             perf_buffers.erase(it);
111             break;
112         }
113     }
114     perf_buffers_mutex.release();
115
116 }
117
118
119
120 //: tells EM that a connection has died (ie by gui disconnecting)
121 //  not for the case of removal by configRemove
122 void vjEnvironmentManager::connectHasDied (vjConnect* con) {
123     std::string s = con->getName();
124
125     connections_mutex.acquire();
126     removeConnect(con);
127     connections_mutex.release();
128     vjConfigManager::instance()->lockActive();
129     vjConfigManager::instance()->getActiveConfig()->removeNamed(s);
130     vjConfigManager::instance()->unlockActive();
131     sendRefresh();
132 }
133
134
135
136 void vjEnvironmentManager::sendRefresh() {
137    connections_mutex.acquire();
138    for (unsigned int i = 0; i < connections.size(); i++) {
139        connections[i]->sendRefresh();
140    }
141    connections_mutex.release();
142 }
143
144
145
146 //: ConfigChunkHandler stuff
147 //! PRE: configCanHandle(chunk) == true
148 //! RETURNS: success
149 bool vjEnvironmentManager::configAdd(vjConfigChunk* chunk) {
150     bool networkingchanged = false;
151     int newport;
152
153     std::string s = chunk->getType();
154     if (!vjstrcasecmp (s, "EnvironmentManager")) {
155         configured_to_accept = chunk->getProperty ("AcceptConnections");
156         newport = chunk->getProperty("Port");
157
158         if (newport == 0)
159             newport = Port;
160         if ((newport != Port) || (configured_to_accept != isAccepting()))
161             networkingchanged = true;
162         perf_target_name = (std::string)chunk->getProperty ("PerformanceTarget");
163         connections_mutex.acquire();
164
165         vjConnect* new_perf_target = getConnect(perf_target_name);
166         if (new_perf_target != perf_target)
167             setPerformanceTarget (NULL);
168
169         if (networkingchanged) {
170             Port = newport;
171             if (isAccepting())
172                 rejectConnections();
173             if (configured_to_accept)
174                 acceptConnections();
175             else
176                 killConnections();
177         }
178         if (new_perf_target)
179             setPerformanceTarget(new_perf_target);
180         connections_mutex.release();
181
182         return true;
183     }
184     else if (!vjstrcasecmp (s, "PerfMeasure")) {
185         current_perf_config = new vjConfigChunk (*chunk);
186         perf_buffers_mutex.acquire();
187         activatePerfBuffers();
188         perf_buffers_mutex.release();
189         return true;
190     }
191     else if (!vjstrcasecmp (s, "FileConnect")) {
192         // I wanted to just look if the fileconnect had been added yet.
193         // however I seem to have a chicken/egg problem.
194         // so the kludge we'll do now is to not directly add a chunk that's
195         // of type VJC_INTERACTIVE. sigh.
196         // Unfortunately, this means that for other cases (such as attaching
197         // to a named pipe) we're still broken
198         if ((int)chunk->getProperty("Mode") != VJC_INTERACTIVE) {
199             // it's new to us
200             vjConnect* vn = new vjConnect (chunk);
201             vjDEBUG (vjDBG_ENV_MGR, 1) << "EM adding connection: " << vn->getName().c_str() << '\n'
202                                        << vjDEBUG_FLUSH;
203             connections_mutex.acquire();
204             connections.push_back (vn);
205             vn->startProcess();
206             if (!vjstrcasecmp (vn->getName(), perf_target_name))
207                 setPerformanceTarget (vn);
208             connections_mutex.release();
209         }
210         return true;
211     }
212     return false;
213 }
214
215
216
217 //: Remove the chunk from the current configuration
218 //! PRE: configCanHandle(chunk) == true
219 //!RETURNS: success
220 bool vjEnvironmentManager::configRemove(vjConfigChunk* chunk) {
221
222     std::string s = chunk->getType();
223     if (!vjstrcasecmp (s, "EnvironmentManager")) {
224         // this could be trouble if the chunk being removed isn't the chunk
225         // we were configured with...
226         rejectConnections();
227         Port = 4450;
228         configured_to_accept = false;
229         return true;
230     }
231     else if (!vjstrcasecmp (s, "PerfMeasure")) {
232         if (current_perf_config) {
233             if (!vjstrcasecmp (current_perf_config->getProperty ("Name"),
234                                chunk->getProperty ("Name"))) {
235                 delete (current_perf_config);
236                 current_perf_config = NULL;
237                 connections_mutex.acquire();
238                 deactivatePerfBuffers ();
239                 connections_mutex.release();
240             }
241         }
242         return true;
243     }
244     else if (!vjstrcasecmp (s, "FileConnect")) {
245         vjDEBUG (vjDBG_ENV_MGR,1) << "EM Removing connection: "
246                                   << chunk->getProperty ("Name") << '\n' << vjDEBUG_FLUSH;
247         connections_mutex.acquire();
248         vjConnect* c = getConnect (chunk->getProperty ("Name"));
249         if (c) {
250             removeConnect (c);
251         }
252         connections_mutex.release();
253         vjDEBUG (vjDBG_ENV_MGR,4) << "EM completed connection removal\n" << vjDEBUG_FLUSH;
254         return true;
255     }
256
257     return false;
258 }
259
260
261
262 //: Can the handler handle the given chunk?
263 //! RETURNS: true - Can handle it
264 //+          false - Can't handle it
265 bool vjEnvironmentManager::configCanHandle(vjConfigChunk* chunk) {
266     std::string s = chunk->getType();
267     return (!vjstrcasecmp (s, "EnvironmentManager") ||
268             !vjstrcasecmp (s, "PerfMeasure") ||
269             !vjstrcasecmp (s, "FileConnect"));
270 }
271
272
273
274 //-------------------- PRIVATE MEMBER FUNCTIONS -------------------------
275
276 // should only be called when we own connections_mutex
277 void vjEnvironmentManager::removeConnect (vjConnect* con) {
278     if (!con)
279         return;
280     if (con == perf_target)
281         setPerformanceTarget (NULL);
282     std::vector<vjConnect*>::iterator i;
283     for (i = connections.begin(); i != connections.end(); i++)
284         if (con == *i) {
285             connections.erase (i);
286             delete con;
287             break;
288         }
289 }
290
291
292
293 // should only be called when we own connections_mutex
294 void vjEnvironmentManager::setPerformanceTarget (vjConnect* con) {
295     if (con == perf_target)
296         return;
297     perf_buffers_mutex.acquire();
298     deactivatePerfBuffers();
299     perf_target = con;
300     activatePerfBuffers();
301     perf_buffers_mutex.release();
302 }
303
304
305
306 // should only be called when we own connections_mutex
307 vjConnect* vjEnvironmentManager::getConnect (const std::string& s) {
308     for (unsigned int i = 0; i < connections.size(); i++)
309         if (s == connections[i]->getName())
310             return connections[i];
311     return NULL;
312 }
313
314
315
316 void vjEnvironmentManager::controlLoop (void* nullParam) {
317     // Child process used to listen for new network connections
318     //struct sockaddr_in servaddr;
319     vjSocket* servsock;
320     //int len;
321     vjConnect* connection;
322
323     vjDEBUG(vjDBG_ENV_MGR,4) << "vjEnvironmentManager started control loop.\n"
324           << vjDEBUG_FLUSH;
325
326     for (;;) {
327         servsock = listen_socket->accept();
328         char name[128];
329         sprintf (name, "Network Connect %d", servsock->getID());
330         connection = new vjConnect (servsock, (std::string)name);
331         connections_mutex.acquire();
332         connections.push_back( connection );
333         connection->startProcess();
334         connections_mutex.release();
335     }
336 }
337
338
339
340 // should only be called while we have the connections mutex...
341 void vjEnvironmentManager::deactivatePerfBuffers () {
342     std::vector<vjPerfDataBuffer*>::iterator i;
343     for (i = perf_buffers.begin(); i != perf_buffers.end(); i++) {
344         (*i)->deactivate();
345         if (perf_target)
346             perf_target->removeTimedUpdate (*i);
347     }
348 }
349
350
351
352 // should only be called while we own connections_mutex
353 void vjEnvironmentManager::activatePerfBuffers () {
354     // activates all perf buffers configured to do so
355     // this is still a bit on the big and bulky side.
356
357     if (perf_buffers.empty())
358         return;
359
360     if (perf_target == NULL || current_perf_config == NULL) {
361         deactivatePerfBuffers();
362         return;
363     }
364
365     std::vector<vjVarValue*> v = current_perf_config->getAllProperties ("TimingTests");
366     std::vector<vjPerfDataBuffer*>::const_iterator b;
367     std::vector<vjVarValue*>::const_iterator val;
368     bool found;
369     vjConfigChunk* ch;
370
371     for (b = perf_buffers.begin(); b != perf_buffers.end(); b++) {
372         found = false;
373         for (val = v.begin(); val != v.end(); val++) {
374             ch = *(*val); // this line demonstrates a subtle danger
375             if ((bool)ch->getProperty ("Enabled")) {
376                 if (!vjstrncasecmp(ch->getProperty("Prefix"), (*b)->getName()))
377                     found = true;
378             }
379         }
380         if (found) {
381             (*b)->activate();
382             perf_target->addTimedUpdate ((*b), perf_refresh_time);
383         }
384         else if ((*b)->isActive()) {
385             (*b)->deactivate();
386             perf_target->removeTimedUpdate (*b);
387         }
388     }
389     for (val = v.begin(); val != v.end(); val++) {
390         delete (*val);
391     }
392
393 }
394
395
396
397 bool vjEnvironmentManager::acceptConnections() {
398
399     if (listen_thread != NULL)
400         return true;
401
402     listen_socket = new vjSocket ();
403     if (!listen_socket->listen (Port)) {
404         vjDEBUG(vjDBG_ERROR,vjDBG_CRITICAL_LVL) <<  clrOutNORM(clrRED,"ERROR:") << "Environment Manager couldn't open socket\n"
405                                                 << vjDEBUG_FLUSH;
406         return false;
407     }
408     else
409         vjDEBUG(vjDBG_ALL,vjDBG_CRITICAL_LVL)
410             << clrOutNORM(clrCYAN, "Environment Manager")
411             << " listening on port " << clrOutNORM(clrMAGENTA, Port) << "\n"
412             << vjDEBUG_FLUSH;
413
414     /* now we ought to spin off a thread to do the listening */
415     vjThreadMemberFunctor<vjEnvironmentManager>* memberFunctor =
416         new vjThreadMemberFunctor<vjEnvironmentManager>(this,
417                                                         &vjEnvironmentManager::controlLoop,
418                                                         NULL);
419     listen_thread = new vjThread (memberFunctor, 0);
420
421
422     return (listen_thread != NULL);
423 }
424
425
426
427
428 bool vjEnvironmentManager::rejectConnections () {
429     if (listen_thread) {
430         listen_thread->kill();
431         listen_thread = NULL;
432         delete listen_socket;
433         listen_socket = 0;
434     }
435     return 1;
436 }
437
438
439
440 // should only be called while we own connections_mutex
441 void vjEnvironmentManager::killConnections() {
442     unsigned int i;
443
444     //connections_mutex.acquire();
445     for (i = 0; i < connections.size(); i++) {
446         connections[i]->stopProcess();
447         delete (connections[i]);
448     }
449     connections.erase (connections.begin(), connections.end());
450     //connections_mutex.release();
451 }
452
453
454
Note: See TracBrowser for help on using the browser.