|
8 | 8 |
|
9 | 9 | classPDispatchSerialQueue:PDispatchQueueBackend{ |
10 | 10 |
|
11 | | -fileprivateclassBlocks{ |
12 | | -varblocks=[Block]() |
| 11 | +privateclassBlocks{ |
| 12 | +varblocks:ContiguousArray<Block> |
13 | 13 | init(_ block:@escapingBlock){ blocks=[block]} |
14 | 14 | } |
15 | 15 |
|
16 | | -fileprivateenumItem{ |
| 16 | +privateenumItem{ |
17 | 17 | case sync(Int),async(Blocks) |
18 | 18 | } |
19 | 19 |
|
20 | | -privateletcondition=PCondition() |
21 | | -privatevarqueue=FifoQueue<Item>(),performing=1 |
| 20 | +privateletlock=PLock() |
| 21 | +privatevarperforming=false |
22 | 22 |
|
23 | 23 | init(){ |
24 | 24 | thread.start() |
25 | | -condition.lockedPerform(block:condition.wait) |
| 25 | +lock.lockedPerform(block:threadCondition.wait) |
26 | 26 | } |
27 | 27 |
|
28 | | - // MARK: -Thread |
| 28 | + // MARK: -Queue |
29 | 29 |
|
30 | | -privatelazyvarthreadCondition=PCondition(lock: condition) |
| 30 | +privatevarqueue=FifoQueue<Item>() |
31 | 31 |
|
32 | | -private lazyvarthread=PThread{[weak self]in |
33 | | -(self?.condition).map{ $0.lockedPerform(block: $0.signal)} |
34 | | -whilelet self=self{self.performLoop()} |
| 32 | +privatefunc startNextItem(){ |
| 33 | +switch queue.first{ |
| 34 | +case.sync(let index)?: syncConditions.signal(index: index) |
| 35 | +case.async?: threadCondition.signal() |
| 36 | +default: performing=false |
| 37 | +} |
35 | 38 | } |
36 | 39 |
|
37 | | - // MARK: -RunLoop |
| 40 | + // MARK: -Thread |
38 | 41 |
|
39 | | -privatefunc performLoop(){ |
40 | | - condition.lock() |
41 | | -waitAsync() |
42 | | -letblocks= queue.pop() |
43 | | -condition.unlock() |
44 | | -blocks?.asyncBlocks?.blocks.forEach{$0()} |
| 42 | +privatelazyvarthreadCondition=PCondition(lock: lock) |
| 43 | + |
| 44 | +private lazyvarthread=PThread{[weak self]in |
| 45 | +self?.lock.lock() |
| 46 | +self?.threadCondition.signal() |
| 47 | +whilelet self=self{self.runLoop()} |
45 | 48 | } |
46 | 49 |
|
47 | | -privatefunc waitAsync(){ |
48 | | -guard performing==2 || queue.first?.asyncBlocks==nilelse{return} |
49 | | - performing-=1 |
50 | | - condition.broadcast() |
51 | | - threadCondition.repeatWait(while: performing==1 || queue.first?.asyncBlocks==nil) |
52 | | - performing+=1 |
| 50 | +privatefunc runLoop(){ |
| 51 | + threadCondition.wait() |
| 52 | +while case.async(let blocks)?= queue.first{ |
| 53 | + queue.pop() |
| 54 | + lock.unlock() |
| 55 | + blocks.blocks.forEach{$0()} |
| 56 | + lock.lock() |
| 57 | +} |
| 58 | +startNextItem() |
53 | 59 | } |
54 | 60 |
|
55 | 61 | // MARK: - Async |
56 | 62 |
|
57 | | -@inlinablefuncasync(execute work:@escapingBlock){ |
58 | | - condition.lock() |
59 | | -iflet blocks= queue.last?.asyncBlocks{ |
| 63 | +funcasync(execute work:@escapingBlock){ |
| 64 | + lock.lock() |
| 65 | +defer{ lock.unlock()} |
| 66 | +if case.async(let blocks)?= queue.last{ |
60 | 67 | blocks.blocks.append(work) |
61 | 68 | }else{ |
62 | 69 | queue.push(.async(.init(work))) |
63 | | -if performing==0{ threadCondition.signal()} |
| 70 | +if performing{return} |
| 71 | + performing=true |
| 72 | + threadCondition.signal() |
64 | 73 | } |
65 | | - condition.unlock() |
66 | 74 | } |
67 | 75 |
|
68 | 76 | funcasync(flags:DispatchItemFlags, execute work:@escapingBlock){ |
69 | 77 | guard flags.contains(.enforceQoS)else{returnasync(execute: work)} |
70 | | -condition.lock() |
| 78 | +lock.lock() |
71 | 79 | queue.insertInStart(.async(.init(work))) |
72 | | -if performing==0{ threadCondition.signal()} |
73 | | -condition.unlock() |
| 80 | +if!performing{ threadCondition.signal()} |
| 81 | +lock.unlock() |
74 | 82 | } |
75 | 83 |
|
76 | 84 | // MARK: - Sync |
77 | 85 |
|
| 86 | +private lazyvarsyncConditions=PConditionStorage(lock: lock) |
78 | 87 | privatevarsyncIndex=0 |
79 | 88 |
|
80 | 89 | @discardableResultfunc sync<T>(execute work:()throws->T)rethrows->T{ |
81 | | -condition.lockedPerform{waitSync(enforce:false)} |
82 | | -defer{condition.lockedPerform(block:finishSync)} |
| 90 | +lock.lockedPerform{waitSync(enforce:false)} |
| 91 | +defer{lock.lockedPerform(block:startNextItem)} |
83 | 92 | returntrywork() |
84 | 93 | } |
85 | 94 |
|
86 | 95 | @discardableResult |
87 | 96 | func sync<T>(flags:DispatchItemFlags, execute work:()throws->T)rethrows->T{ |
88 | | -condition.lockedPerform{waitSync(enforce: flags.contains(.enforceQoS))} |
89 | | -defer{condition.lockedPerform(block:finishSync)} |
| 97 | +lock.lockedPerform{waitSync(enforce: flags.contains(.enforceQoS))} |
| 98 | +defer{lock.lockedPerform(block:startNextItem)} |
90 | 99 | returntrywork() |
91 | 100 | } |
92 | 101 |
|
93 | 102 | privatefunc waitSync(enforce:Bool){ |
94 | | -defer{ performing+=1} |
95 | | -if performing==0, queue.isEmpty{return} |
| 103 | +defer{ performing=true} |
| 104 | +guard performingelse{return} |
96 | 105 | letindex= syncIndex |
97 | 106 | syncIndex+=1 |
98 | | -enforce? queue.insertInStart(.sync(index)):queue.push(.sync(index)) |
99 | | -condition.repeatWait(while: performing!=0 || queue.first?.syncIndex!= index) |
| 107 | + queue.push(.sync(index)) |
| 108 | +syncConditions.wait(index: index) |
100 | 109 | queue.pop() |
101 | 110 | } |
102 | 111 |
|
103 | | -privatefunc finishSync(){ |
104 | | - performing-=1 |
105 | | -switch queue.first{ |
106 | | -case.sync?: condition.broadcast() |
107 | | -case.async?: threadCondition.signal() |
108 | | -default:break |
109 | | -} |
110 | | -} |
111 | | - |
112 | | -} |
113 | | - |
114 | | -extensionPDispatchSerialQueue.Item{ |
115 | | - |
116 | | -varsyncIndex:Int?{ |
117 | | -if case.sync(let index)=self{return index} |
118 | | -returnnil |
119 | | -} |
120 | | - |
121 | | -varasyncBlocks:PDispatchSerialQueue.Blocks?{ |
122 | | -if case.async(let blocks)=self{return blocks} |
123 | | -returnnil |
124 | | -} |
125 | | - |
126 | 112 | } |