24
24
25
25
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
26
26
#include < dispatch/dispatch.h>
27
-
28
27
#if !defined(_WIN32)
29
28
#include < dlfcn.h>
30
29
#endif
31
-
32
30
#endif
33
31
34
32
// Ensure that Job's layout is compatible with what Dispatch expects.
@@ -226,6 +224,74 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
226
224
}
227
225
228
226
#define DISPATCH_UP_OR_MONOTONIC_TIME_MASK (1ULL << 63 )
227
+ #define DISPATCH_WALLTIME_MASK (1ULL << 62 )
228
+ #define DISPATCH_TIME_MAX_VALUE (DISPATCH_WALLTIME_MASK - 1 )
229
+
230
+ struct __swift_job_source {
231
+ dispatch_source_t source;
232
+ Job *job;
233
+ };
234
+
235
+ static void _swift_run_job_leeway (struct __swift_job_source *jobSource) {
236
+ dispatch_source_t source = jobSource->source ;
237
+ dispatch_release (source);
238
+ Job *job = jobSource->job ;
239
+ auto task = dyn_cast<AsyncTask>(job);
240
+ assert (task && " provided job must be a task" );
241
+ _swift_task_dealloc_specific (task, jobSource);
242
+ __swift_run_job (job);
243
+ }
244
+
245
+ #if defined(__i386__) || defined(__x86_64__) || !defined(__APPLE__)
246
+ #define TIME_UNIT_USES_NANOSECONDS 1
247
+ #else
248
+ #define TIME_UNIT_USES_NANOSECONDS 0
249
+ #endif
250
+
251
+ #if TIME_UNIT_USES_NANOSECONDS
252
+ // x86 currently implements mach time in nanoseconds
253
+ // this is NOT likely to change
254
+ static inline uint64_t
255
+ platform_time (uint64_t nsec) {
256
+ return nsec;
257
+ }
258
+ #else
259
+ #define DISPATCH_USE_HOST_TIME 1
260
+ #if defined(__APPLE__)
261
+ #if defined(__arm__) || defined(__arm64__)
262
+ // Apple arm platforms currently use a fixed mach timebase of 125/3 (24 MHz)
263
+ static inline uint64_t
264
+ platform_time (uint64_t nsec) {
265
+ if (!nsec) {
266
+ return nsec;
267
+ }
268
+ if (nsec >= (uint64_t )INT64_MAX) {
269
+ return INT64_MAX;
270
+ }
271
+ if (nsec >= UINT64_MAX / 3ull ) {
272
+ return (nsec / 125ull ) * 3ull ;
273
+ } else {
274
+ return (nsec * 3ull ) / 125ull ;
275
+ }
276
+ }
277
+ #endif
278
+ #endif
279
+ #endif
280
+
281
+ static inline dispatch_time_t
282
+ clock_and_value_to_time (int clock, long long deadline) {
283
+ uint64_t value = platform_time ((uint64_t )deadline);
284
+ if (value >= DISPATCH_TIME_MAX_VALUE) {
285
+ return DISPATCH_TIME_FOREVER;
286
+ }
287
+ switch (clock) {
288
+ case swift_clock_id_suspending:
289
+ return value;
290
+ case swift_clock_id_continuous:
291
+ return value | DISPATCH_UP_OR_MONOTONIC_TIME_MASK;
292
+ }
293
+ __builtin_unreachable ();
294
+ }
229
295
230
296
SWIFT_CC (swift)
231
297
static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
@@ -234,9 +300,7 @@ static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
234
300
long long tnsec,
235
301
int clock, Job *job) {
236
302
assert (job && " no job provided" );
237
-
238
- dispatch_function_t dispatchFunction = &__swift_run_job;
239
- void *dispatchContext = job;
303
+ auto task = cast<AsyncTask>(job);
240
304
241
305
JobPriority priority = job->getPriority ();
242
306
@@ -245,20 +309,33 @@ static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
245
309
job->SchedulerPrivate [Job::DispatchQueueIndex] =
246
310
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
247
311
248
- long long nowSec;
249
- long long nowNsec;
250
- swift_get_time (&nowSec, &nowNsec, (swift_clock_id)clock);
312
+ uint64_t deadline = sec * NSEC_PER_SEC + nsec;
313
+ dispatch_time_t when = clock_and_value_to_time (clock, deadline);
314
+
315
+ if (tnsec != -1 ) {
316
+ uint64_t leeway = tsec * NSEC_PER_SEC + tnsec;
251
317
252
- uint64_t delta = (sec - nowSec) * NSEC_PER_SEC + nsec - nowNsec;
318
+ dispatch_source_t source =
319
+ dispatch_source_create (DISPATCH_SOURCE_TYPE_TIMER, 0 , 0 , queue);
320
+ dispatch_source_set_timer (source, when, DISPATCH_TIME_FOREVER, leeway);
253
321
254
- dispatch_time_t when = dispatch_time (DISPATCH_TIME_NOW, delta );
322
+ size_t sz = sizeof ( struct __swift_job_source );
255
323
256
- if (clock == swift_clock_id_continuous) {
257
- when |= DISPATCH_UP_OR_MONOTONIC_TIME_MASK;
324
+ struct __swift_job_source *jobSource =
325
+ (struct __swift_job_source *)_swift_task_alloc_specific (task, sz);
326
+
327
+ jobSource->job = job;
328
+ jobSource->source = source;
329
+
330
+ dispatch_set_context (source, jobSource);
331
+ dispatch_source_set_event_handler_f (source,
332
+ (dispatch_function_t )&_swift_run_job_leeway);
333
+
334
+ dispatch_activate (source);
335
+ } else {
336
+ dispatch_after_f (when, queue, (void *)job,
337
+ (dispatch_function_t )&__swift_run_job);
258
338
}
259
- // TODO: this should pass the leeway/tolerance along when it is not -1 nanoseconds
260
- // either a dispatch_source can be created or a better dispatch_after_f can be made for this
261
- dispatch_after_f (when, queue, dispatchContext, dispatchFunction);
262
339
}
263
340
264
341
SWIFT_CC (swift)
0 commit comments