Download presentation
Presentation is loading. Please wait.
1
A Modality for Safe Resource Sharing and Code Reentrancy
Rui Shi (Yahoo! Inc) Dengping Zhu (Bloomberg Inc) Hongwei Xi (Boston Univ.)
2
The Research Context ATS is a functional programming language with a highly expressive type system rooted in the Applied Type System framework: In ATS, advanced types such as dependent types and linear types are supported. In ATS, a programming style is advocated that combines programming with theorem-proving
3
A Function in ATS swap {l1,l2:addr} ( pf1: pf2: | p1: ptr l1, p2: ptr l2 ) : void = let val tmp = !p1 in !p1 := !p2; !p2 := tmp end // end of [swap]
4
Resource Specification
Resource protection is crucial in programming We need to properly specify resources We need to strike a balance when specifying resources If specification is too weak, verification may underachieve If specification is too strong, verification may become too demanding
5
Views for Classifying Capabilities (1)
Given a type T and a location L, we use for a (primitive) view meaning that a value of the type T is stored at the location L. Given types T1 and T2 and a location L, we use for a (compound) view meaning that a value of the type T1 is stored at L and another value of the type T2 is stored at L+1.
6
Views for Classifying Capabilities (2)
We can also declare recursively defined views (similar to datatypes in a functional language like ML). For instance the following declaration introduces a view constructor array_v: datatype array_v addr) = {l:addr} array_v_nil (a, 0, l) of () | {l:addr} {n:nat} array_v_cons (a, n+1, l) of l, array_v (a, n, l+1))
7
Viewtypes Given a view V and a type T, we can form a viewtype VT = VT
The following type can be assigned to a function (ptrget_L) which reads from a fixed location L: ptr(L)) T) The following type can be assigned to a function (ptrset_L) which writes to a fixed location L: ptr(L), T2) 1) Note that we use 1 for the unit type.
8
Resource Threading There is a serious problem with linear types: resources (of linear types) must thread through function calls. For instance, we have seen this in the types assigned to the functions ptrget_L and ptrset_L. Suppose larray(T) is a type for linear arrays in which each element is of type T. Then the array subscripting function sub for linear arrays needs to be given the following type: larray(T) int larray(T) T So a linear array is threaded through each call to sub.
9
Sharable Arrays We refer to arrays in functional languages like ML as (non-linear) sharable arrays. The question we want to answer is how a sharable array can be implemented based on a linear array. More generally, how sharable data structures can be implemented based on linear ones.
10
A Sharing Modality Given a viewtype VT, we use □VT for a (non-linear) type such that a value of the type □VT represents the handle of a box containing a value of the viewtype VT. The introduction for □ is straightforward: vbox: (VT) □VT However, the elimination for □ is tricky. Essentially, we need something like this: let □ x = □ v in … end
11
The “double-borrow” problem
Assume that a resource stored in a box has been borrowed. If it is to be borrowed again before it is returned to the box, we have a “double-borrow” problem: let □ x1 = □ v1 in … … let □ x2 = □ v2 in … … end … … end
12
A Type-with-Effect System
A pure function is one that does not borrow resources; it is given a type of the following form: (VT1, …, VT2) 0 VT A non-pure function is one that may borrow resources; it is given a type of the following form: (VT1, …, VT2) 1 VT So, we can distinguish a pure function from a non-pure function at the level of types.
13
Implementing references (1)
We use ref(T) for (non-linear) references to values of the type T. In ATS, ref(T) is defined as typedef ref(T) = [l:addr] | ptr l)
14
Implementing References (2)
fun refget (r: ref(T)):<!ref> = let val (pfbox | p) = r; val vbox (pf) = pfbox in ptrget (pf | p) end // end of [refget]
15
Implement References (3)
fun refset (r: ref(T), x:T):<!ref> void = let val (pfbox | p) = r; val vbox (pf) = pfbox in ptrset (pf | p, x) end // end of [refset]
16
Reentrancy (1) A function f is reentrant if it can be called in a nested manner. That is, another call to f can be made before a call to f is finished. A non-reentrant function is one that is not reentrant. For instance, functions like ctime, drand48, and strtok are non-reentrant. Their reentrant counterparts are ctime_r, drand48_r, and strtok_r, respectively.
17
Reentrancy (2) Pure functions are reentrant
Non-pure functions are not reentrant However, if a function is guaranteed to do borrowing/returning atomically, then this function is still reentrant. We assign such a function a type of the following form: (VT1, …, VT2) 0.5 VT
18
Conclusion We have presented a type-theoretic justification for implementing (non-linear) sharable resources based on linear resources We have fully implemented the sharing modality in ATS and also used it extensively. The solution we adopted to the “double-borrow” problem is simple but effective in practice. A more elaborate solution is certainly possible but it may not fit well in ATS.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.