• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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