Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:59:28

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4VUPLSplitter
0027 //
0028 // Class description:
0029 //
0030 // Utility template class for splitting RW data for thread-safety from classes:
0031 // G4UserPhysicsList, G4VPhysicsConstructor and G4VModularPhysicsList.
0032 // This class implements the split-mechanism for shared objects.
0033 // In the split-class we have an instance of this class and an 'instanceID'.
0034 // Every time in the master thread a new instance of the split-class is
0035 // created, the constructor calls:
0036 //   instanceID = g4vuplsplitter.CreateInstance();
0037 // This creates in memory an "array", pointed by "sharedOffset" of capacity
0038 // "totalspace". The array contains "totalobj" (<=totalspace) instances
0039 // (i.e. the array has un-initialized spaces). Note that also the TLS variables
0040 // "offset" and "workertotalspace" have also the same stuff. When a worker
0041 // thread is started we can call g4vuplsplitter.NewSubInstances(). This will
0042 // simply allocate enough space in the TLS space "offset" and call
0043 // T::initialize() onto the new created methods. Alternatively one can call,
0044 // when the worker thread start, g4vuplsplitter.workerCopySubInstanceArray(),
0045 // that will copy the content of master thread "array" into the TLS one.
0046 // To see this stuff in action see the G4VUserPhysicsList and G4WorkerThread
0047 // classes.
0048 
0049 // Author: Xin Dong, 25 January 2009 - First implementation from
0050 //                                     automatic MT conversion.
0051 // --------------------------------------------------------------------
0052 #ifndef G4VUPLSplitter_hh
0053 #define G4VUPLSplitter_hh 1
0054 
0055 #include "G4AutoLock.hh"
0056 #include "globals.hh"
0057 
0058 #include "rundefs.hh"
0059 #include <stdlib.h>
0060 
0061 template<class T>  // T is the private data from the object to be split
0062 class G4VUPLSplitter
0063 {
0064   public:
0065     G4VUPLSplitter() { G4MUTEXINIT(mutex); }
0066 
0067     // Invoked by the master thread to create a new subinstance
0068     // whenever a new split class instance is created.
0069     // This is called by constructor of shared classes,
0070     // thus only master thread calls this
0071     G4int CreateSubInstance()
0072     {
0073       G4AutoLock l(&mutex);
0074       // One more instance
0075       ++totalobj;
0076       // If the number of objects is larger than the available spaces,
0077       // a re-allocation is needed
0078       if (totalobj > workertotalspace) {
0079         l.unlock();
0080         NewSubInstances();
0081         l.lock();
0082       }
0083       // Since this is called by Master thread, we can remember this
0084       totalspace = workertotalspace;
0085       sharedOffset = offset;
0086       return (totalobj - 1);
0087     }
0088 
0089     // Invoked by each worker thread to grow the subinstance array and
0090     // initialize each new subinstance using a particular method defined
0091     // by the subclass.
0092     void NewSubInstances()
0093     {
0094       G4AutoLock l(&mutex);
0095       if (workertotalspace >= totalobj) {
0096         return;
0097       }
0098       // Remember current large size
0099       G4int originaltotalspace = workertotalspace;
0100       // Increase its size by some value (purely arbitrary)
0101       workertotalspace = totalobj + 512;
0102       // Now re-allocate new space
0103       offset = (T*)realloc(offset, workertotalspace * sizeof(T));
0104       if (offset == nullptr) {
0105         G4Exception("G4VUPLSplitter::NewSubInstances()", "OutOfMemory", FatalException,
0106                     "Cannot malloc space!");
0107         return;
0108       }
0109       // The newly created objects need to be initialized
0110       for (G4int i = originaltotalspace; i < workertotalspace; ++i) {
0111         offset[i].initialize();
0112       }
0113     }
0114 
0115     // Invoked by all threads to free the subinstance array.
0116     void FreeWorker()
0117     {
0118       if (offset == nullptr) {
0119         return;
0120       }
0121       free(offset);
0122       offset = nullptr;
0123     }
0124 
0125     T* GetOffset() { return offset; }
0126 
0127     void UseWorkArea(T* newOffset)
0128     {
0129       // Use recycled work area - which was created previously
0130       if (offset != nullptr && offset != newOffset) {
0131         G4Exception("G4VUPLSplitter::UseWorkspace()", "TwoWorkspaces", FatalException,
0132                     "Thread already has workspace - cannot use another.");
0133       }
0134       offset = newOffset;
0135     }
0136 
0137     T* FreeWorkArea()
0138     {
0139       // Detach this thread from this Location
0140       // The object which calls this method is responsible for it.
0141       //
0142       T* offsetRet = offset;
0143       offset = nullptr;
0144 
0145       return offsetRet;
0146     }
0147 
0148     // Invoked by each worker thread to copy all subinstances array from
0149     // the master thread
0150     void WorkerCopySubInstanceArray()
0151     {
0152       if (offset != nullptr) return;
0153 
0154       // Since this is called by worker threds, totalspace is some valid
0155       // number > 0. Remember totalspace is the number of available slots
0156       // from master. We are sure that it has valid data
0157       G4AutoLock l(&mutex);
0158       offset = (T*)realloc(offset, totalspace * sizeof(T));
0159       if (offset == nullptr) {
0160         G4Exception("G4VUPLSplitter::WorkerCopySubInstanceArray()", "OutOfMemory", FatalException,
0161                     "Cannot malloc space!");
0162         return;
0163       }
0164       // Now just copy from master thread (sharedOffset)
0165       std::memcpy(offset, sharedOffset, totalspace * sizeof(T));
0166     }
0167 
0168   public:
0169     // Per-thread available number of slots
0170     G4RUN_DLL G4ThreadLocalStatic G4int workertotalspace;
0171     // Pointer to first instance of an array
0172     G4RUN_DLL G4ThreadLocalStatic T* offset;
0173 
0174   private:
0175     G4int totalobj = 0;  // Total number of instances from master thread
0176     G4int totalspace = 0;  // Available number of "slots"
0177     T* sharedOffset = nullptr;
0178     G4Mutex mutex;
0179 };
0180 
0181 template<typename T>
0182 G4ThreadLocal G4int G4VUPLSplitter<T>::workertotalspace = 0;
0183 template<typename T>
0184 G4ThreadLocal T* G4VUPLSplitter<T>::offset = nullptr;
0185 
0186 #endif