@@ -63,9 +63,27 @@ using namespace swift;
63
63
SWIFT_CC (swift)
64
64
void (*swift::swift_task_enqueueGlobal_hook)(Job *job) = nullptr;
65
65
66
+ SWIFT_CC (swift)
67
+ void (*swift::swift_task_enqueueGlobalWithDelay_hook)(unsigned long long delay, Job *job) = nullptr;
68
+
66
69
#if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
70
+
71
+ #include < chrono>
72
+ #include < thread>
73
+
67
74
static Job *JobQueue = nullptr ;
68
75
76
+ class DelayedJob {
77
+ public:
78
+ Job *job;
79
+ unsigned long long when;
80
+ DelayedJob *next;
81
+
82
+ DelayedJob (Job *job, unsigned long long when) : job(job), when(when), next(nullptr ) {}
83
+ };
84
+
85
+ static DelayedJob *DelayedJobQueue = nullptr ;
86
+
69
87
// / Get the next-in-queue storage slot.
70
88
static Job *&nextInQueue (Job *cur) {
71
89
return reinterpret_cast <Job*&>(cur->SchedulerPrivate );
@@ -89,13 +107,58 @@ static void insertIntoJobQueue(Job *newJob) {
89
107
*position = newJob;
90
108
}
91
109
110
+ static unsigned long long currentNanos () {
111
+ auto now = std::chrono::steady_clock::now ();
112
+ auto nowNanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
113
+ auto value = std::chrono::duration_cast<std::chrono::nanoseconds>(nowNanos.time_since_epoch ());
114
+ return value.count ();
115
+ }
116
+
117
+ // / Insert a job into the cooperative global queue.
118
+ static void insertIntoDelayedJobQueue (unsigned long long delay, Job *job) {
119
+ DelayedJob **position = &DelayedJobQueue;
120
+ DelayedJob *newJob = new DelayedJob (job, currentNanos () + delay);
121
+
122
+ while (auto cur = *position) {
123
+ // If we find a job with lower priority, insert here.
124
+ if (cur->when > newJob->when ) {
125
+ newJob->next = cur;
126
+ *position = newJob;
127
+ return ;
128
+ }
129
+
130
+ // Otherwise, keep advancing through the queue.
131
+ position = &cur->next ;
132
+ }
133
+ *position = newJob;
134
+ }
135
+
92
136
// / Claim the next job from the cooperative global queue.
93
137
static Job *claimNextFromJobQueue () {
94
- if (auto job = JobQueue) {
95
- JobQueue = nextInQueue (job);
96
- return job;
138
+ // Check delayed jobs first
139
+ while (true ) {
140
+ if (auto delayedJob = DelayedJobQueue) {
141
+ if (delayedJob->when < currentNanos ()) {
142
+ DelayedJobQueue = delayedJob->next ;
143
+ auto job = delayedJob->job ;
144
+
145
+ delete delayedJob;
146
+
147
+ return job;
148
+ }
149
+ }
150
+ if (auto job = JobQueue) {
151
+ JobQueue = nextInQueue (job);
152
+ return job;
153
+ }
154
+ // there are only delayed jobs left, but they are not ready,
155
+ // so we sleep until the first one is
156
+ if (auto delayedJob = DelayedJobQueue) {
157
+ std::this_thread::sleep_for (std::chrono::nanoseconds (delayedJob->when - currentNanos ()));
158
+ continue ;
159
+ }
160
+ return nullptr ;
97
161
}
98
- return nullptr ;
99
162
}
100
163
101
164
void swift::donateThreadToGlobalExecutorUntil (bool (*condition)(void *),
@@ -177,6 +240,30 @@ void swift::swift_task_enqueueGlobal(Job *job) {
177
240
#endif
178
241
}
179
242
243
+ void swift::swift_task_enqueueGlobalWithDelay (unsigned long long delay, Job *job) {
244
+ assert (job && " no job provided" );
245
+
246
+ // If the hook is defined, use it.
247
+ if (swift_task_enqueueGlobalWithDelay_hook)
248
+ return swift_task_enqueueGlobalWithDelay_hook (delay, job);
249
+
250
+ #if SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
251
+ insertIntoDelayedJobQueue (delay, job);
252
+ #else
253
+
254
+ dispatch_function_t dispatchFunction = &__swift_run_job;
255
+ void *dispatchContext = job;
256
+
257
+ JobPriority priority = job->getPriority ();
258
+
259
+ // TODO: cache this to avoid the extra call
260
+ auto queue = dispatch_get_global_queue ((dispatch_qos_class_t ) priority,
261
+ /* flags*/ 0 );
262
+ dispatch_time_t when = dispatch_time (DISPATCH_TIME_NOW, delay);
263
+ dispatch_after_f (when, queue, dispatchContext, dispatchFunction);
264
+ #endif
265
+ }
266
+
180
267
181
268
// / Enqueues a task on the main executor.
182
269
// / FIXME: only exists for the quick-and-dirty MainActor implementation.
0 commit comments