root/juggler/branches/1.0/Environment/vjEnvironmentManager.cpp

Revision 8789, 13.6 kB (checked in by patrickh, 7 years ago)

Copyright update.

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