root/juggler/tags/1.0.5/Kernel/vjKernel.cpp

Revision 7539, 17.1 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 #include <vjConfig.h>
35 #include <vjParam.h>
36 #include <string.h>
37 #include <Kernel/vjKernel.h>
38 #include <Kernel/vjDebug.h>
39 #include <Config/vjChunkFactory.h>
40 #include <Kernel/vjConfigManager.h>
41 #include <Threads/vjThread.h>
42 #include <Environment/vjEnvironmentManager.h>
43
44 // Get the system factory we need
45 #if defined(VJ_OS_IRIX) || defined(VJ_OS_Linux) || defined(VJ_OS_AIX) ||   \
46     defined(VJ_OS_Solaris) || defined(VJ_OS_FreeBSD) || defined(VJ_OS_HPUX)
47 #include <Kernel/vjSGISystemFactory.h>
48 #elif defined(VJ_OS_Win32)
49 #include <Kernel/vjWin32SystemFactory.h>
50 #endif
51
52 //vjKernel* vjKernel::_instance = NULL;
53 vjSingletonImp(vjKernel);
54
55 //: Start the Kernel loop running
56 int vjKernel::start()
57 {
58    if(mControlThread != NULL) // Have already started
59    {
60       vjDEBUG(vjDBG_ERROR,0) << clrOutNORM(clrRED,"ERROR:") << "vjKernel::start called when kernel already running\n" << vjDEBUG_FLUSH;
61       vjASSERT(false);
62       exit(0);
63    }
64
65    // Create a new thread to handle the control
66    vjThreadMemberFunctor<vjKernel>* memberFunctor =
67    new vjThreadMemberFunctor<vjKernel>(this, &vjKernel::controlLoop, NULL);
68
69    vjThread* new_thread;   // I set mControlThread in vjKernel::controlLoop
70    new_thread = new vjThread(memberFunctor, 0);
71
72    vjDEBUG(vjDBG_KERNEL,vjDBG_STATE_LVL) << "vjKernel::start: Just started control loop.  "
73                                          << std::endl << vjDEBUG_FLUSH;
74
75    return 1;
76 }
77
78 /// The Kernel loop
79 void vjKernel::controlLoop(void* nullParam)
80 {
81    vjDEBUG(vjDBG_KERNEL,1) << "vjKernel::controlLoop: Started.\n" << vjDEBUG_FLUSH;
82
83    while (0 == vjThread::self())
84    {
85       vjDEBUG(vjDBG_ALL,1) << "vjKernel: Waiting for (thread::self() != NULL)\n" << vjDEBUG_FLUSH;
86       usleep(50);
87    }
88    mControlThread = (vjThread*) vjThread::self();
89
90    vjTimeStamp::initialize();
91    // Do any initial configuration
92    initConfig();
93
94    // setup performance buffer
95    perfBuffer = new vjPerfDataBuffer ("Kernel loop", 500, 8);
96    environmentManager->addPerfDataBuffer (perfBuffer);
97
98    //while(!Exit)
99    while (1)
100    {
101       // Iff we have an app and a draw manager
102       if((mApp != NULL) && (mDrawManager != NULL))
103       {
104             vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: mApp->preFrame()\n" << vjDEBUG_FLUSH;
105          mApp->preFrame();         // PREFRAME: Do Any application pre-draw stuff
106             perfBuffer->set (0);
107             vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: drawManager->draw()\n" << vjDEBUG_FLUSH;
108          mDrawManager->draw();    // DRAW: Trigger the beginning of frame drawing
109          vjASSERT(mSoundManager != NULL);
110          mSoundManager->update();
111             perfBuffer->set (1);
112             vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: mApp->intraFrame()\n" << vjDEBUG_FLUSH;
113          mApp->intraFrame();        // INTRA FRAME: Do computations that can be done while drawing.  This should be for next frame.
114          //usleep(15000);              // Generate a wait in critical section
115             perfBuffer->set (2);
116             vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: drawManager->sync()\n" << vjDEBUG_FLUSH;
117          mSoundManager->sync();
118          mDrawManager->sync();    // SYNC: Block until drawing is done
119             perfBuffer->set (3);
120             vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: mApp->postFrame()\n" << vjDEBUG_FLUSH;
121          mApp->postFrame();        // POST FRAME: Do processing after drawing is complete
122             perfBuffer->set (4);
123       }
124       else
125       {
126          // ??? Should we do this, or just grind up the CPU as fast as possible
127          vjASSERT(NULL != mControlThread);      // If control thread is not set correctly, it will seg fault here
128          mControlThread->yield();   // Give up CPU
129       }
130
131       //usleep(10000);
132       checkForReconfig();        // Check for any reconfiguration that needs done
133
134       perfBuffer->set(5);
135
136          vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: Update Trackers\n" << vjDEBUG_FLUSH;
137       getInputManager()->updateAllData();    // Update the trackers
138          perfBuffer->set(6);
139          vjDEBUG(vjDBG_KERNEL,5) << "vjKernel::controlLoop: Update Projections\n" << vjDEBUG_FLUSH;
140       updateFrameData();         // Update the projections, etc.
141          perfBuffer->set(7);
142    }
143 }
144
145 // Set the application to run
146 // XXX: Should have protection here
147 void vjKernel::setApplication(vjApp* _app)
148 {
149    vjDEBUG(vjDBG_KERNEL,vjDBG_CONFIG_LVL) << "vjKernel::setApplication: New application set\n" << vjDEBUG_FLUSH;
150    mNewApp = _app;
151    mNewAppSet = true;
152 }
153
154
155
156 //: Checks to see if there is reconfiguration to be done
157 //! POST: Any reconfiguration needed has been completed
158 //! NOTE: Can only be called by the kernel thread
159 void vjKernel::checkForReconfig()
160 {
161    vjASSERT(vjThread::self() == mControlThread);      // ASSERT: We are being called from kernel thread
162
163    // ---- RECONFIGURATION --- //
164    int total_chunks_processed(0);
165    int local_chunks_processed(0);
166
167    // This loop will keep processing the pending list
168    // until there is an iteration where no chunks are processed.
169    do
170    {
171       local_chunks_processed = configProcessPending();
172       total_chunks_processed += local_chunks_processed;
173    }
174    while(local_chunks_processed > 0);
175
176    // If we changed the active configuration, then the environment manager needs to refresh
177    if((total_chunks_processed > 0) && (environmentManager != NULL))
178    {
179       environmentManager->sendRefresh();
180    }
181
182    // ---- APP SWITCH ---- //
183    // check for a new applications
184    if(mNewAppSet)
185    {
186       if(mNewApp->depSatisfied())
187       {
188          vjDEBUG(vjDBG_KERNEL,vjDBG_CONFIG_LVL) << "vjKernel: New application dependencies: Satisfied.\n" << vjDEBUG_FLUSH;
189          mNewAppSet = false;
190          changeApplication(mNewApp);
191       }
192       else
193       {
194          vjDEBUG(vjDBG_KERNEL,vjDBG_WARNING_LVL) << "vjKernel: New application dependencies: Not satisfied yet.\n" << vjDEBUG_FLUSH;
195       }
196    }
197 }
198
199 // Changes the application in use
200 //  If there is another app active, it has to stop that
201 //  application first then restart all API specific Managers.
202 //! ARGS: _app - If NULL, stops current application
203 //! NOTE: This can only be called from the kernel thread
204 // app = NULL ==> stop draw manager and null out app
205 // app != NULL ==>
206 //             Get the draw manager needed
207 //             Start it
208 //             Give it the application
209 void vjKernel::changeApplication(vjApp* _app)
210 {
211    vjDEBUG(vjDBG_KERNEL,1) << "vjKernel::changeApplication: Changing to:"
212                            << _app << std::endl << vjDEBUG_FLUSH;
213
214    vjASSERT(vjThread::self() == mControlThread);      // ASSERT: We are being called from kernel thread
215
216    // EXIT Previous application
217    if(mApp != NULL)
218       mApp->exit();
219
220    // SET NEW APPLICATION
221    if(_app != NULL)        // We were given an app
222    {
223       mApp = _app;
224       vjDrawManager* new_draw_mgr = mApp->getDrawManager();
225       vjASSERT(NULL != new_draw_mgr);
226
227       if (new_draw_mgr != mDrawManager)      // Have NEW draw manager
228       {
229          stopDrawManager();                           // Stop old one
230          mDrawManager = mApp->getDrawManager();       // Get the new one
231          startDrawManager(true);                      // Start the new one
232       }
233       else     // SAME draw manager
234       {
235          startDrawManager(false);                     // Start new app
236       }
237    }
238    else                 // No app, clear to NULL
239    {
240       stopDrawManager();
241       mApp = NULL;
242    }
243 }
244
245
246
247 //-----------------------------------------------
248 // Initialize Shared Memory
249 // Load config
250 // Setup Input, Display, and kernel
251 //!NOTE: Does initial configuration and then sends config file to configAdd
252 //!POST: Shared Memory Initialized
253 //----------------------------------------------
254 void vjKernel::initConfig()
255 {
256    vjDEBUG_BEGIN(vjDBG_KERNEL,3) << "vjKernel::initConfig: Setting initial config.\n" << vjDEBUG_FLUSH;
257
258    // --- CREATE SHARED MEMORY --- //
259    vjSharedPool::init();         // Try to init the pool stuff
260    sharedMemPool = new vjSharedPool(1024*1024);      // Create shared memory pool
261
262    // ---- ALLOCATE MANAGERS --- //
263    //initialSetupInputManager();
264    mInputManager = new (sharedMemPool) vjInputManager;
265    //initialSetupDisplayManager();
266    mDisplayManager = vjDisplayManager::instance();  // Get display manager
267    vjASSERT(mDisplayManager != NULL);                 // Did we get an object
268
269    mSoundManager = vjSoundManager::instance();
270    vjASSERT(mSoundManager != NULL);
271
272    //setupEnvironmentManager();
273    environmentManager = new vjEnvironmentManager();
274
275    //??// processPending() // Should I do this here
276
277 #ifdef VJ_OS_IRIX
278    mSysFactory = vjSGISystemFactory::instance(); // XXX: Should not be system specific
279 #elif defined(VJ_OS_Linux) || defined(VJ_OS_Solaris) || defined(VJ_OS_AIX) || \
280       defined(VJ_OS_FreeBSD) || defined(VJ_OS_HPUX)
281    mSysFactory = vjSGISystemFactory::instance(); // HACK - this could be trouble, using SGI factory
282 #elif defined(VJ_OS_Win32)
283    mSysFactory = vjWin32SystemFactory::instance();
284 #else
285    //vjDEBUG(0,0) << "ERROR!: Don't know how to create System Factory!\n" << vjDEBUG_FLUSH;
286    vjASSERT(false);
287 #endif
288
289    vjDEBUG_END(vjDBG_KERNEL,3) << "vjKernel::initConfig: Done.\n" << vjDEBUG_FLUSH;
290 }
291
292
293 void vjKernel::updateFrameData()
294 {
295    // When we have a draw manager, tell it to update it's projections
296    mDisplayManager->updateProjections();
297 }
298
299
300 // -------------------------------
301 // CHUNK Handler
302 // -------------------------------
303 //: Process any pending reconfiguration that we can deal with
304 //
305 //  For all dependant managers, call process pending.
306 //  and call it on our selves
307 int vjKernel::configProcessPending(bool lockIt)
308 {
309    int chunks_processed(0);     // Needs to return this value
310
311    vjConfigManager* cfg_mgr = vjConfigManager::instance();
312    if(cfg_mgr->pendingNeedsChecked())
313    {
314       vjDEBUG_BEGIN(vjDBG_ALL,vjDBG_STATE_LVL) << "vjKernel::configProcessPending: Examining pending list.\n" << vjDEBUG_FLUSH;
315
316       chunks_processed += vjConfigChunkHandler::configProcessPending(lockIt);      // Process kernels pending chunks
317       chunks_processed += getInputManager()->configProcessPending(lockIt);
318       chunks_processed += mDisplayManager->configProcessPending(lockIt);
319       if(NULL != mSoundManager)
320          chunks_processed += mSoundManager->configProcessPending(lockIt);
321       if(NULL != mDrawManager)
322          chunks_processed += mDrawManager->configProcessPending(lockIt);              // XXX: We should not necessarily do this for all draw mgrs
323       if (NULL != environmentManager)
324          chunks_processed += environmentManager->configProcessPending(lockIt);
325       if(NULL != mApp)
326          chunks_processed += mApp->configProcessPending(lockIt);
327
328       vjDEBUG_CONT_END(vjDBG_ALL,vjDBG_CONFIG_LVL) << std::endl
329                                                    << vjDEBUG_FLUSH;
330    }
331    return chunks_processed;
332 }
333
334
335 bool vjKernel::configCanHandle(vjConfigChunk* chunk)
336 {
337    std::string chunk_type = (std::string)chunk->getType();
338
339    if(std::string("JugglerUser") == chunk_type)
340       return true;
341    else
342       return false;
343 }
344
345 bool vjKernel::configAdd(vjConfigChunk* chunk)
346 {
347    std::string chunk_type = (std::string)chunk->getType();
348
349    vjASSERT(configCanHandle(chunk));
350
351    if(std::string("JugglerUser") == chunk_type)
352    {
353       return addUser(chunk);
354    }
355    else
356       return false;
357 }
358
359 bool vjKernel::configRemove(vjConfigChunk* chunk)
360 {
361    std::string chunk_type = (std::string)chunk->getType();
362
363    vjASSERT(configCanHandle(chunk));
364
365    if(std::string("JugglerUser") == chunk_type)
366    {
367       return removeUser(chunk);
368    }
369    else
370       return false;
371 }
372
373 //: Add a new user to the kernel
374 bool vjKernel::addUser(vjConfigChunk* chunk)
375 {
376    vjASSERT((std::string)chunk->getType() == std::string("JugglerUser"));
377
378    vjUser* new_user = new vjUser;
379    bool success = new_user->config(chunk);
380
381    if(!success)
382    {
383       vjDEBUG(vjDBG_CONFIG,vjDBG_CRITICAL_LVL)
384                      << clrOutNORM(clrRED,"ERROR:") << "Failed to add new vjUser: "
385                      << chunk->getProperty("name") << std::endl
386                      << vjDEBUG_FLUSH;
387       delete new_user;
388    }
389    else
390    {
391       vjDEBUG(vjDBG_CONFIG,vjDBG_STATE_LVL)
392                              << "vjKernel: Added new vjUser: "
393                              << new_user->getName().c_str() << std::endl
394                              << vjDEBUG_FLUSH;
395       mUsers.push_back(new_user);
396    }
397
398    return success;
399 }
400
401 // XXX: Not implemented
402 bool vjKernel::removeUser(vjConfigChunk* chunk)
403 {
404    return false;
405 }
406
407 // --- STARTUP ROUTINES --- //
408 void vjKernel::loadConfigFile(std::string filename)
409 {
410    vjDEBUG(vjDBG_KERNEL,vjDBG_CONFIG_LVL) << "Loading config file: "
411                            << filename << std::endl << vjDEBUG_FLUSH;
412
413    vjConfigChunkDB* chunk_db = new vjConfigChunkDB;
414
415    // ------- OPEN Program specified Config file ------ //
416    if(filename.empty())   // We have a filename
417      return;
418
419    bool chunk_db_load_success = chunk_db->load(filename);
420    if (!chunk_db_load_success)
421    {
422      vjDEBUG(vjDBG_ERROR,vjDBG_CRITICAL_LVL) << clrOutNORM(clrRED,"ERROR:")
423         << "vjKernel::loadConfigFile: DB Load failed to load file: "
424         << filename.c_str() << std::endl << vjDEBUG_FLUSH;
425      exit(1);
426    }
427
428    // Put them all in pending
429    vjConfigManager::instance()->addChunkDB(chunk_db);
430
431    //vjDEBUG(vjDBG_KERNEL,5) << "------------  Loaded Config Chunks ----------" << vjDEBUG_FLUSH;
432    //vjDEBUG(vjDBG_KERNEL,5) << (*mInitialChunkDB) << vjDEBUG_FLUSH;
433 }
434
435 //: Load a chunk description file
436 //! POST: The chunk factory can now manage chunks with the given types
437 void vjKernel::loadChunkDescFile(std::string filename)
438 {
439    vjChunkFactory::instance()->loadDescs(filename);
440 }
441
442
443
444 // This starts up the draw manager given
445 //!POST: All processes and data should have been created by draw manager
446 void vjKernel::startDrawManager(bool newMgr)
447 {
448    vjASSERT((mApp != NULL) && (mDrawManager != NULL) && (mDisplayManager != NULL));
449
450    if(newMgr)
451    {
452       //mDrawManager->configInitial(mInitialChunkDB);     // Give it the chunk DB to extract API specific info
453       mDrawManager->setDisplayManager(mDisplayManager);
454       mDrawManager->configProcessPending(true);           // See if there are any config chunks for us
455    }
456    mDrawManager->setApp(mApp);
457
458    mApp->init();                     // Init the app
459    if(newMgr)
460       mDrawManager->initAPI();       // Just sets up API type stuff, possibly starts new processes
461    mApp->apiInit();                  // Have app do any app-init stuff
462    if(newMgr)
463    {
464      mDisplayManager->setDrawManager(mDrawManager);      // This can trigger the update of windows to the draw manager
465    }
466 }
467
468 // Stop the draw manager and close it's resources, then delete it
469 //! POST: draw mgr resources are closed
470 //+       draw mgr is deleted, display manger set to NULL draw mgr
471 void vjKernel::stopDrawManager()
472 {
473    if(mDrawManager != NULL)
474    {
475       mDrawManager->closeAPI();
476       delete mDrawManager;
477       mDrawManager = NULL;
478       mDisplayManager->setDrawManager(NULL);
479    }
480 }
481
482
483 vjUser* vjKernel::getUser(std::string userName)
484 {
485    for(unsigned int i=0;i<mUsers.size();i++)
486       if(userName == mUsers[i]->getName())
487          return mUsers[i];
488
489    return NULL;
490 }
491
492 vjKernel::vjKernel()
493 {
494    mApp = NULL;
495    mNewApp = NULL;
496    mNewAppSet = false;
497    mControlThread = NULL;
498    mSysFactory = NULL;
499    mInputManager = NULL;
500    mDrawManager = NULL;
501    mDisplayManager = NULL;
502    mSoundManager = NULL;
503
504    environmentManager = NULL;
505    perfBuffer = NULL;
506
507    //mInitialChunkDB = NULL;
508    //mChunkDB = NULL;
509
510    sharedMemPool = NULL;
511
512    // Print out the Juggler version number when the kernel is created.
513    vjDEBUG(vjDBG_BASE, 0) << std::string(strlen(VJ_VERSION) + 12, '=')
514                           << std::endl << vjDEBUG_FLUSH;
515    vjDEBUG(vjDBG_BASE, 0) << clrOutNORM(clrGREEN, "VR Juggler: ")
516                           << clrOutNORM(clrGREEN, VJ_VERSION) << clrRESET
517                           << std::endl << vjDEBUG_FLUSH;
518    vjDEBUG(vjDBG_BASE, 0) << std::string(strlen(VJ_VERSION) + 12, '=')
519                           << std::endl << vjDEBUG_FLUSH;
520 }
521
Note: See TracBrowser for help on using the browser.