Skip to content

Commit d45a793

Browse files
committed
Rewording the proof of (VIEW)
1 parent f9cbcc9 commit d45a793

File tree

1 file changed

+58
-62
lines changed

1 file changed

+58
-62
lines changed

text/2018-01-07-deque-proof.md

+58-62
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,12 @@ object.
222222
<!-- By invalid pointer dereference we mean (1) null pointer dereference, (2) use-after-free, or (3)
223223
free-after-free. -->
224224

225-
Pointer safety boils down to proving the safety of every access to the contents of the buffer
226-
pointed-to by `Inner`'s `self.buffer`, (1) since the other shared objects, namely `self.bottom`,
227-
`self.top`, and `self.buffer`, are just integers or pointers, and (2) accesses to thread-local
228-
storage are straightforwardly safe. It is worth noting that while the deque is shared among the
229-
owner and its stealers, only the owner is able to call `fn push()`, `fn pop()`, and `fn resize()`,
230-
thereby modifying `self.bottom` and `self.buffer`.
225+
For pointer safety, it is sufficient to prove that every access to the contents of the buffer
226+
pointed-to by `Inner`'s `self.buffer` is safe, since (1) the other shared objects, namely
227+
`self.bottom`, `self.top`, and `self.buffer`, are just integers or pointers, and (2) accesses to
228+
thread-local storage are straightforwardly safe. It is worth noting that while the deque is shared
229+
among the owner and its stealers, only the owner is able to call `fn push()`, `fn pop()`, and `fn
230+
resize()`, thereby modifying `self.bottom` and `self.buffer`.
231231

232232
After `self.buffer` is initialized, it is modified only by the owner in `fn resize(): 'L307`. Since
233233
the contents inside a buffer is always accessed modulo the buffer's capacity (`'L109`, `'L211`,
@@ -246,8 +246,9 @@ user of Crossbeam, we only need to prove that:
246246
buffer is deferred to be dropped at `'L308`, the only reference to the buffer via `self.buffer` is
247247
removed at `'L307`.
248248

249-
- With an `unprotected()` guard, we should not defer to drop an object that is accessed by another
250-
thread, and should not access an object that is deferred to be dropped by another thread.
249+
- With an `unprotected()` guard, we should not defer to drop an object that is concurrently accessed
250+
by another thread, and should not access an object that is concurrently deferred to be dropped by
251+
another thread.
251252

