========================================================================= with Text_IO; with ListPack; with UnChecked_Deallocation; package body ReplicatedWorkers is function "="(x,y : ArchitectureConfig.WorkOrder) return Boolean renames ArchitectureConfig."="; function "="(x,y : ArchitectureConfig.ExecuteSemantics) return Boolean renames ArchitectureConfig."="; function "="(x,y : ArchitectureConfig.CallBackSemantics) return Boolean renames ArchitectureConfig."="; ---------------------------------------------------------------------- -- -- TRANSFORM: -- -- We will see below that WorkerInfo must be considered partially -- static. Therefore, the 'access' to WorkerInfo must be consider -- static. Since the components of the WorkerVector are static, -- the WorkerVector itself must be consider static. -- -- This will be OK, if all the indices of each worker vector -- can be determined statically. -- -- In summary all the declarations below go away (except the -- orginal WorkerInfo record). Also, three WorkerInfo records -- are created, so we migrate these three to compile time. -- -- type WorkerInfo; -- type Worker is access WorkerInfo; -- type WorkerVector is array(Natural range <>) of Worker; type WorkerInfo; AS$1$WorkerInfo : WorkerInfo; AS$2$WorkerInfo : WorkerInfo; AS$3$WorkerInfo : WorkerInfo; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- package WorkPool is new ListPack(WorkType); use WorkPool; procedure Insert(work : in out WorkPool.List; item : in WorkType) is begin -- Insert new element at the front of the list WorkPool.FindIth(work, 1); WorkPool.InsertBefore(work, item); end Insert; procedure Remove(work : in out WorkPool.List; item : out WorkType) is begin if theWorkOrder = ArchitectureConfig.LIFO then -- Remove element from the front of the list WorkPool.FindIth(work, 1); WorkPool.Retrieve(work, item); WorkPool.Delete(work); else -- Remove element from the end of the list WorkPool.FindIth(work, WorkPool.Size(work)); WorkPool.Retrieve(work, item); WorkPool.Delete(work); end if; end Remove; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- protected type WorkLock is entry signal; entry wait; private value : Boolean := TRUE; end WorkLock; protected body WorkLock is entry signal when not value is begin value := TRUE; end signal; entry wait when value is begin value := FALSE; end wait; end WorkLock; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- -- TRANSFORM: -- A task of this type is created once in function Create. So, the -- task type declaration goes away, and we have an anonymous task -- type (AASL p. 816). We will assume that this type (or perhaps -- the associated variable that uses the access type) has been -- annotated to indicated that the dynamically created object -- should be moved to compile time. -- -- Also, tasks with anonymous types cannot have discriminants, -- so we must add a special initiation method which has the -- the discriminant value as a parameter. However, the parameter -- (an access to CollectionInfo) is static, and will therefore be -- removed. Does this mean that we optimize and not introduce -- a new AS$init entry? I think so, but we will leave it in -- for now. -- -- If the original ActivePool type is annotated, this tells us -- that any use of new on that type must go away. Therefore, it -- is impossible to use the associated access declaration (so it -- must go away). If we annotate something else, we probably has to -- come up with some other rules. -- -- task type ActivePool(c : Collection) is -- entry StartUp; -- entry ShutDown; -- entry Get(numItems : in Natural; newWork : in out WorkList; -- done : out Boolean); -- entry Put(newWork : in out WorkList); -- entry GetResult(resultItem : out ResultType); -- entry PutResults(newResults : in out ResultList); -- entry Finished; -- entry Execute; -- entry Complete; -- end ActivePool; -- type ActivePoolAccess is access ActivePool; task AS$ActivePool is entry AS$init; entry StartUp; entry ShutDown; entry Get(numItems : in Natural; newWork : in out WorkList; done : out Boolean); entry Put(newWork : in out WorkList); entry GetResult(resultItem : out ResultType); entry PutResults(newResults : in out ResultList); entry Finished; entry Execute; entry Complete; end AS$ActivePool; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- TRANSFORM: -- A task of this type is created three times in function Create -- (based on unrolling a loop bounded by numWorkers. So, the -- task type declaration goes away, and we have three anonymous task -- type declarations. We will assume that this type (or perhaps -- the associated variable that uses the access type) has been -- annotated to indicated that the dynamically created object -- should be moved to compile time. -- -- We transform as in the task above. Since the Worker type -- is declared to be static, the descriminant goes away again. -- -- task type ActiveWorker(self : Worker) is -- entry StartUp; -- entry ShutDown; -- entry Execute; -- end ActiveWorker; -- type ActiveWorkerAccess is access ActiveWorker; -- task AS$1$ActiveWorker is entry StartUp; entry ShutDown; entry Execute; end ActiveWorker; task AS$2$ActiveWorker is entry StartUp; entry ShutDown; entry Execute; end ActiveWorker; task AS$3$ActiveWorker is entry StartUp; entry ShutDown; entry Execute; end ActiveWorker; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- ---------------------------------------------------------------------- -- TRANSFORM: -- Below we can blindly follow the rule that any declaration that is -- equivalent to access ActiveWorker and acess ActivePool should be -- "removed". All deferences of the fields below should be replaced -- with the associated name generated when "new ActivePool" etc. was -- performed. -- -- Since some fields in WorkerInfo will still be unknown at transformation -- time (while 'aw' and 'ap' will be known), the type must be annotated -- as partially static. This implies that the 'access' in the -- Worker type (= access WorkerInfo) must be static. Thus, all -- WorkerInfo objects will be migrated to compile-time. -- -- The CollectionInfo record must be annotated as partially static -- for similar reasons. Thus the Collection (i.e., access -- CollectionInfo) field below must be annotated as static. Thus -- it will be removed as well. -- -- type WorkerInfo is record -- c : Collection; -- aw : ActiveWorkerAccess; -- ap : ActivePoolAccess; -- work : WorkRef; -- result : ResultRef; -- numIn : Natural; -- end record; type WorkerInfo is record work : WorkRef; result : ResultRef; numIn : Natural; end record; -- TRANSFORM: -- This will no longer be used (since all WorkerInfo objects must -- be migrated to compile-time), and so it can go away. -- procedure WorkerInfoDeallocation is new -- Unchecked_Deallocation(WorkerInfo, Worker); -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- ---------------------------------------------------------------------- -- TRANSFORM: -- As above, the ActivePoolAccess should go away. -- -- type CollectionInfo(max : Natural) is record -- workers : WorkerVector(1..max); -- pool : ActivePoolAccess; -- results : ResultList; -- done : Boolean; -- wl : WorkLock; -- rl : WorkLock; -- end record; -- -- Additionally, the discriminant of this record will bind to -- numWorkers (which is static), so it should be removed (and -- the value of numWorkers inlined for max). -- -- But in fact, the WorkerVector -- is static so it will not appear in the residual type below. -- -- Now since pool and WorkerVector are static, CollectionInfo -- must be annotated as partially static, which means that -- Collection (which is 'access CollectionInfo) must be annotated -- as a static access type to a partially static object (which -- means that we will migrate all CollectionInfo objects to -- compile time). type CollectionInfo is record results : ResultList; done : Boolean; wl : WorkLock; rl : WorkLock; end record; -- TRANSFORM: -- One CollectionInfo object is created in 'Create' procedure, -- so we migrate this to compile time. AS$CollectionInfo : CollectionInfo; -- TRANSFORM: -- No longer needed as above. -- -- procedure CollectionInfoDeallocation is new -- Unchecked_Deallocation(CollectionInfo, Collection); -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- task body ActivePool is executeDone : Boolean := TRUE; waitPhaseWorkers, idleWorkers : Natural; work : WorkPool.List; workCount : Natural; workItem : WorkType; resultItem : ResultType; begin -- TRANSFORM: -- -- discriminant would be passed in new tool-generated entry, -- but the discriminant itself is static. Thus, any references -- to 'c' (the discriminant) is the code below is replaced with -- the symbolic name of the one collection object migrated to -- compile time. accept AS$init; if Debug then text_io.put_line("activepool : starting"); text_io.flush; end if; accept StartUp; WorkPool.Create(work); workCount := 0; Outer: loop if Debug then text_io.put_line("activepool : transition to wait phase"); text_io.flush; end if; loop select accept ShutDown; exit Outer; or accept Finished; accept Shutdown; exit Outer; or accept Put(newWork : in out WorkList) do Remove(newWork, workItem); while workItem /= nullWork loop Insert(work, workItem); workCount := workcount + 1; Remove(newWork, workItem); end loop; end Put; or accept Execute; -- TRANSFORM: -- Replace static discriminant with value (symbolic name of -- CollectionInfo record -- c.done := FALSE; AS$CollectionInfo.done := FALSE; -- TRANSFORM: -- Here we should know that c.max is static (fixed to three), -- thus the for loop will be unrolled. In addition, the -- aw (which is originally type 'access ActiveWorker' can -- be dereferenced to the symbolic name. -- -- for i in 1 .. c.max loop -- c.workers(i).aw.Execute; -- end loop; AS$1$ActiveWorker.Execute; AS$2$ActiveWorker.Execute; AS$3$ActiveWorker.Execute; exit; or accept GetResult(resultItem : out ResultType) do -- TRANSFORM: -- Replace static discriminant with value (symbolic name of -- CollectionInfo record -- Remove(c.results, resultItem); Remove(AS$CollectionInfo.results, resultItem); end GetResult; end select; end loop; if Debug then text_io.put_line("activepool : transition to execute phase"); text_io.flush; end if; executeDone := FALSE; -- TRANSFORM: -- c.max is static, so the RHS of the following assignment gets -- residualized as 3. -- idleWorkers := c.max; idleWorkers := 3; waitPhaseWorkers := 0; -- Repeatedly get work, process it, put new work -- There are two conditions under which the loop is exited: -- -- 1) All workers are idle and there is no work to be done -- -- 2) A workers indicated computation is done and all workers -- are idle. -- -- When wither of these conditions is met the pool begins -- the process of sending workers to their wait phase. -- Upon completion of this the pool enters its wait phase. -- -- It is important to note that the pool-worker protocol begins -- with a get and ends with a put. That is why the idleWorkers -- variable is updated in the accepts of those entries. loop select when (workCount > 0) or executeDone => accept Get(numItems : in Natural; newWork : in out WorkList; done : out Boolean) do if executeDone then done := TRUE; waitPhaseWorkers := waitPhaseWorkers + 1; else done := FALSE; for i in 1 .. numItems loop Remove(work, workItem); exit when workItem = nullWork; workCount := workcount - 1; Insert(newWork, workItem); end loop; idleWorkers := idleWorkers - 1; end if; end Get; or accept Put(newWork : in out WorkList) do Remove(newWork, workItem); while workItem /= nullWork loop Insert(work, workItem); workCount := workcount + 1; Remove(newWork, workItem); end loop; end Put; idleWorkers := idleWorkers + 1; or accept GetResult(resultItem : out ResultType) do -- TRANSFORM: -- Replace static discriminant with value (symbolic name of -- CollectionInfo record -- Remove(c.results, resultItem); Remove(AS$CollectionInfo.results, resultItem); end GetResult; or accept PutResults(newResults : in out ResultList) do Remove(newResults, resultItem); while resultItem /= nullResult loop -- TRANSFORM: -- Replace static discriminant with value (symbolic name of -- CollectionInfo record -- Insert(c.results, resultItem); Insert(AS$CollectionInfo.results, resultItem); Remove(newResults, resultItem); end loop; end PutResults; or accept Finished; executeDone := TRUE; waitPhaseWorkers := waitPhaseWorkers + 1; end select; if Debug then text_io.put_line("activepool : idleWorkers = " & integer'image(idleWorkers) & " and workCount = " & integer'image(workCount) & " and waitPhaseWorkers = " & integer'image(waitPhaseWorkers)) ; text_io.flush; end if; -- TRANSFORM: -- Again, c.max is known... -- if idleWorkers = c.max and workCount=0 then if idleWorkers = 3 and workCount=0 then executeDone := TRUE; end if; -- TRANSFORM: -- Again, c.max is known... -- exit when waitPhaseWorkers = c.max; exit when waitPhaseWorkers = 3; end loop; if theExecuteSemantics = Architectureconfig.Synchronous then accept Complete; end if; -- TRANSFORM: -- Replace static discriminant with value (symbolic name of -- CollectionInfo record -- c.done := TRUE; AS$CollectionInfo.done := TRUE; end loop Outer; if Debug then text_io.put_line("activepool : terminating "); text_io.flush; end if; end ActivePool; -- ---------------------------------------------------------------------- -- TRANSFORM: -- Now we create a new task body for each worker. The discriminant -- value for each worker (self) is propogated into the body. -- ---------------------------------------------------------------------- -- -- -- task body ActiveWorker is -- inWork, genWork : WorkList; -- genResults : ResultList; -- done : Boolean; -- begin -- if Debug then -- text_io.put_line("activeworker : starting up"); -- text_io.flush; -- end if; -- accept StartUp; -- Create(inWork); -- Create(genWork); -- Create(genResults); -- loop -- if Debug then -- text_io.put_line("activeworker : transition to wait phase"); -- text_io.flush; -- end if; -- select accept ShutDown; -- exit; -- or accept Execute; -- end select; -- if Debug then -- text_io.put_line("activeworker : transition to execute phase"); -- text_io.flush; -- end if; -- -- Repeatedly get work, process it, put new work -- loop -- -- Attempt to get new work -- self.ap.Get(self.numIn, inWork, done); -- exit when done; -- -- Perform the work -- if theWorkSemantics = ArchitectureConfig.Exclusive then -- self.c.wl.wait; -- end if; -- self.work(inWork, genWork, genResults, done); -- if theWorkSemantics = ArchitectureConfig.Exclusive then -- self.c.wl.signal; -- end if; -- -- Short-circuit the computation if indicated -- if done then -- self.ap.Finished; -- exit; -- end if; -- -- Process the results -- if theResultSemantics /= ArchitectureConfig.None then -- if theResultSemantics = ArchitectureConfig.Exclusive then -- self.c.rl.wait; -- end if; -- self.result(genResults, done); -- if theResultSemantics = ArchitectureConfig.Exclusive then -- self.c.rl.signal; -- end if; -- -- Short-circuit the computation if indicated -- if done then -- self.ap.Finished; -- exit; -- end if; -- else -- -- save up the results -- self.ap.PutResults(genResults); -- end if; -- -- Put the new work back -- self.ap.Put(genWork); -- end loop; -- end loop; -- Destroy(inWork); -- Destroy(genWork); -- Destroy(genResults); -- if Debug then -- text_io.put_line("activeworker : terminating"); -- text_io.flush; -- end if; -- end ActiveWorker; -- -- -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- task body AS$1$ActiveWorker is inWork, genWork : WorkList; genResults : ResultList; done : Boolean; begin -- TRANSFORM: -- Tool generated entry for descriminant would be added here if -- discriminant were dynamic. -- accept AS$Init(...discriminant...); if Debug then text_io.put_line("activeworker : starting up"); text_io.flush; end if; accept StartUp; Create(inWork); Create(genWork); Create(genResults); loop if Debug then text_io.put_line("activeworker : transition to wait phase"); text_io.flush; end if; select accept ShutDown; exit; or accept Execute; end select; if Debug then text_io.put_line("activeworker : transition to execute phase"); text_io.flush; end if; -- Repeatedly get work, process it, put new work loop -- Attempt to get new work -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool. Also, self is replaced -- with symbolic name. -- self.ap.Get(self.numIn, inWork, done); AS$ActivePool.Get(AS$1$WorkerInfo.numIn, inWork, done); exit when done; -- Perform the work if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- to symbolic name of generated CollectionInfo. -- self.c.wl.wait; AS$CollectionInfo.wl.wait; end if; -- TRANSFORM: -- Dereference of self gets transformed -- self.work(inWork, genWork, genResults, done); AS$1$WorkerInfo.work(inWork, genWork, genResults, done); if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.wl.signal; AS$CollectionInfo.wl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; -- Process the results if theResultSemantics /= ArchitectureConfig.None then if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.wait; AS$CollectionInfo.rl.wait; end if; -- TRANSFORM: -- Dereference of self.c gets transformed -- self.result(genResults, done); AS$1$WorkerInfo.result(genResults, done); if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.signal; AS$Collection.rl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; else -- save up the results -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.PutResults(genResults); AS$ActivePool.PutResults(genResults); end if; -- Put the new work back -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Put(genWork); AS$ActivePool.Put(genWork); end loop; end loop; Destroy(inWork); Destroy(genWork); Destroy(genResults); if Debug then text_io.put_line("activeworker : terminating"); text_io.flush; end if; end AS$1$ActiveWorker; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- task body AS$2$ActiveWorker is inWork, genWork : WorkList; genResults : ResultList; done : Boolean; begin -- TRANSFORM: -- Tool generated entry for descriminant would be added here if -- discriminant were dynamic. -- accept AS$Init(...discriminant...); if Debug then text_io.put_line("activeworker : starting up"); text_io.flush; end if; accept StartUp; Create(inWork); Create(genWork); Create(genResults); loop if Debug then text_io.put_line("activeworker : transition to wait phase"); text_io.flush; end if; select accept ShutDown; exit; or accept Execute; end select; if Debug then text_io.put_line("activeworker : transition to execute phase"); text_io.flush; end if; -- Repeatedly get work, process it, put new work loop -- Attempt to get new work -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool. Also, self is replaced -- with symbolic name. -- self.ap.Get(self.numIn, inWork, done); AS$ActivePool.Get(AS$2$WorkerInfo.numIn, inWork, done); exit when done; -- Perform the work if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- to symbolic name of generated CollectionInfo. -- self.c.wl.wait; AS$CollectionInfo.wl.wait; end if; -- TRANSFORM: -- Dereference of self gets transformed -- self.work(inWork, genWork, genResults, done); AS$2$WorkerInfo.work(inWork, genWork, genResults, done); if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.wl.signal; AS$CollectionInfo.wl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; -- Process the results if theResultSemantics /= ArchitectureConfig.None then if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.wait; AS$CollectionInfo.rl.wait; end if; -- TRANSFORM: -- Dereference of self.c gets transformed -- self.result(genResults, done); AS$2$WorkerInfo.result(genResults, done); if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.signal; AS$Collection.rl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; else -- save up the results -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.PutResults(genResults); AS$ActivePool.PutResults(genResults); end if; -- Put the new work back -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Put(genWork); AS$ActivePool.Put(genWork); end loop; end loop; Destroy(inWork); Destroy(genWork); Destroy(genResults); if Debug then text_io.put_line("activeworker : terminating"); text_io.flush; end if; end AS$2$ActiveWorker; -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- task body AS$3$ActiveWorker is inWork, genWork : WorkList; genResults : ResultList; done : Boolean; begin -- TRANSFORM: -- Tool generated entry for descriminant would be added here if -- discriminant were dynamic. -- accept AS$Init(...discriminant...); if Debug then text_io.put_line("activeworker : starting up"); text_io.flush; end if; accept StartUp; Create(inWork); Create(genWork); Create(genResults); loop if Debug then text_io.put_line("activeworker : transition to wait phase"); text_io.flush; end if; select accept ShutDown; exit; or accept Execute; end select; if Debug then text_io.put_line("activeworker : transition to execute phase"); text_io.flush; end if; -- Repeatedly get work, process it, put new work loop -- Attempt to get new work -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool. Also, self is replaced -- with symbolic name. -- self.ap.Get(self.numIn, inWork, done); AS$ActivePool.Get(AS$3$WorkerInfo.numIn, inWork, done); exit when done; -- Perform the work if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- to symbolic name of generated CollectionInfo. -- self.c.wl.wait; AS$CollectionInfo.wl.wait; end if; -- TRANSFORM: -- Dereference of self gets transformed -- self.work(inWork, genWork, genResults, done); AS$3$WorkerInfo.work(inWork, genWork, genResults, done); if theWorkSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.wl.signal; AS$CollectionInfo.wl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; -- Process the results if theResultSemantics /= ArchitectureConfig.None then if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.wait; AS$CollectionInfo.rl.wait; end if; -- TRANSFORM: -- Dereference of self.c gets transformed -- self.result(genResults, done); AS$3$WorkerInfo.result(genResults, done); if theResultSemantics = ArchitectureConfig.Exclusive then -- TRANSFORM: -- Dereference of self.c gets transformed -- self.c.rl.signal; AS$Collection.rl.signal; end if; -- Short-circuit the computation if indicated if done then -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Finished; AS$ActivePool.Finished; exit; end if; else -- save up the results -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.PutResults(genResults); AS$ActivePool.PutResults(genResults); end if; -- Put the new work back -- TRANSFORM: -- Dereference of ap (type 'access ActivePool') gets transformed -- to symbolic name of generated ActivePool -- self.ap.Put(genWork); AS$ActivePool.Put(genWork); end loop; end loop; Destroy(inWork); Destroy(genWork); Destroy(genResults); if Debug then text_io.put_line("activeworker : terminating"); text_io.flush; end if; end AS$3$ActiveWorker; -- ---------------------------------------------------------------------- -- TRANSFORM: -- numWorkers parameter to Create is static and will get specialized -- away. Note that the discriminant to CollectionInfo goes away -- as noted in the transformed declaration of CollectionInfo. -- Calls to 'new' for ActivePool and ActiveWorker's get transformed -- into tool generated AS$init calls. Loops bounded by -- numWorkers get unrolled. -- function Create(numWorkers : Natural; -- work : WorkRef; result : resultRef; -- numIn : Natural := 1) return Collection is -- newCollection : Collection; -- begin -- newCollection := new CollectionInfo(numWorkers); -- Create(newCollection.results); -- newCollection.done := TRUE; -- -- Create and initialize the active entities in the collection -- newCollection.pool := new ActivePool(newCollection); -- for i in 1..numWorkers loop -- newCollection.workers(i) := new WorkerInfo; -- newCollection.workers(i).c := newCollection; -- newCollection.workers(i).aw := new ActiveWorker(newCollection.workers(i)) ; -- newCollection.workers(i).ap := newCollection.pool; -- newCollection.workers(i).work := work; -- newCollection.workers(i).result := result; -- newCollection.workers(i).numIn := numIn; -- end loop; -- -- Start up the active entities in the collection -- newCollection.pool.StartUp; -- for i in 1..numWorkers loop -- newCollection.workers(i).aw.Startup; -- end loop; -- return newCollection; -- end Create; function Create( -- numWorkers : Natural; ...parameter is static work : WorkRef; result : resultRef; numIn : Natural := 1) return Collection is newCollection : Collection; begin -- TRANSFORM: -- Migrate CollectionInfo to compile time. Discriminant is static. -- The compile-time declaration is given toward the top of the -- code. -- newCollection := new CollectionInfo(numWorkers); -- TRANSFORM: -- CollectionInfo is migrated to compile-time so inline symbolic -- name. -- Create(newCollection.results); -- newCollection.done := TRUE; Create(AS$CollectionInfo.results); AS$CollectionInfo.done := TRUE; -- TRANSFORM: -- migrate ActivePool to compile time. -- Create and initialize the active entities in the collection -- newCollection.pool := new ActivePool(newCollection); -- TRANSFORM: -- unroll loop, calls to new ActiveWorker go away, -- CollectionInfo and WorkerInfo objects have been -- migrated to compile-time, WorkerVector is static so entries -- are split (indexing disappears). -- for i in 1..numWorkers loop -- newCollection.workers(i) := new WorkerInfo; -- newCollection.workers(i).c := newCollection; -- newCollection.workers(i).aw := new ActiveWorker(newCollection.workers(i)) ; -- newCollection.workers(i).ap := newCollection.pool; -- newCollection.workers(i).work := work; -- newCollection.workers(i).result := result; -- newCollection.workers(i).numIn := numIn; -- end loop; -- i = 1 AS$1$WorkerInfo.work := work; AS$1$WorkerInfo.result := result; AS$1$WorkerInfo.numIn := numIn; -- i = 2 AS$2$WorkerInfo.work := work; AS$2$WorkerInfo.result := result; AS$2$WorkerInfo.numIn := numIn; -- i = 3 AS$3$WorkerInfo.work := work; AS$3$WorkerInfo.result := result; AS$3$WorkerInfo.numIn := numIn; -- Start up the active entities in the collection -- TRANSFORM: -- Dereference of ActivePool yields symbolic name... -- newCollection.pool.StartUp; AS$ActivePool.StartUp; -- TRANSFORM: -- unroll loop bounded by numWorkers, and dereference aw yields -- symbolic name of active worker. -- -- for i in 1..numWorkers loop -- newCollection.workers(i).aw.Startup; -- end loop; AS$1$ActiveWorker.Startup; AS$2$ActiveWorker.Startup; AS$3$ActiveWorker.Startup; -- TRANSFORM: -- I don't know what to do here. The pointer to newCollection -- has gone away. ??? -- -- return newCollection; end Create; -- TRANSFORM: -- Procedure declaration is modified since CollectionInfo migrates -- to compile-time -- procedure Destroy(c : in out Collection) is procedure Destroy is begin -- Finish the computation if one is in progress -- TRANSFORM: -- Dereference of ActivePool yields symbolic name... -- c.pool.Finished; AS$ActivePool.Finished; -- Shut down all of the active componenents of the collection -- TRANSFORM: -- unroll loop, dereference of 'aw' yields symbolic name... -- for i in 1..c.max loop -- c.workers(i).aw.ShutDown; -- end loop; AS$1$ActiveWorker.ShutDown; AS$2$ActiveWorker.ShutDown; AS$3$ActiveWorker.ShutDown; -- TRANSFORM: -- dereference of 'pool' yields symbolic name... -- c.pool.ShutDown; AS$ActivePool.ShutDown; -- TRANSFORM: -- dereference of 'c' yields symbolic name... -- Destroy(c.results); Destroy(AS$CollectionInfo.results); -- Garbage collect the dynamically allocated data -- TRANSFORM: -- unroll loop. Since statement in the body of loop is -- completely static, all of the code below goes away. -- -- for i in 1..c.max loop -- WorkerInfoDeallocation(c.workers(i)); -- end loop; -- TRANSFORM: -- The deallocation below goes away since CollectionInfo -- record is no longer created dynamically. -- -- CollectionInfoDeallocation(c); end Destroy; -- TRANSFORM: -- Procedure declaration is modified since CollectionInfo migrates -- to compile-time -- procedure Execute(c : in Collection) is procedure Execute is begin -- TRANSFORM: -- dereference of 'pool' yields symbolic name... -- c.pool.Execute; AS$ActivePool.Execute; if theExecuteSemantics = ArchitectureConfig.Synchronous then -- TRANSFORM: -- dereference of 'pool' yields symbolic name... -- c.pool.Complete; AS$ActivePool.Complete; end if; end Execute; -- TRANSFORM: -- Procedure declaration is modified since CollectionInfo migrates -- to compile-time -- function Output(c : in Collection) return ResultType is function Output return ResultType is item : ResultType; begin -- TRANSFORM: -- dereference of 'pool' yields symbolic name... -- c.pool.GetResult(item); AS$ActivePool.GetResult(item); return item; end Output; -- TRANSFORM: -- Procedure declaration is modified since CollectionInfo migrates -- to compile-time -- function IsDone(c : in Collection) return Boolean is function IsDone return Boolean is begin -- TRANSFORM: -- use symbolic name of 'c' return AS$CollectionInfo.done; end IsDone; -- TRANSFORM: -- Procedure declaration is modified since CollectionInfo migrates -- to compile-time -- procedure Input(c : in Collection; w : WorkType) is procedure Input(w : WorkType) is tmp : WorkList; begin Create(tmp); Insert(tmp, w); -- TRANSFORM: -- dereference of 'pool' yields symbolic name... -- c.pool.Get(tmp); AS$ActivePool.Put(tmp); Destroy(tmp); end Input; end ReplicatedWorkers;