1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 static int
sul_compare(const lws_dll2_t * d,const lws_dll2_t * i)28 sul_compare(const lws_dll2_t *d, const lws_dll2_t *i)
29 {
30 lws_usec_t a = ((lws_sorted_usec_list_t *)d)->us;
31 lws_usec_t b = ((lws_sorted_usec_list_t *)i)->us;
32
33 /*
34 * Simply returning (a - b) in an int
35 * may lead to an integer overflow bug
36 */
37
38 if (a > b)
39 return 1;
40 if (a < b)
41 return -1;
42
43 return 0;
44 }
45
46 int
__lws_sul_insert(lws_dll2_owner_t * own,lws_sorted_usec_list_t * sul,lws_usec_t us)47 __lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul,
48 lws_usec_t us)
49 {
50 lws_usec_t now = lws_now_usecs();
51 lws_dll2_remove(&sul->list);
52
53 if (us == LWS_SET_TIMER_USEC_CANCEL) {
54 /* we are clearing the timeout */
55 sul->us = 0;
56
57 return 0;
58 }
59
60 sul->us = now + us;
61 assert(sul->cb);
62
63 /*
64 * we sort the pt's list of sequencers with pending timeouts, so it's
65 * cheap to check it every second
66 */
67
68 lws_dll2_add_sorted(&sul->list, own, sul_compare);
69
70 #if 0 // defined(_DEBUG)
71 {
72 lws_usec_t worst = 0;
73 int n = 1;
74
75 lwsl_info("%s: own %p: count %d\n", __func__, own, own->count);
76
77 lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
78 lws_dll2_get_head(own)) {
79 lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)p;
80 lwsl_info("%s: %d: %llu (+%lld)\n", __func__, n++,
81 (unsigned long long)sul->us,
82 (long long)(sul->us - now));
83 if (sul->us < worst) {
84 lwsl_err("%s: wrongly sorted sul entry!\n",
85 __func__);
86 assert(0);
87 }
88 worst = sul->us;
89 } lws_end_foreach_dll_safe(p, tp);
90 }
91 #endif
92
93 return 0;
94 }
95
96 void
lws_sul_schedule(struct lws_context * context,int tsi,lws_sorted_usec_list_t * sul,sul_cb_t cb,lws_usec_t us)97 lws_sul_schedule(struct lws_context *context, int tsi,
98 lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us)
99 {
100 struct lws_context_per_thread *pt = &context->pt[tsi];
101
102 sul->cb = cb;
103
104 __lws_sul_insert(&pt->pt_sul_owner, sul, us);
105 }
106
107 lws_usec_t
__lws_sul_service_ripe(lws_dll2_owner_t * own,lws_usec_t usnow)108 __lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow)
109 {
110 struct lws_context_per_thread *pt = (struct lws_context_per_thread *)
111 lws_container_of(own, struct lws_context_per_thread,
112 pt_sul_owner);
113
114 if (pt->attach_owner.count)
115 lws_system_do_attach(pt);
116
117 while (lws_dll2_get_head(own)) {
118
119 /* .list is always first member in lws_sorted_usec_list_t */
120 lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)
121 lws_dll2_get_head(own);
122
123 assert(sul->us); /* shouldn't be on the list otherwise */
124
125 if (sul->us > usnow)
126 return sul->us - usnow;
127
128 /* his moment has come... remove him from timeout list */
129 lws_dll2_remove(&sul->list);
130 sul->us = 0;
131 pt->inside_lws_service = 1;
132 sul->cb(sul);
133 pt->inside_lws_service = 0;
134
135 /*
136 * The callback may have done any mixture of delete
137 * and add sul entries... eg, close a wsi may pull out
138 * multiple entries making iterating it statefully
139 * unsafe. Always restart at the current head of list.
140 */
141 }
142
143 /*
144 * Nothing left to take care of in the list (cannot return 0 otherwise
145 * because we will service anything equal to usnow rather than return)
146 */
147
148 return 0;
149 }
150