252253
It is indeed the case because (1) a buffer is deferred to be dropped only by the owner with a
253254
protected guard, and (2) stealers do not use an unprotected guard.
@@ -265,11 +266,12 @@ In order to answer the question, we first define the sequential specification of
265266
state* is a triple `(t, b, A)`, where `t` is the top index, `b` is the bottom index, and `A` is the
266267
array of the values within the indexes `[t, b)`. A `push()` invocation increases the bottom index
267268
`b`, and push the input value at the end of `A`. A `pop()` invocation decreases the bottom index `b`
268-
and pop the last value from `A`, if `t < b`; otherwise, touch nothing and return `EMPTY`. (As a
269+
and pop the last value from `A`, if `t < b`; otherwise, touches nothing and returns `EMPTY`. (As a
269270
special case, if `t+1 = b`, you can increase the top index `t` instead of decreasing the bottom
270271
index `b`.) A `steal()` invocation increases the top index `t` and pop the first value from `A`, if
271-
`t < b`; otherwise, touch nothing and return `EMPTY`. By `S -(I,R)-> S'` we denote the *transition
272-
relation* described above, from a deque state `S` into `S'` by the invocation `I` returning `R`.
272+
`t < b`; otherwise, touches nothing and returns `EMPTY`. By `S -(I,R)-> S'` we denote the
273+
*transition relation* described above, from a deque state `S` into `S'` by the invocation `I`
274+
returning `R`.
273275

274276
A shared object is **linearizable** as a deque if the following holds:
275277

@@ -284,21 +286,22 @@ A shared object is **linearizable** as a deque if the following holds:
284286
>
285287
> - (SEQ) Initially, `(t_0, b_0, A_0) = (0, 0, [])` holds. Furthermore, for all `i`, `(t_i, b_i,
286288
> A_i) -(signature(I_i),ret(I_i))-> (t_(i+1), b_(i+1), A_(i+1))` holds. In other words, the
287-
> invocations `I_`, ..., `I_(n-1)` return outputs *as if* the invocations are sequentially
289+
> invocations `I_0`, ..., `I_(n-1)` return outputs *as if* the invocations are sequentially
288290
> (i.e. non-concurrently) executed to a deque in the linearization order.
289291
290-
Here, by `view_beginning(I)` and `view_end(I)` we mean the thread `I`'s view at the beginning and
291-
the end of the invocation. A view `v1` is less than or equal to another view `v2`, denoted by `v1 <=
292-
v2`, if for any location `l`, `v1[l] <= v2[l]` holds; and `v1` is less than `v2`, denoted by `v1 <
293-
v2`, if (1) `v1 <= v2`, and (2) there exists a location `l` such that `v1[l] < v2[l]`. By `I <V J`
294-
we mean `view_end(I) < view_beginning(J)`. Also, `signature(I)` and `ret(I)` are the function call
295-
signature and the return value of `I`.
292+
Here, by `signature(I)` and `ret(I)` we mean the function call signature and the return value of
293+
`I`. Also, by `I <V J` we mean `view_end(I) < view_beginning(J)`, and by `view_beginning(I)` and
294+
`view_end(I)` we mean the thread `I`'s view at the beginning and the end of the invocation. A view
295+
`v1` is less than or equal to another view `v2`, denoted by `v1 <= v2`, if for any location `l`,
296+
`v1[l] <= v2[l]` holds; and `v1` is less than `v2`, denoted by `v1 < v2`, if (1) `v1 <= v2`, and (2)
297+
there exists a location `l` such that `v1[l] < v2[l]`.
298+
296299

297300
In addition to linearizability, we require that a matching pair of `push()` and `steal()`
298301
synchronize like a matching pair of a release-store and an acquire-load:
299302

300-
> - (SYNC) If a value is `push()`ed by an invocation `I` and then `steal()`ed by `J`, then
301-
> `view_beginning(I) <= view_end(J)` holds.
303+
> - (SYNC) If a value is `push()`ed by an invocation `I` and then `steal()`ed by an invocation `J`,
304+
> then `view_beginning(I) <= view_end(J)` holds.
302305
303306
Note that a similar property for a matching pair of `push()` and `pop()` is a corollary of
304307
linearizability, as only the owner is able to call `push()` and `pop()` and the `push()` should be
@@ -342,11 +345,12 @@ owner's invocations, sorted according to the program order. We construct a full
342345
by inserting stealers' invocations into it.
343346

344347
Note that every owner's invocation writes to `bottom`, and every stealers' invocation reads from
345-
`bottom` at `'L404`. We classify the stealers' invocations into "groups" `{G_i}` as follows:
348+
`bottom` at `'L404`. Using `bottom`, we classify the stealers' invocations into "groups" `{G_i}` as
349+
follows:
346350

347351
- For a stealer's invocation `S`, if `S` reads the initial value from `bottom`, then `S ∈
348-
G_(-1)`. Otherwise, let `O_i` be the owner's invocation that writes to `bottom` a value read by
349-
`S`.
352+
G_(-1)`. Otherwise, let `O_i` be such an owner's invocation that `S` read from `bottom` a value
353+
written by` O_i`.
350354

351355
- If `S` returns `EMPTY`, then `S ∈ G_i`.
352356

@@ -379,18 +383,6 @@ Let `WF_i` and `WL_i` be `O_i`'s first and last write to `bottom`.
379383
Since `view_beginning(I)[loc] < view_end(J)[loc]` holds, it is not the case that
380384
`view_beginning(I)[loc] < view_end(J)[loc]` holds.
381385

382-
- > (VIEW-BOTTOM-OWNER): For arbitrary `i`, since `O_(i-1)` wrote `WF_(i-1)`, `WL_(i-1)` and `O_i`
383-
wrote `WF_i`, `WL_i`, we have `Timestamp(WL_(i-1)) <= view_beginning(O_i)[bottom] <
384-
Timestamp(WF_i)`. Similarly, we have `Timestamp(WL_i) <= view_end(O_i)[bottom] <
385-
Timestamp(WF_(i+1))`.
386-
387-
FIXME: remove it
388-
389-
- > (VIEW-BOTTOM-STEAL): For arbitrary `i` and `S ∈ G_i`, since `S` read `WF_i` or a later value, we
390-
have `Timestamp(WF_i) <= view_end(S)[bottom]`.
391-
392-
FIXME: remove it
393-
394386
Suppose that `O_i` is `pop()` taking the irregular path, and `x` be the value `O_i` read from
395387
`bottom` at `'L201`.
396388

@@ -401,15 +393,16 @@ Suppose that `O_i` is `pop()` taking the irregular path, and `x` be the value `O
401393
tries to compare-and-swap (CAS) `top` from `x-1` to `x` at `'L213`. Regardless of whether the CAS
402394
succeeds or fails, `O_i` reads or writes `top >= x`.
403395

404-
It is worth nothing that it is necessary for the CAS at `'L213` to be strong, i.e. it the CAS does
405-
not spuriously fail, for this lemma to hold.
396+
It is worth nothing that for this lemma to hold, it is necessary for the CAS at `'L213` to be
397+
strong, i.e. it the CAS does not spuriously fail.
406398

407-
- > (IRREGULAR-STEAL): Let `S` be `steal()` that reads from `bottom` a value written by `O_i` and
408-
returns a value, and `y` be the value `S` writes to `top` at `'L410`. Then `y < x` holds.
399+
- > (IRREGULAR-STEAL): Let `S` be a successful `steal()` that reads from `bottom` a value written by
400+
`O_i` and returns a value, and `y` be the value `S` writes to `top` at `'L410`. Then `y < x`
401+
holds.
409402

410-
If `S` read `bottom = x-1` written by `O_i` at `'L202`, then `y <= x-1`. Otherwise, `S` read
411-
`bottom = x` written by `O_i` at `'L207` or `'L216`. We already know `y <= x` from the condition
412-
at `'L405`, so suppose `y = x` and let's derive a contradiction.
403+
If `S` read `bottom = x-1` written by `O_i` at `'L202`, then `y <= x-1` from the condition at
404+
`'L405`. Otherwise, `S` read `bottom = x` written by `O_i` at `'L207` or `'L216`. We already know
405+
`y <= x` from the condition at `'L405`, so suppose `y = x` and let's derive a contradiction.
413406

414407
+ Case `O_i` read `top >= x` at `'L204`.
415408

@@ -442,7 +435,8 @@ For `(VIEW)`, it is sufficient to prove that:
442435
4. `(VIEW-STEAL-INTRA-GROUP)`: for all `i` and `S, S' ∈ G_i`, if `S` is placed before `S'`, then it
443436
is not the case that `S' <V S`.
444437

445-
(Note that what would be `(VIEW-OWNER-OWNER)` is obvious.)
438+
(Note that what would be `(VIEW-OWNER-OWNER)` is obvious from the fact that `{O_i}` is sorted
439+
according to the program order.)
446440

447441
#### Proof of `(VIEW-OWNER-STEAL)`
448442

@@ -454,57 +448,59 @@ view_end(S)[bottom]`, and by `(VIEW-LOC)`, it is not the case that `S <V O_i`.
454448
#### Proof of `(VIEW-STEAL-OWNER)`
455449

456450
If `S` returns `EMPTY`, then `view_beginning(S)[bottom] <= Timestamp(WL_i) < Timestamp(WL_j) <=
457-
view_end(O_j)[bottom]`.
451+
view_end(O_j)[bottom]`, and by `(VIEW-LOC)`, the conclusion follows.
458452

459-
Now suppose `S` returns a value. Let `O_k` be the owner invocation that writes to `bottom` a value
460-
read by `S` at `'L404`. Then for all `l ∈ (i, k]`, `O_k` is `pop()` taking the irregular path. If `k
461-
< j`, then `view_beginning(S)[bottom] <= Timestamp(WL_k) < Timestamp(WL_j) <=
462-
view_end(O_j)[bottom]`. Now suppose `j ∈ (i, k]`. Let `x` and `y` be the values `O_j` read from
463-
`bottom` at `'201` and `top` at `'204`, respectively. Then we have `x-1 <= y` by the fact that `O_j`
464-
is a `pop()` taking the irregular path, `view_beginning(S)[top] < x-1` by `(IRREGULAR-STEAL)`, and
465-
`x <= view_end(O_j)[top]` by `(IRREGULAR-TOP)`. Thus we have `view_beginning(S)[top] < x-1 < x <=
466-
view_end(O_j)[top]`.
453+
Now suppose `S` returns a value. Let `O_k` be such an owner invocation that the value `S` read from
454+
`bottom` at `'L404` is written by `O_k`. Then for all `l ∈ (i, k]`, `O_l` is `pop()` taking the
455+
irregular path. If `k < j`, then `view_beginning(S)[bottom] <= Timestamp(WL_k) < Timestamp(WL_j) <=
456+
view_end(O_j)[bottom]`, and by `(VIEW-LOC)`, the conclusion follows.
467457

468-
In either case, by `(VIEW-LOC)`, it is not the case that `O_j <V S`.
458+
Now suppose `j ∈ (i, k]`. Let `x` and `y` be the values `O_j` read from `bottom` at `'201` and `top`
459+
at `'204`, respectively. Then we have `x-1 <= y` by the fact that `O_j` is a `pop()` taking the
460+
irregular path, `view_beginning(S)[top] < x-1` by `(IRREGULAR-STEAL)`, and `x <= view_end(O_j)[top]`
461+
by `(IRREGULAR-TOP)`. Thus we have `view_beginning(S)[top] < x-1 < x <= view_end(O_j)[top]`, and by
462+
`(VIEW-LOC)`, the conclusion follows.
469463

470464
#### Proof of `(VIEW-STEAL-INTER-GROUP)`
471465

472466
- Case 1: `O_(i+1)`, ..., `O_j` are all `pop()` taking the irregular path.
473467

474468
Then `S_j` should have returned `EMPTY`. If `S_i` read from `WF_i` or `WL_i`, then
475469
`view_beginning(S_i)[bottom] <= Timestamp(WL_i) < Timestamp(WF_j) <= view_ending(S_j)[bottom]`,
476-
and by `(VIEW-LOC)`, the conclusion follows. Otherwise, let `x` be the value `O_(i+1)`, ..., `O_j`
477-
read from `bottom` at `'L201`. Then we have `view_beginning(S_i)[top] < x-1` by
470+
and by `(VIEW-LOC)`, the conclusion follows.
471+
472+
Not suppose otherwise. Then `S_i` should have returned a value. Let `x` be the value `O_(i+1)`,
473+
..., `O_j` read from `bottom` at `'L201`. We have `view_beginning(S_i)[top] < x-1` by
478474
`(IRREGULAR-STEAL)`, and `x-1 <= view_end(S_j)[top]` by `(IRREGULAR-TOP)` and the fact that `S_j`
479475
read `x-1` or `x` from `bottom` at `'L404`. By `(VIEW-LOC)`, the conclusion follows.
480476

481477
- Case 2: Otherwise.
482478

483479
Let `O_k` be such an invocation that is not `pop()` taking the irregular path and `k ∈ (i,
484-
j]`. Then we have `view_beginning(S_i)[bottom] < Timestamp(WF_k) <= view_ending(S_j)[bottom]`, and
485-
by `(VIEW-LOC)`, the conclusion follows.
480+
j]`. Then we have `view_beginning(S_i)[bottom] < Timestamp(WF_k) <= Timestamp(WF_j) <=
481+
view_ending(S_j)[bottom]`, and by `(VIEW-LOC)`, the conclusion follows.
486482

487483
#### Proof of `(VIEW-STEAL-INTRA-GROUP)`
488484

489485
- Case 1: `S, S' ∈ STEAL`.
490486

