|
1 // |reftest| skip |
|
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 //----------------------------------------------------------------------- |
|
8 |
|
9 var summary = "Lamport Bakery's algorithm for mutual exclusion"; |
|
10 // Adapted from pseudocode in Wikipedia: |
|
11 // http://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm |
|
12 |
|
13 printStatus(summary); |
|
14 |
|
15 var N = 15; // Number of threads. |
|
16 var LOOP_COUNT = 10; // Number of times each thread should loop |
|
17 |
|
18 function range(n) { |
|
19 for (let i = 0; i < n; i++) |
|
20 yield i; |
|
21 } |
|
22 |
|
23 function max(a) { |
|
24 let x = Number.NEGATIVE_INFINITY; |
|
25 for each (let i in a) |
|
26 if (i > x) |
|
27 x = i; |
|
28 return x; |
|
29 } |
|
30 |
|
31 // the mutex mechanism |
|
32 var entering = [false for (i in range(N))]; |
|
33 var ticket = [0 for (i in range(N))]; |
|
34 |
|
35 // the object being protected |
|
36 var counter = 0; |
|
37 |
|
38 function lock(i) |
|
39 { |
|
40 entering[i] = true; |
|
41 ticket[i] = 1 + max(ticket); |
|
42 entering[i] = false; |
|
43 |
|
44 for (let j = 0; j < N; j++) { |
|
45 // If thread j is in the middle of getting a ticket, wait for that to |
|
46 // finish. |
|
47 while (entering[j]) |
|
48 ; |
|
49 |
|
50 // Wait until all threads with smaller ticket numbers or with the same |
|
51 // ticket number, but with higher priority, finish their work. |
|
52 while ((ticket[j] != 0) && ((ticket[j] < ticket[i]) || |
|
53 ((ticket[j] == ticket[i]) && (i < j)))) |
|
54 ; |
|
55 } |
|
56 } |
|
57 |
|
58 function unlock(i) { |
|
59 ticket[i] = 0; |
|
60 } |
|
61 |
|
62 function worker(i) { |
|
63 for (let k = 0; k < LOOP_COUNT; k++) { |
|
64 lock(i); |
|
65 |
|
66 // The critical section |
|
67 let x = counter; |
|
68 sleep(0.003); |
|
69 counter = x + 1; |
|
70 |
|
71 unlock(i); |
|
72 } |
|
73 return 'ok'; |
|
74 } |
|
75 |
|
76 function makeWorker(id) { |
|
77 return function () { return worker(id); }; |
|
78 } |
|
79 |
|
80 var expect; |
|
81 var actual; |
|
82 |
|
83 if (typeof scatter == 'undefined' || typeof sleep == 'undefined') { |
|
84 print('Test skipped. scatter or sleep not defined.'); |
|
85 expect = actual = 'Test skipped.'; |
|
86 } else { |
|
87 scatter([makeWorker(i) for (i in range(N))]); |
|
88 |
|
89 expect = "counter: " + (N * LOOP_COUNT); |
|
90 actual = "counter: " + counter; |
|
91 } |
|
92 |
|
93 reportCompare(expect, actual, summary); |