@@ -47,10 +47,12 @@ internal class WorkQueue {
47
47
* [T2] changeProducerIndex (3)
48
48
* [T3] changeConsumerIndex (4)
49
49
*
50
- * Which can lead to resulting size bigger than actual size at any moment of time.
51
- * This is in general harmless because steal will be blocked by timer
50
+ * Which can lead to resulting size being negative or bigger than actual size at any moment of time.
51
+ * This is in general harmless because steal will be blocked by timer.
52
+ * Negative sizes can be observed only when non-owner reads the size, which happens only
53
+ * for diagnostic toString().
52
54
*/
53
- internal val bufferSize: Int get() = producerIndex.value - consumerIndex.value
55
+ private val bufferSize: Int get() = producerIndex.value - consumerIndex.value
54
56
internal val size: Int get() = if (lastScheduledTask.value != null ) bufferSize + 1 else bufferSize
55
57
private val buffer: AtomicReferenceArray <Task ?> = AtomicReferenceArray (BUFFER_CAPACITY )
56
58
private val lastScheduledTask = atomic<Task ?>(null )
@@ -134,6 +136,32 @@ internal class WorkQueue {
134
136
return tryStealLastScheduled(stolenTaskRef, blockingOnly = true )
135
137
}
136
138
139
+ // Polls for blocking task, invoked only by the owner
140
+ fun pollBlocking (): Task ? {
141
+ while (true ) { // Poll the slot
142
+ val lastScheduled = lastScheduledTask.value ? : break
143
+ if (! lastScheduled.isBlocking) break
144
+ if (lastScheduledTask.compareAndSet(lastScheduled, null )) {
145
+ return lastScheduled
146
+ } // Failed -> someone else stole it
147
+ }
148
+
149
+ val start = consumerIndex.value
150
+ var end = producerIndex.value
151
+
152
+ while (start != end) {
153
+ -- end
154
+ val index = end and MASK
155
+ if (blockingTasksInBuffer.value == 0 ) break
156
+ val value = buffer[index]
157
+ if (value != null && value.isBlocking && buffer.compareAndSet(index, value, null )) {
158
+ blockingTasksInBuffer.decrementAndGet()
159
+ return value
160
+ }
161
+ }
162
+ return null
163
+ }
164
+
137
165
fun offloadAllWorkTo (globalQueue : GlobalQueue ) {
138
166
lastScheduledTask.getAndSet(null )?.let { globalQueue.addLast(it) }
139
167
while (pollTo(globalQueue)) {
0 commit comments