@@ -222,12 +222,12 @@ object.
222
222
<!-- By invalid pointer dereference we mean (1) null pointer dereference, (2) use-after-free, or (3)
223
223
free-after-free. -->
224
224
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`.
231
231
232
232
After ` self.buffer ` is initialized, it is modified only by the owner in ` fn resize(): 'L307 ` . Since
233
233
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:
246
246
buffer is deferred to be dropped at ` 'L308 ` , the only reference to the buffer via ` self.buffer ` is
247
247
removed at ` 'L307 ` .
248
248
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.
251
252
252
253
It is indeed the case because (1) a buffer is deferred to be dropped only by the owner with a
253
254
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
265
266
state* is a triple ` (t, b, A) ` , where ` t ` is the top index, ` b ` is the bottom index, and ` A ` is the
266
267
array of the values within the indexes ` [t, b) ` . A ` push() ` invocation increases the bottom index
267
268
` 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
269
270
special case, if ` t+1 = b ` , you can increase the top index ` t ` instead of decreasing the bottom
270
271
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 ` .
273
275
274
276
A shared object is ** linearizable** as a deque if the following holds:
275
277
@@ -284,21 +286,22 @@ A shared object is **linearizable** as a deque if the following holds:
284
286
>
285
287
> - (SEQ) Initially, ` (t_0, b_0, A_0) = (0, 0, []) ` holds. Furthermore, for all ` i ` , `(t_i, b_i,
286
288
> 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
288
290
> (i.e. non-concurrently) executed to a deque in the linearization order.
289
291
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
+
296
299
297
300
In addition to linearizability, we require that a matching pair of ` push() ` and ` steal() `
298
301
synchronize like a matching pair of a release-store and an acquire-load:
299
302
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.
302
305
303
306
Note that a similar property for a matching pair of ` push() ` and ` pop() ` is a corollary of
304
307
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
342
345
by inserting stealers' invocations into it.
343
346
344
347
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:
346
350
347
351
- 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 ` .
350
354
351
355
- If ` S ` returns ` EMPTY ` , then ` S ∈ G_i ` .
352
356
@@ -379,18 +383,6 @@ Let `WF_i` and `WL_i` be `O_i`'s first and last write to `bottom`.
379
383
Since ` view_beginning(I)[loc] < view_end(J)[loc] ` holds, it is not the case that
380
384
` view_beginning(I)[loc] < view_end(J)[loc] ` holds.
381
385
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
-
394
386
Suppose that ` O_i ` is ` pop() ` taking the irregular path, and ` x ` be the value ` O_i ` read from
395
387
` bottom ` at ` 'L201 ` .
396
388
@@ -401,15 +393,16 @@ Suppose that `O_i` is `pop()` taking the irregular path, and `x` be the value `O
401
393
tries to compare-and-swap (CAS) ` top ` from ` x-1 ` to ` x ` at ` 'L213 ` . Regardless of whether the CAS
402
394
succeeds or fails, ` O_i ` reads or writes ` top >= x ` .
403
395
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 .
406
398
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.
409
402
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.
413
406
414
407
+ Case ` O_i ` read ` top >= x ` at ` 'L204 ` .
415
408
@@ -442,7 +435,8 @@ For `(VIEW)`, it is sufficient to prove that:
442
435
4 . ` (VIEW-STEAL-INTRA-GROUP) ` : for all ` i ` and ` S, S' ∈ G_i ` , if ` S ` is placed before ` S' ` , then it
443
436
is not the case that ` S' <V S ` .
444
437
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.)
446
440
447
441
#### Proof of ` (VIEW-OWNER-STEAL) `
448
442
@@ -454,57 +448,59 @@ view_end(S)[bottom]`, and by `(VIEW-LOC)`, it is not the case that `S <V O_i`.
454
448
#### Proof of ` (VIEW-STEAL-OWNER) `
455
449
456
450
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 .
458
452
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.
467
457
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.
469
463
470
464
#### Proof of ` (VIEW-STEAL-INTER-GROUP) `
471
465
472
466
- Case 1: ` O_(i+1) ` , ..., ` O_j ` are all ` pop() ` taking the irregular path.
473
467
474
468
Then ` S_j ` should have returned ` EMPTY ` . If ` S_i ` read from ` WF_i ` or ` WL_i ` , then
475
469
` 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
478
474
` (IRREGULAR-STEAL) ` , and ` x-1 <= view_end(S_j)[top] ` by ` (IRREGULAR-TOP) ` and the fact that ` S_j `
479
475
read ` x-1 ` or ` x ` from ` bottom ` at ` 'L404 ` . By ` (VIEW-LOC) ` , the conclusion follows.
480
476
481
477
- Case 2: Otherwise.
482
478
483
479
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.
486
482
487
483
#### Proof of ` (VIEW-STEAL-INTRA-GROUP) `
488
484
489
485
- Case 1: ` S, S' ∈ STEAL ` .
490
486
491
487
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 .
493
489
494
490
- Case 2: ` S, S' ∈ STEAL_EMPTY ` . Obvious from the construction.
495
491
496
492
- Case 3: ` S ∈ STEAL ` and ` S' ∈ STEAL_EMPTY ` .
497
493
498
494
Let ` b ` be the value of ` WL_i ` ; ` x ` and ` x' ` be the values ` S ` and ` S' ` read from ` bottom ` at
499
495
` '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'`.
502
498
503
499
If ` S ` read from ` bottom ` a value written by ` O_i ` , then we have `y < x = b = x' <=
504
500
y'` . Otherwise, then ` S` read from ` bottom` a value written by ` O_j` for some ` j > i`, and for all
505
501
` 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.
508
504
509
505
510
506
## Proof of ` (SEQ) ` and ` (SYNC) `
0 commit comments