491487
Suppose `S` read the value `y` from `top` at `'L401`, and `S'` read the value `w` from `top` at
492-
`'L401`. By the construction, `y < w`. Thus it is not the case that `S' <V S`.
488+
`'L401`. By the construction, `y < w`. By `(VIEW-LOC)`, the conclusion follows.
493489

494490
- Case 2: `S, S' ∈ STEAL_EMPTY`. Obvious from the construction.
495491

496492
- Case 3: `S ∈ STEAL` and `S' ∈ STEAL_EMPTY`.
497493

498494
Let `b` be the value of `WL_i`; `x` and `x'` be the values `S` and `S'` read from `bottom` at
499495
`'L404`, respectively; and `y` and `y'` be the values `S` and `S'` read from `top` at `'L401`,
500-
respectively. Since `S' ∈ STEAL`, we have `y < x`. Since `S' ∈ STEAL_EMPTY`, we have `b-1 <= x' <=
501-
y'`.
496+
respectively. Since `S' ∈ STEAL`, we have `y < x` from the condition at `'L405`. Since `S' ∈
497+
STEAL_EMPTY`, we have `x' <= y'`.
502498

503499
If `S` read from `bottom` a value written by `O_i`, then we have `y < x = b = x' <=
504500
y'`. Otherwise, then `S` read from `bottom` a value written by `O_j` for some `j > i`, and for all
505501
`k ∈ (i, j]`, `O_k` is `pop()` taking the irregular path. By `(IRREGULAR-STEAL)`, we have `y+1 <
506-
b`, and then `y <= b-2 < b-1 <= x' <= y'`. In either case, we have `y < y'`, and by `(VIEW-LOC)`,
507-
the conclusion follows.
502+
b`. By the definition of `push()` and `pop()`, we have `b-1 <= x'`, and thus `y <= b-2 < b-1 <= x'
503+
<= y'`. In either case, we have `y < y'`, and by `(VIEW-LOC)`, the conclusion follows.
508504

509505

510506
## Proof of `(SEQ)` and `(SYNC)`

0 commit comments

Comments
 (0)