1 | /* Copyright 2016 Google Inc. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. */ |
14 | |
15 | #include "nsync_cpp.h" |
16 | #include "platform.h" |
17 | #include "compiler.h" |
18 | #include "cputype.h" |
19 | #include "nsync.h" |
20 | #include "dll.h" |
21 | #include "sem.h" |
22 | #include "wait_internal.h" |
23 | #include "common.h" |
24 | #include "atomic.h" |
25 | |
26 | NSYNC_CPP_START_ |
27 | |
28 | /* Wait until one of: |
29 | w->sem is non-zero----decrement it and return 0. |
30 | abs_deadline expires---return ETIMEDOUT. |
31 | cancel_note is non-NULL and *cancel_note becomes notified---return ECANCELED. */ |
32 | int nsync_sem_wait_with_cancel_ (waiter *w, nsync_time abs_deadline, |
33 | nsync_note cancel_note) { |
34 | int sem_outcome; |
35 | if (cancel_note == NULL) { |
36 | sem_outcome = nsync_mu_semaphore_p_with_deadline (&w->sem, abs_deadline); |
37 | } else { |
38 | nsync_time cancel_time; |
39 | cancel_time = nsync_note_notified_deadline_ (cancel_note); |
40 | sem_outcome = ECANCELED; |
41 | if (nsync_time_cmp (cancel_time, nsync_time_zero) > 0) { |
42 | struct nsync_waiter_s nw; |
43 | nw.tag = NSYNC_WAITER_TAG; |
44 | nw.sem = &w->sem; |
45 | nsync_dll_init_ (&nw.q, &nw); |
46 | ATM_STORE (&nw.waiting, 1); |
47 | nw.flags = 0; |
48 | nsync_mu_lock (&cancel_note->note_mu); |
49 | cancel_time = NOTIFIED_TIME (cancel_note); |
50 | if (nsync_time_cmp (cancel_time, nsync_time_zero) > 0) { |
51 | nsync_time local_abs_deadline; |
52 | int deadline_is_nearer = 0; |
53 | cancel_note->waiters = nsync_dll_make_last_in_list_ ( |
54 | cancel_note->waiters, &nw.q); |
55 | local_abs_deadline = cancel_time; |
56 | if (nsync_time_cmp (abs_deadline, cancel_time) < 0) { |
57 | local_abs_deadline = abs_deadline; |
58 | deadline_is_nearer = 1; |
59 | } |
60 | nsync_mu_unlock (&cancel_note->note_mu); |
61 | sem_outcome = nsync_mu_semaphore_p_with_deadline (&w->sem, |
62 | local_abs_deadline); |
63 | if (sem_outcome == ETIMEDOUT && !deadline_is_nearer) { |
64 | sem_outcome = ECANCELED; |
65 | nsync_note_notify (cancel_note); |
66 | } |
67 | nsync_mu_lock (&cancel_note->note_mu); |
68 | cancel_time = NOTIFIED_TIME (cancel_note); |
69 | if (nsync_time_cmp (cancel_time, |
70 | nsync_time_zero) > 0) { |
71 | cancel_note->waiters = nsync_dll_remove_ ( |
72 | cancel_note->waiters, &nw.q); |
73 | } |
74 | } |
75 | nsync_mu_unlock (&cancel_note->note_mu); |
76 | } |
77 | } |
78 | return (sem_outcome); |
79 | } |
80 | |
81 | NSYNC_CPP_END_ |
82 | |