11th IEEE Symposium on Object Oriented Real-Time Distributed Computing (ISORC)
Allowing Cycle References by Introducing Controlled Violations of the Assignment Rules in Real-Time Java ∗
M. Teresa Higuera-Toledano Facultad Informática, Universidad Complutense de Madrid, Ciudad Universitaria, 28040 Madrid Saín Email:
[email protected]
However, the memory assignment rules by themselves do not prevent the dangling reference problem. To avoid this problem, RTSJ introduces the single parent rule, which avoid cycle references by requiring for each scoped memory region zero or one parent. The parentage relation between two scoped regions is established dynamically by the way they are used (i.e., at time a real-time thread enters a new scope or exits the current scope). The assignment rules together with the single parent rule makes difficult the design of distributed RTSJ applications. In general, distributed systems require encapsulation, separation of concerns, and modular composition of independently developed software components. Taken into account RTSJ independent components, it is required to have multiple scope allocation contexts (i.e., one for a RTSJ component) into a single scope nesting level allowing the cooperation of all these components, which requires bidirectional references among objects allocated within different scoped memory regions. In the new Specification Request (JSR-282) [10], the 2ond and 3rd enhancements relate with references between memory regions that would normally be forbidden in JSR-001. Bidirectional references mean scoped region cycles, which require breaking the single parent rule and redesign the collector for scoped regions in order to taken into account garbage collection of cycles references. This paper We present an efficient algorithm, for managing scoped memory allowing controlled violations of the assignment rules, and in this way supporting bidirectional references. Write barrier checks for illegal references are based on name-codes assigned to scoped regions, which are masking to allow controlled violations of the assignment rules.
Abstract The Real-time Specification for Java (RTSJ) extends the Java memory model through immortal and scoped memory regions to reduce the timing-indeterminism caused by garbage collection. Since scoped regions can be nested, RTSJ imposes strict assignment rules to avoid dangling pointers. These rules stabilise that an object shall not reference any object whose lifetime could be shorter than they own. Then references among two objects within different scoped regions are allowed only in one direction (i.e., from objects within region r1 to region r2, but never from r2 to r1). In order to support RTSJ component-based applications, we require controlled violations of the assignment rules to have bidirectional references among objects within two different scopes.
Keywords. Memory Management, Real-Time Java, Memory Regions, Garbage Collection.
1 Introduction The first Specification Request (JSR-001) supports the Real-time Specification for Java (RTSJ). The memory model used in RTSJ [13] offers real-time guarantees to critical tasks by tuning of the garbage collector (GC). RTSJ provides as alternative to the garbage collected heap; scoped memory regions. Since scoped memory regions can be nested, in order to prevent the creation of dangling pointers, RTSJ imposes strict assignment rules to or from memory regions, which we can formulate as: “An object shall not reference any object whose lifetime could be shorter than they own“.
∗
This research was supported by Consejería de Educación de Comunidad de Madrid, Fondo Europeo de Desarrollo Regional (FEDER) and Fondo Social Europeo (FSE), through BIOGRIDNET Research Pro-gram S-0505/TIC/000101, and by Ministerio de Educación y Ciencia, through the research grant TIN2006-02806.
978-0-7695-3132-8/08 $25.00 © 2008 IEEE DOI 10.1109/ISORC.2008.48
463
1.1 Related Work
2 RTSJ Memory Management
Since the current RTSJ memory model introduces a complex programming model, some researches have produce new programming paradigms and patterns in order to reduce the complexity of programming using memory regions. Whereas in [6] we found some adaptations of classical patterns to the RTSJ memory, in [2] we found a copying-based mechanism to perform automatic object copies from one region to another avoiding some of the limitations imposed by the assignment rules. Others works presenting the use of a copy-based mechanism in order to avoid the maintenance of dangling pointers are [3] [8] [12]. All these cases are compatible with the current RTSJ enhancements 9 and 11 are specific for the garbage collector within the heap. reference model, and use portals as the main assignment rule violation mechanism. As an exception, the solution presented in [4] uses both: the weak references mechanism, and the reflection support of the Java API. In the extension called pinning scopes [14] we found the way to avoid the use of linked portals in order to access forbidden objects. But it still requires the use of wedge threads to prevent region destruction. Also, in [11] appears the idea of an auxiliary thread together with a portal-based mechanism that allows getting some kind of control on the regions life. In [1] we found a mechanism to violate the assignment rule, which introduces the idea of having an easy navigation for RTSJ portals by using weak references. Here the RTSJ portal is extended to support a region-based distributed middleware. Based on the display-based ideas presented in [7], in order to support time-predictability we use name-codes and binary masks to support write barrier checks. A name-based code for scoped memory region based on the idea that regions are parented at creation time has been presented in [9]. This solution gives a memory model less flexible than the RTSJ one, however the advantages that it presents are the simplicity to both its use and implementation.
The RTSJ revision, which is under the JSR-282 [10] [5], considers 21 enhancement requests. Where four of them are related to memory management1: “2. Investigate a class, similar to the weak reference classes, that supports references between memory areas that would normally be forbidden by the RTSJ assignment rules.” “3. Relax the bi-directional reference rule for parameter objects.”
2.1 Memory Areas and Assignment Rules RTSJ allows memory to be allocated and freed outside of garbage collected heap, by defining regions of memory outside of the traditional Java heap; specifically, scoped memory areas contain objects with a related limited lifetime, and can be nested. When a schedulable object has a memory region amr as its active region, all calls to the new() method create the object within amr. When there are no active schedulable objects inside a scoped memory region, this region can be reclaimed by a reference counter based collector which collects the region when its counter becomes zero. The reference count of a scoped memory area is the count of the number of active calls (explicit or implicit) to its enter() method. Let an object objA, created within a scoped memory region (e.g., ScopedA). A reference to that object has been stored in the object objH (objH.field = objA), which resides whithin the heap. The reference from objH to objA becomes dangling when reclaiming the objA (i.e. the ScopedA memory region) before than objH. So the safety of the program would be compromised. In order to avoid dangling pointers, RTSJ introduces strict memory assignment rules, which can be expressed as follows:
1.2 Paper Organization The rest of this paper is organized as follows: First, we present an in depth description of the RTSJ memory model and analyze both the single parent rule and assignment rules (Section 2). Then, we present a solution in order to allow controlled violations of the assignments rules, which can be implemented efficiently by using simple data structures and algorithms (Section 3). Finally a summary of our contribution conclude this paper (Section 4).
If
“An object within the heap or an immortal region shall not reference any object within a scoped region”. “An object within a scoped region shall not reference any object within another scoped region which is non-outer”.
the
application
violates
these rules, the is thrown. To enforce the assignment rules, a real-time JVM implementation will need to keep track of the currently active memory areas of each schedulable object (e.g., by illegalAssignmentException()
1
Enhancements 9 and 11 are specific for the garbage collector within the heap.
464
In both cases, the garbage collection of the scoped region invocating the method must be delayed until his parent was collected. Note that when the parent region is the primordial scoped (i.e., the heap, the immortal memory region, or an immortal physical memory region), the scoped region invocating these methods becomes persistent, and its live is linking with the end of the application.
a scope stack). The scope stack can be used to check invalid references to or from scoped memory regions.
2.2 The Single Parent Rule Let us consider a schedulable object that enters the scopedA, scopedB, and scopedA scope memory regions (i.e., enters the scopedA scope memory region twice). An object objA created whithin scopedA could have references to objects within the scopedB region (e.g., objB). Since when the current scopedA memory
3.1 Name-based Write Barriers
region is exited, the reference count for that area is still greater than zero; its objects are not reclaimed. Now, the reference objA.field = objB still exits. Then when exiting scopedB, its objects are reclaimed and consequently objA.field becomes a dangling pointer. To avoid this problem, RTSJ establishes the single parent rule [8]:
Given that one of the requirements of RTSJ is that there should be no changes in the Java language and that Java base line compilers can be used to compile RTSJ programs, both the assignment rules and the single parent rule must be enforced at run-time. This solution adversely affects both the performance and predictability of the RTSJ application. The success of the RTSJ may well hinge on the possibility to offer an efficient and time-predictable implementation of scoped memory regions. The RTSJ specification does not explicitly provide an algorithm to enforce the assignment rules. This includes the possibility of static analysis of the application logic. However, since assignment rules cannot be fully enforced by the compiler, some dangling pointers must be detected at runtime [15]. This approach requires the introduction of write barriers; that is, to introduce a code checking the validity of the reference when creating an assignment, before the statement is executed. The display-based solution presented in [7] allows us to check illegal references in constant time. In order to have efficient checking for relaxing assignments rules, we understand that both allowed and illegal references are not depending on the thread that creates the reference (i.e., illegal references are the same for all threads in the system). Then, we use a global scope tree structure supporting the parentage relation among regions and use a name-based algorithm [9]. Where the name-code for each memory region is generated from the name-code of their parent, having implicit the name-code of all its ancestors. We can also use a m ask to deal with relaxed references. As an example, taken 6 bits for the name-code, we can organize a region tree of two nested levels having six scoped regions on each level. Note that there is one combination non-used (i.e., we must to reserve a binary combination for the level-mask). As another example, we can organize a name-code of 6 bits in three levels (see Figure 1). Then, the binary mask for level 1 is “111100”, “110011” for level 2, and “001111” for level 3. And for the region name-codes:
“For the first scoped area on the stack, the parent is the primordial scope area (i.e., either the ImmortalMemory or the HeapMemory objects)”. “For all other scoped memory areas, the parent is the first scoped area below it on the stack”.
Since multiple schedulable objects can access the same memory region, the cactus stacks for all schedulable objects are linked together.
3 Relaxing the Assignments Rules We propose to make legal the following references by expressing it explicitly in the program code: 1. 2.
Bidirectional references among two nested levels (i.e., references to an object from objects within the nested outer region). References to objects within a given scoped region from objects within all scoped regions having the same parent (i.e., references from objects within regions in the same level having the same region as parent).
Note that the last case does not create cycles (i.e., allowed references are unidirectional). Since these controlled violations must be established at user level, we must to support the corresponding methods in the SopedMemoryArea abstract class: • • •
allowParentReferences(), allowBrotherReferences()and allowFamilyReferences().
465
from = nameCode(X); to = nameCode(Y); mask = maskLevel(to);
“000000” for the primordial scope, “000001” and “000010” for possible memory regions in level 1; “000101”, “001001”, “000110” and “001010” for level 2, and “010101”, ..., “101010” for level 3.
case allowedReferences(from) do none: *does not allowed if (from & to != to) then illegalAssignment(); parent: *outer scope if (from & to != to) then if ((mask & to) != from) then illegalAssignment();
000000
000001 000101 010101
001001 100101
brother: *same outer scope if (from & to != to) then if ((mask & from)!=(parent(to)) then illegalAssignment();
000010
…
…
101001
family: *both parent and brother if (from & to != to) then if ((mask & from)!=(mask & to)) then illegalAssignment();
…
endCase;
Figure 1. Scope tree for 6 bits name-code with masks.
Figure 3. Checks for allowed violation of RTSJ rules. Figure 2 shows the pseudo-code that we must introduce in the execution of each assignment statement (e.g., X.a=Y). The nameCode() function returns the namecode of the region to which the object parameter belongs.
3.2 Data Structures and Region Collection Note that when a scoped region allows non-inner references, it must be collected together with its parent region. Then, we must to redesign the scoped region garbage collector in order to maintain the live of scoped regions which reference counter have reached zero, but have pointers from an outer scope. Note that relaxed references link the life-time of the region which relaxes the references with the life-time of its parent region. In order to have efficient scoped region collection, we maintain some internal information for each scoped memory region: (i) A count of the number of schedulable objects having use of this scoped region (i.e., reference-count). (ii) A binary name-code used for checking illegal references (i.e., name-code). (iii) The parent of the region (i.e., parent-region). (iv) The active region at time that the region has been entered. (v) A field indicating the relaxed reference type for the scoped region (i.e., inner-references). And (vi) a waiting region list for scoped regions which memory cannot be still recycled (i.e., waiting-list). To collect a scoped region, we must check both fields associated to the region, the reference-count and the inner-references. Then, when the reference count of a scoped region reaches zero, it can be collected only if it has not relaxed references (i.e., noninner references potentially causing dangling pointers). Then, when the reference count of a scoped region becomes zero and the region allows non-inner references, it must be collected together with its parent. Scoped regions which reference counters become zero but have non-inner references are linked within the
inner = nameCode(X); outer = nameCode(Y); if ((outer and inner) != outer) then illegalAssignment();
Figure 2. Write barriers for illegal reference checks. Figure 3 shows the pseudo-code of write barriers taken into account relaxed references. The allowedReferences()function gives the non-inner reference type that the region allows:
none: Objects within the region cannot have
parent: Objects within the region can have
external references from non-outer scopes.
references from objects allocated within the parent region. brother: Objects within the region can have references from objects allocated within regions having the same the parent region. family: Objects within the region allows references from objects allocated within regions having the same the parent region, or from objects allocated within the parent region.
The maskLevel() function gives a mask associated with the nested level of the region name-code passed as parameter.
466
waiting-list, in order to be recycled by a background thread when their parent becomes collectable. The data structure supporting the information that the garbage collector of scoped region requires can be implemented by a descriptor table which implicitly supports the scope tree. Then, in order to support the aforementioned memory model, we must to implement the algorithms maintaining this data structure. Considering the situation showed in Figure 4; suppose that the program executes the method scopedC.allowParentReferences(). As consequence both the inner-reference field and the waiting-list of its parent are updated. When the scopedC region is exited, the reference count of this region reaches zero, but it can not be collected because it has non-inner references, and its collection must be delayed until its parent (i.e., the scopedB region) becomes collectable. Since the inner-reference field of the scopedB region is none, both regions scopedC and scopedB are finally collected at time exiting scopedB. scopedA
scopedB
scopedC
scopedD
2
1
1
1
1
Name-code
__A
_BA
ABA
_AA
AAA
primordia l primordia l none
scopedA
scopedB
scopedA
scopedD
primordia l none
scopedB
scopedA
scopedD
parent
None
none
nil
scopedC
nil
Nil
nil
Outer Inner-ref Waiting-list
[1] P. Basanta-Val, M. García-Valls, I. Estévez-Ayres. “ExtendedPortal: Violating the assignment rule and enforcing the single parent one”. JTRES 2006. [2] E.G. Benowitz, A.F. Niessner. "A Patterns Catalog for RTSJ Software Designs". OTM Workshop on Java Technologies for Real-Time and Embedded Systems (JTRES 2002). [3] G. Bollella, T. Canham, V. Carson, V.Champlin, D. Dvorak, B. Giovannoni, M. Indictor, K. Meyer, A. Murray, K. Reinholtz. "Programming with nonheap memory in the real time specification for Java". ACM SIGPLAN OOPSLA 2002. [4] A. Borg, A.J. Wellings. "Reference Objects for RTSJ Memory Areas". JTRES 2002. [5] Peter Dibble. “The current status of the RTSJ and JSR 282”. JTRES 200). [6] A. Corsaro, C. Santoro. "Design Patterns for RTSJ Application Development". JTRES 2004. [7] A. Corsaro, R. Cytron. "Efficient memory-reference checks for real-time java". LCTES 2002. [8] P.C. Dibble. "Real-time Java Platform Programming". Prentice Hall. 2002. [9] M.T. Higuera-Toledano. “Name-based WriteBarriers in Real-Time Java”. IEEE CIT 2007. [10] JSR-282. "RTSJ version 1.1". Available on-line at http://www.jcp.org/en/jsr [11] F. Pizlo, J. M. Fox, D. Holmes, J. Vitek. "Real-Time Java
scopedE
Ref-count Parent
References
Scoped Memory: Design Patterns and Semantics". IEEE ISORC 2004.
[12] K., Y. Zhang, M. Panahi, J. A. Colmenares, R. Klefstad. "Patterns and Tools for Achieving Predictability and Performance with Real-Time Java". IEEE RTCSA 2005. [13] RTJEG. "The Real-time Java Specification". Version 1.0.1(b). Available on-line at http://www.rtj.org [14] Timesys. "JTIME RTSJ 1.0 Extensions User Guide" Available on-line at http://www.timesys.com [15] A. Wellings. “Concurrent and Real-Time Programming in JAVA”. Johm Wiley &Sons, Ltd. 2004.
Figure 4. Scoped region descriptor table.
4 Conclusions Dealing with component-based applications, encapsulation requires the use of a scoped region to support the component memory requirements, and relations among the components which compound the application require violations of the strict assignment rules. A binary code base name associated witch each scope region allows efficient and time predictable checks for illegal references. More over, the use of binary masks in order to relax the assignments rules allows us an efficient and time predictable write barrierchecking for both illegal and relaxed references. The programming model presented in this paper is compliant with RTSJ. However, we think that the single parent rule introduces an unfamiliar programming model allowing data races. By relaxing assignment rules and redefining the single parent rule (i.e., parenting regions at creation time instead of at entering time), we obtain a simpler and flexible programming model.
467