Tizen 2.1 base
[platform/upstream/gcd.git] / dispatch-1.0 / src / source.c
1 /*
2  * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
3  *
4  * @APPLE_APACHE_LICENSE_HEADER_START@
5  * 
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  * 
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  * 
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  * 
18  * @APPLE_APACHE_LICENSE_HEADER_END@
19  */
20
21 #include "internal.h"
22 #if HAVE_MACH
23 #include "protocol.h"
24 #include "protocolServer.h"
25 #endif
26 #include <sys/mount.h>
27
28 #ifndef DISPATCH_NO_LEGACY
29 struct dispatch_source_attr_vtable_s {
30         DISPATCH_VTABLE_HEADER(dispatch_source_attr_s);
31 };
32
33 struct dispatch_source_attr_s {
34         DISPATCH_STRUCT_HEADER(dispatch_source_attr_s, dispatch_source_attr_vtable_s);
35         void* finalizer_ctxt;
36         dispatch_source_finalizer_function_t finalizer_func;
37         void* context;
38 };
39 #endif /* DISPATCH_NO_LEGACY */
40
41 #define _dispatch_source_call_block ((void *)-1)
42 static void _dispatch_source_latch_and_call(dispatch_source_t ds);
43 static void _dispatch_source_cancel_callout(dispatch_source_t ds);
44 static size_t dispatch_source_debug_attr(dispatch_source_t ds, char* buf, size_t bufsiz);
45
46 void
47 dispatch_source_cancel(dispatch_source_t ds)
48 {
49 #if DISPATCH_DEBUG
50         dispatch_debug(ds, __FUNCTION__);
51 #endif
52         // Right after we set the cancel flag, someone else
53         // could potentially invoke the source, do the cancelation, 
54         // unregister the source, and deallocate it. We would
55         // need to therefore retain/release before setting the bit
56
57         _dispatch_retain(ds);
58         dispatch_atomic_or(&ds->ds_atomic_flags, DSF_CANCELED);
59         _dispatch_wakeup(ds);
60         _dispatch_release(ds);
61 }
62
63 DISPATCH_NOINLINE
64 void
65 _dispatch_source_xref_release(dispatch_source_t ds)
66 {
67 #ifndef DISPATCH_NO_LEGACY
68         if (ds->ds_is_legacy) {
69                 if (!(ds->ds_timer.flags & DISPATCH_TIMER_ONESHOT)) {
70                         dispatch_source_cancel(ds);
71                 }
72                 // Clients often leave sources suspended at the last release
73                 dispatch_atomic_and(&ds->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_LOCK);
74         } else
75 #endif
76         if (slowpath(DISPATCH_OBJECT_SUSPENDED(ds))) {
77                 // Arguments for and against this assert are within 6705399
78                 DISPATCH_CLIENT_CRASH("Release of a suspended object");
79         }
80         _dispatch_wakeup(ds);
81         _dispatch_release(ds);
82 }
83
84 long
85 dispatch_source_testcancel(dispatch_source_t ds)
86 {
87         return (bool)(ds->ds_atomic_flags & DSF_CANCELED);
88 }
89
90
91 unsigned long
92 dispatch_source_get_mask(dispatch_source_t ds)
93 {
94         return ds->ds_pending_data_mask;
95 }
96
97 uintptr_t
98 dispatch_source_get_handle(dispatch_source_t ds)
99 {
100         return (int)ds->ds_ident_hack;
101 }
102
103 unsigned long
104 dispatch_source_get_data(dispatch_source_t ds)
105 {
106         return ds->ds_data;
107 }
108
109 dispatch_queue_t
110 _dispatch_source_invoke(dispatch_source_t ds)
111 {
112         // This function performs all source actions. Each action is responsible
113         // for verifying that it takes place on the appropriate queue. If the
114         // current queue is not the correct queue for this action, the correct queue
115         // will be returned and the invoke will be re-driven on that queue.
116
117         // The order of tests here in invoke and in probe should be consistent.
118         
119         dispatch_queue_t dq = _dispatch_queue_get_current();
120
121         if (!ds->ds_is_installed) {
122                 // The source needs to be installed on the manager queue.
123                 if (dq != &_dispatch_mgr_q) {
124                         return &_dispatch_mgr_q;
125                 }
126                 _dispatch_kevent_merge(ds);
127         } else if ((ds->ds_atomic_flags & DSF_CANCELED) || (ds->do_xref_cnt == 0)) {
128                 // The source has been cancelled and needs to be uninstalled from the
129                 // manager queue. After uninstallation, the cancellation handler needs
130                 // to be delivered to the target queue.
131                 if (ds->ds_dkev) {
132                         if (dq != &_dispatch_mgr_q) {
133                                 return &_dispatch_mgr_q;
134                         }
135                         _dispatch_kevent_release(ds);
136                         return ds->do_targetq;
137                 } else if (ds->ds_cancel_handler) {
138                         if (dq != ds->do_targetq) {
139                                 return ds->do_targetq;
140                         }
141                 }       
142                 _dispatch_source_cancel_callout(ds);
143         } else if (ds->ds_pending_data) {
144                 // The source has pending data to deliver via the event handler callback
145                 // on the target queue. Some sources need to be rearmed on the manager
146                 // queue after event delivery.
147                 if (dq != ds->do_targetq) {
148                         return ds->do_targetq;
149                 }
150                 _dispatch_source_latch_and_call(ds);
151                 if (ds->ds_needs_rearm) {
152                         return &_dispatch_mgr_q;
153                 }
154         } else if (ds->ds_needs_rearm && !ds->ds_is_armed) {
155                 // The source needs to be rearmed on the manager queue.
156                 if (dq != &_dispatch_mgr_q) {
157                         return &_dispatch_mgr_q;
158                 }
159                 _dispatch_source_kevent_resume(ds, 0, 0);
160                 ds->ds_is_armed = true;
161         }
162
163         return NULL;
164 }
165
166 bool
167 _dispatch_source_probe(dispatch_source_t ds)
168 {
169         // This function determines whether the source needs to be invoked.
170         // The order of tests here in probe and in invoke should be consistent.
171
172         if (!ds->ds_is_installed) {
173                 // The source needs to be installed on the manager queue.
174                 return true;
175         } else if ((ds->ds_atomic_flags & DSF_CANCELED) || (ds->do_xref_cnt == 0)) {
176                 // The source needs to be uninstalled from the manager queue, or the
177                 // cancellation handler needs to be delivered to the target queue.
178                 // Note: cancellation assumes installation.
179                 if (ds->ds_dkev || ds->ds_cancel_handler) {
180                         return true;
181                 }
182         } else if (ds->ds_pending_data) {
183                 // The source has pending data to deliver to the target queue.
184                 return true;
185         } else if (ds->ds_needs_rearm && !ds->ds_is_armed) {
186                 // The source needs to be rearmed on the manager queue.
187                 return true;
188         }
189         // Nothing to do.
190         return false;
191 }
192
193 void
194 _dispatch_source_dispose(dispatch_source_t ds)
195 {
196         _dispatch_queue_dispose((dispatch_queue_t)ds);
197 }
198
199 void
200 _dispatch_source_latch_and_call(dispatch_source_t ds)
201 {
202         unsigned long prev;
203
204         if ((ds->ds_atomic_flags & DSF_CANCELED) || (ds->do_xref_cnt == 0)) {
205                 return;
206         }
207         prev = dispatch_atomic_xchg(&ds->ds_pending_data, 0);
208         if (ds->ds_is_level) {
209                 ds->ds_data = ~prev;
210         } else {
211                 ds->ds_data = prev;
212         }
213         if (dispatch_assume(prev)) {
214                 if (ds->ds_handler_func) {
215 #ifndef DISPATCH_NO_LEGACY
216                         ((dispatch_source_handler_function_t)ds->ds_handler_func)(ds->ds_handler_ctxt, ds);
217 #else
218                         ds->ds_handler_func(ds->ds_handler_ctxt);
219 #endif
220                 }
221         }
222 }
223
224 void
225 _dispatch_source_cancel_callout(dispatch_source_t ds)
226 {
227         ds->ds_pending_data_mask = 0;
228         ds->ds_pending_data = 0;
229         ds->ds_data = 0;
230
231 #ifdef __BLOCKS__
232         if (ds->ds_handler_is_block) {
233                 Block_release(ds->ds_handler_ctxt);
234                 ds->ds_handler_is_block = false;
235                 ds->ds_handler_func = NULL;
236                 ds->ds_handler_ctxt = NULL;
237         }
238 #endif
239
240         if (!ds->ds_cancel_handler) {
241                 return;
242         }
243         if (ds->ds_cancel_is_block) {
244 #ifdef __BLOCKS__
245                 dispatch_block_t b = ds->ds_cancel_handler;
246                 if (ds->ds_atomic_flags & DSF_CANCELED) {
247                         b();
248                 }
249                 Block_release(ds->ds_cancel_handler);
250                 ds->ds_cancel_is_block = false;
251 #endif
252         } else {
253                 dispatch_function_t f = ds->ds_cancel_handler;
254                 if (ds->ds_atomic_flags & DSF_CANCELED) {
255                         f(ds->do_ctxt);
256                 }
257         }
258         ds->ds_cancel_handler = NULL;
259 }
260
261 size_t
262 dispatch_source_debug_attr(dispatch_source_t ds, char* buf, size_t bufsiz)
263 {
264         dispatch_queue_t target = ds->do_targetq;
265         return snprintf(buf, bufsiz,
266                         "target = %s[%p], pending_data = 0x%lx, pending_data_mask = 0x%lx, ",
267                         target ? target->dq_label : "", target,
268                         ds->ds_pending_data, ds->ds_pending_data_mask);
269 }
270
271 size_t
272 _dispatch_source_debug(dispatch_source_t ds, char* buf, size_t bufsiz)
273 {
274         size_t offset = 0;
275         offset += snprintf(&buf[offset], bufsiz - offset, "%s[%p] = { ", dx_kind(ds), ds);
276         offset += dispatch_object_debug_attr(ds, &buf[offset], bufsiz - offset);
277         offset += dispatch_source_debug_attr(ds, &buf[offset], bufsiz - offset);
278         return offset;
279 }
280
281 #ifndef DISPATCH_NO_LEGACY
282 static void
283 dispatch_source_attr_dispose(dispatch_source_attr_t attr)
284 {
285         // release the finalizer block if necessary
286         dispatch_source_attr_set_finalizer(attr, NULL);
287         _dispatch_dispose(attr);
288 }
289
290 static const struct dispatch_source_attr_vtable_s dispatch_source_attr_vtable = {
291         .do_type = DISPATCH_SOURCE_ATTR_TYPE,
292         .do_kind = "source-attr",
293         .do_dispose = dispatch_source_attr_dispose,
294 };
295
296 dispatch_source_attr_t
297 dispatch_source_attr_create(void)
298 {
299         dispatch_source_attr_t rval = calloc(1, sizeof(struct dispatch_source_attr_s));
300
301         if (rval) {
302                 rval->do_vtable = &dispatch_source_attr_vtable;
303                 rval->do_next = DISPATCH_OBJECT_LISTLESS;
304                 rval->do_targetq = dispatch_get_global_queue(0, 0);
305                 rval->do_ref_cnt = 1;
306                 rval->do_xref_cnt = 1;
307         }
308
309         return rval;
310 }
311
312 void
313 dispatch_source_attr_set_finalizer_f(dispatch_source_attr_t attr,
314         void *context, dispatch_source_finalizer_function_t finalizer)
315 {
316 #ifdef __BLOCKS__
317         if (attr->finalizer_func == (void*)_dispatch_call_block_and_release2) {
318                 Block_release(attr->finalizer_ctxt);
319         }
320 #endif
321
322         attr->finalizer_ctxt = context;
323         attr->finalizer_func = finalizer;
324 }
325
326 #ifdef __BLOCKS__
327 long
328 dispatch_source_attr_set_finalizer(dispatch_source_attr_t attr,
329         dispatch_source_finalizer_t finalizer)
330 {
331         void *ctxt;
332         dispatch_source_finalizer_function_t func;
333
334         if (finalizer) {
335                 if (!(ctxt = Block_copy(finalizer))) {
336                         return 1;
337                 }
338                 func = (void *)_dispatch_call_block_and_release2;
339         } else {
340                 ctxt = NULL;
341                 func = NULL;
342         }
343
344         dispatch_source_attr_set_finalizer_f(attr, ctxt, func);
345
346         return 0;
347 }
348
349 dispatch_source_finalizer_t
350 dispatch_source_attr_get_finalizer(dispatch_source_attr_t attr)
351 {
352         if (attr->finalizer_func == (void*)_dispatch_call_block_and_release2) {
353                 return (dispatch_source_finalizer_t)attr->finalizer_ctxt;
354         } else if (attr->finalizer_func == NULL) {
355                 return NULL;
356         } else {
357                 abort(); // finalizer is not a block...
358         }
359 }
360 #endif
361
362 void
363 dispatch_source_attr_set_context(dispatch_source_attr_t attr, void *context)
364 {
365         attr->context = context;
366 }
367
368 dispatch_source_attr_t
369 dispatch_source_attr_copy(dispatch_source_attr_t proto)
370 {
371         dispatch_source_attr_t rval = NULL;
372
373         if (proto && (rval = malloc(sizeof(struct dispatch_source_attr_s)))) {
374                 memcpy(rval, proto, sizeof(struct dispatch_source_attr_s));
375 #ifdef __BLOCKS__
376                 if (rval->finalizer_func == (void*)_dispatch_call_block_and_release2) {
377                         rval->finalizer_ctxt = Block_copy(rval->finalizer_ctxt);
378                 }
379 #endif
380         } else if (!proto) {
381                 rval = dispatch_source_attr_create();
382         }
383         return rval;
384 }
385 #endif /* DISPATCH_NO_LEGACY */
386
387
388 dispatch_source_t
389 dispatch_source_create(dispatch_source_type_t type,
390         uintptr_t handle,
391         unsigned long mask,
392         dispatch_queue_t q)
393 {
394         dispatch_source_t ds = NULL;
395         static char source_label[sizeof(ds->dq_label)] = "source";
396
397         // input validation
398         if (type == NULL || (mask & ~type->mask)) {
399                 goto out_bad;
400         }
401
402         ds = calloc(1ul, sizeof(struct dispatch_source_s));
403         if (slowpath(!ds)) {
404                 goto out_bad;
405         }
406
407         // Initialize as a queue first, then override some settings below.
408         _dispatch_queue_init((dispatch_queue_t)ds);
409         memcpy(ds->dq_label, source_label, sizeof(source_label));
410
411         // Dispatch Object
412         ds->do_vtable = &_dispatch_source_kevent_vtable;
413         ds->do_ref_cnt++; // the reference the manger queue holds
414         ds->do_suspend_cnt = DISPATCH_OBJECT_SUSPEND_INTERVAL;
415         // do_targetq will be retained below, past point of no-return
416         ds->do_targetq = q;
417
418         if (slowpath(!type->init(ds, type, handle, mask, q))) {
419                 goto out_bad;
420         }
421
422         dispatch_assert(!(ds->ds_is_level && ds->ds_is_adder));
423 #if DISPATCH_DEBUG
424         dispatch_debug(ds, __FUNCTION__);
425 #endif
426
427         _dispatch_retain(ds->do_targetq);
428         return ds;
429         
430 out_bad:
431         free(ds);
432         return NULL;
433 }
434
435 #ifdef __BLOCKS__
436 // 6618342 Contact the team that owns the Instrument DTrace probe before renaming this symbol
437 static void
438 _dispatch_source_set_event_handler2(void *context)
439 {
440         struct Block_layout *bl = context;
441
442         dispatch_source_t ds = (dispatch_source_t)_dispatch_queue_get_current();
443         dispatch_assert(ds->do_vtable == &_dispatch_source_kevent_vtable);
444         
445         if (ds->ds_handler_is_block && ds->ds_handler_ctxt) {
446                 Block_release(ds->ds_handler_ctxt);
447         }
448         ds->ds_handler_func = bl ? (void *)bl->invoke : NULL;
449         ds->ds_handler_ctxt = bl;
450         ds->ds_handler_is_block = true;
451 }
452
453 void
454 dispatch_source_set_event_handler(dispatch_source_t ds, dispatch_block_t handler)
455 {
456         dispatch_assert(!ds->ds_is_legacy);
457         handler = _dispatch_Block_copy(handler);
458         dispatch_barrier_async_f((dispatch_queue_t)ds,
459                 handler, _dispatch_source_set_event_handler2);
460 }
461 #endif /* __BLOCKS__ */
462
463 static void
464 _dispatch_source_set_event_handler_f(void *context)
465 {
466         dispatch_source_t ds = (dispatch_source_t)_dispatch_queue_get_current();
467         dispatch_assert(ds->do_vtable == &_dispatch_source_kevent_vtable);
468         
469 #ifdef __BLOCKS__
470         if (ds->ds_handler_is_block && ds->ds_handler_ctxt) {
471                 Block_release(ds->ds_handler_ctxt);
472         }
473 #endif
474         ds->ds_handler_func = context;
475         ds->ds_handler_ctxt = ds->do_ctxt;
476         ds->ds_handler_is_block = false;
477 }
478
479 void
480 dispatch_source_set_event_handler_f(dispatch_source_t ds,
481         dispatch_function_t handler)
482 {
483         dispatch_assert(!ds->ds_is_legacy);
484         dispatch_barrier_async_f((dispatch_queue_t)ds,
485                 handler, _dispatch_source_set_event_handler_f);
486 }
487
488 #ifdef __BLOCKS__
489 // 6618342 Contact the team that owns the Instrument DTrace probe before renaming this symbol
490 static void
491 _dispatch_source_set_cancel_handler2(void *context)
492 {
493         dispatch_source_t ds = (dispatch_source_t)_dispatch_queue_get_current();
494         dispatch_assert(ds->do_vtable == &_dispatch_source_kevent_vtable);
495         
496         if (ds->ds_cancel_is_block && ds->ds_cancel_handler) {
497                 Block_release(ds->ds_cancel_handler);
498         }
499         ds->ds_cancel_handler = context;
500         ds->ds_cancel_is_block = true;
501 }
502
503 void
504 dispatch_source_set_cancel_handler(dispatch_source_t ds,
505         dispatch_block_t handler)
506 {
507         dispatch_assert(!ds->ds_is_legacy);
508         handler = _dispatch_Block_copy(handler);
509         dispatch_barrier_async_f((dispatch_queue_t)ds,
510                                                          handler, _dispatch_source_set_cancel_handler2);
511 }
512 #endif /* __BLOCKS__ */
513
514 static void
515 _dispatch_source_set_cancel_handler_f(void *context)
516 {
517         dispatch_source_t ds = (dispatch_source_t)_dispatch_queue_get_current();
518         dispatch_assert(ds->do_vtable == &_dispatch_source_kevent_vtable);
519         
520 #ifdef __BLOCKS__
521         if (ds->ds_cancel_is_block && ds->ds_cancel_handler) {
522                 Block_release(ds->ds_cancel_handler);
523         }
524 #endif
525         ds->ds_cancel_handler = context;
526         ds->ds_cancel_is_block = false;
527 }
528
529 void
530 dispatch_source_set_cancel_handler_f(dispatch_source_t ds,
531         dispatch_function_t handler)
532 {
533         dispatch_assert(!ds->ds_is_legacy);
534         dispatch_barrier_async_f((dispatch_queue_t)ds,
535                                                          handler, _dispatch_source_set_cancel_handler_f);
536 }
537
538 #ifndef DISPATCH_NO_LEGACY
539 // 6618342 Contact the team that owns the Instrument DTrace probe before renaming this symbol
540 dispatch_source_t
541 _dispatch_source_create2(dispatch_source_t ds,
542         dispatch_source_attr_t attr,
543         void *context,
544         dispatch_source_handler_function_t handler)
545 {
546         if (ds == NULL || handler == NULL) {
547                 return NULL;
548         }
549
550         ds->ds_is_legacy = true;
551
552         ds->ds_handler_func = (dispatch_function_t)handler;
553         ds->ds_handler_ctxt = context;
554                 
555         if (attr && attr != DISPATCH_SOURCE_CREATE_SUSPENDED) {
556                 ds->dq_finalizer_ctxt = attr->finalizer_ctxt;
557                 ds->dq_finalizer_func = (typeof(ds->dq_finalizer_func))attr->finalizer_func;
558                 ds->do_ctxt = attr->context;
559         }
560 #ifdef __BLOCKS__
561         if (ds->dq_finalizer_func == (void*)_dispatch_call_block_and_release2) {
562                 ds->dq_finalizer_ctxt = Block_copy(ds->dq_finalizer_ctxt);
563                 if (!ds->dq_finalizer_ctxt) {
564                         goto out_bad;
565                 }
566         }
567         if (handler == _dispatch_source_call_block) {
568                 struct Block_layout *bl = ds->ds_handler_ctxt = Block_copy(context);
569                 if (!ds->ds_handler_ctxt) {
570                         if (ds->dq_finalizer_func == (void*)_dispatch_call_block_and_release2) {
571                                 Block_release(ds->dq_finalizer_ctxt);
572                         }
573                         goto out_bad;
574                 }
575                 ds->ds_handler_func = (void *)bl->invoke;
576                 ds->ds_handler_is_block = true;
577         }
578
579         // all legacy sources get a cancellation event on the normal event handler.
580         dispatch_function_t func = ds->ds_handler_func;
581         dispatch_source_handler_t block = ds->ds_handler_ctxt;
582         void *ctxt = ds->ds_handler_ctxt;
583         bool handler_is_block = ds->ds_handler_is_block;
584         
585         ds->ds_cancel_is_block = true;
586         if (handler_is_block) {
587                 ds->ds_cancel_handler = _dispatch_Block_copy(^{
588                         block(ds);
589                 });
590         } else {
591                 ds->ds_cancel_handler = _dispatch_Block_copy(^{
592                         ((dispatch_source_handler_function_t)func)(ctxt, ds);
593                 });
594         }
595 #endif
596         if (attr != DISPATCH_SOURCE_CREATE_SUSPENDED) {
597                 dispatch_resume(ds);
598         }
599
600         return ds;
601
602 #ifdef __BLOCKS__
603 out_bad:
604         free(ds);
605         return NULL;
606 #endif
607 }
608
609 long
610 dispatch_source_get_error(dispatch_source_t ds, long *err_out)
611 {
612         // 6863892 don't report ECANCELED until kevent is unregistered
613         if ((ds->ds_atomic_flags & DSF_CANCELED) && !ds->ds_dkev) {
614                 if (err_out) {
615                         *err_out = ECANCELED;
616                 }
617                 return DISPATCH_ERROR_DOMAIN_POSIX;
618         } else {
619                 return DISPATCH_ERROR_DOMAIN_NO_ERROR;
620         }
621 }
622 #endif /* DISPATCH_NO_LEGACY */
623
624 // To be called from the context of the _dispatch_mgr_q
625 static void
626 _dispatch_source_set_timer2(void *context)
627 {
628         struct dispatch_set_timer_params *params = context;
629         dispatch_source_t ds = params->ds;
630         ds->ds_ident_hack = params->ident;
631         ds->ds_timer = params->values;
632         _dispatch_timer_list_update(ds);
633         dispatch_resume(ds);
634         dispatch_release(ds);
635         free(params);
636 }
637
638 void
639 dispatch_source_set_timer(dispatch_source_t ds,
640         dispatch_time_t start,
641         uint64_t interval,
642         uint64_t leeway)
643 {
644         struct dispatch_set_timer_params *params;
645         
646         // we use zero internally to mean disabled
647         if (interval == 0) {
648                 interval = 1;
649         } else if ((int64_t)interval < 0) {
650                 // 6866347 - make sure nanoseconds won't overflow
651                 interval = INT64_MAX;
652         }
653
654         // Suspend the source so that it doesn't fire with pending changes
655         // The use of suspend/resume requires the external retain/release
656         dispatch_retain(ds);
657         dispatch_suspend(ds);
658         
659         if (start == DISPATCH_TIME_NOW) {
660                 start = _dispatch_absolute_time();
661         } else if (start == DISPATCH_TIME_FOREVER) {
662                 start = INT64_MAX;
663         }
664         if ((int64_t)leeway < 0) {
665                 leeway = INT64_MAX;
666         }
667
668         while (!(params = malloc(sizeof(struct dispatch_set_timer_params)))) {
669                 sleep(1);
670         }
671
672         params->ds = ds;
673         params->values.flags = ds->ds_timer.flags;
674
675         if ((int64_t)start < 0) {
676                 // wall clock
677                 params->ident = DISPATCH_TIMER_INDEX_WALL;
678                 params->values.start = -((int64_t)start);
679                 params->values.target = -((int64_t)start);
680                 params->values.interval = interval;
681                 params->values.leeway = leeway;
682                 params->values.flags |= DISPATCH_TIMER_WALL_CLOCK;
683         } else {
684                 // absolute clock
685                 params->ident = DISPATCH_TIMER_INDEX_MACH;
686                 params->values.start = start;
687                 params->values.target = start;
688                 params->values.interval = _dispatch_time_nano2mach(interval);
689                 params->values.leeway = _dispatch_time_nano2mach(leeway);
690                 params->values.flags &= ~DISPATCH_TIMER_WALL_CLOCK;
691         }
692
693         dispatch_barrier_async_f(&_dispatch_mgr_q, params, _dispatch_source_set_timer2);
694 }
695
696 #ifndef DISPATCH_NO_LEGACY
697 // LEGACY
698 long
699 dispatch_source_timer_set_time(dispatch_source_t ds, uint64_t nanoseconds, uint64_t leeway)
700 {
701         dispatch_time_t start;
702         if (nanoseconds == 0) {
703                 nanoseconds = 1;
704         }
705         if (ds->ds_timer.flags == (DISPATCH_TIMER_ABSOLUTE|DISPATCH_TIMER_WALL_CLOCK)) {
706                 static const struct timespec t0;
707                 start = dispatch_walltime(&t0, nanoseconds);
708         } else if (ds->ds_timer.flags & DISPATCH_TIMER_WALL_CLOCK) {
709                 start = dispatch_walltime(DISPATCH_TIME_NOW, nanoseconds);
710         } else {
711                 start = dispatch_time(DISPATCH_TIME_NOW, nanoseconds);
712         }
713         if (ds->ds_timer.flags & (DISPATCH_TIMER_ABSOLUTE|DISPATCH_TIMER_ONESHOT)) {
714                 // 6866347 - make sure nanoseconds won't overflow
715                 nanoseconds = INT64_MAX; // non-repeating (~292 years)
716         }
717         dispatch_source_set_timer(ds, start, nanoseconds, leeway);
718         return 0;
719 }
720
721 // LEGACY
722 uint64_t
723 dispatch_event_get_nanoseconds(dispatch_source_t ds)
724 {
725         if (ds->ds_timer.flags & DISPATCH_TIMER_WALL_CLOCK) {
726                 return ds->ds_timer.interval;
727         } else {
728                 return _dispatch_time_mach2nano(ds->ds_timer.interval);
729         }
730 }
731 #endif /* DISPATCH_NO_LEGACY */
732