1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
4 | * Copyright (©) 2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * |
5 | * |
6 | * Deliantra is free software: you can redistribute it and/or modify |
6 | * Deliantra is free software: you can redistribute it and/or modify it under |
7 | * it under the terms of the GNU General Public License as published by |
7 | * the terms of the Affero GNU General Public License as published by the |
8 | * the Free Software Foundation, either version 3 of the License, or |
8 | * Free Software Foundation, either version 3 of the License, or (at your |
9 | * (at your option) any later version. |
9 | * option) any later version. |
10 | * |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
14 | * GNU General Public License for more details. |
15 | * |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
16 | * You should have received a copy of the Affero GNU General Public License |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | * and the GNU General Public License along with this program. If not, see |
|
|
18 | * <http://www.gnu.org/licenses/>. |
18 | * |
19 | * |
19 | * The authors can be reached via e-mail to <support@deliantra.net> |
20 | * The authors can be reached via e-mail to <support@deliantra.net> |
20 | */ |
21 | */ |
21 | |
22 | |
22 | #include "global.h" |
23 | #include "global.h" |
23 | #include "evthread.h" |
24 | #include "evthread.h" |
24 | #include "cfperl.h" |
25 | #include "cfperl.h" |
25 | |
26 | |
26 | thread evthread; |
27 | thread evthread; |
27 | static ev_loop *loop; |
28 | static ev_loop *loop; |
28 | |
29 | |
29 | #define TICK_CYCLES 4 |
30 | ///////////////////////////////////////////////////////////////////////////// |
30 | |
31 | |
31 | // the tick watcher is activated every TICK_CYCLES |
|
|
32 | ev_async tick_watcher; |
32 | ev_async tick_watcher; |
33 | EV_ATOMIC_T coroapi::cede_pending; |
33 | EV_ATOMIC_T coroapi::cede_pending; |
34 | |
34 | |
35 | // the ticker runs TICK_CYCLES times as fast as the main server tick |
|
|
36 | static ev_periodic cede_watcher; |
35 | static ev_periodic cede_watcher; |
37 | |
|
|
38 | ///////////////////////////////////////////////////////////////////////////// |
|
|
39 | |
36 | |
40 | // it is a bit silly to have to use a mutex, but contention |
37 | // it is a bit silly to have to use a mutex, but contention |
41 | // is basically non-existant, favouring good mutex implementations. |
38 | // is basically non-existant, favouring good mutex implementations. |
42 | static SMUTEX (evthread_mutex); |
39 | static SMUTEX (evthread_mutex); |
43 | static NV next_tick; |
40 | static NV next_tick; |
… | |
… | |
51 | } |
48 | } |
52 | |
49 | |
53 | static void |
50 | static void |
54 | cede_cb (EV_P_ ev_periodic *w, int revents) |
51 | cede_cb (EV_P_ ev_periodic *w, int revents) |
55 | { |
52 | { |
56 | static int cycle = 0; |
|
|
57 | |
|
|
58 | if (++cycle == TICK_CYCLES) |
|
|
59 | { |
|
|
60 | cycle = 0; |
|
|
61 | |
|
|
62 | SMUTEX_LOCK (evthread_mutex); |
53 | SMUTEX_LOCK (evthread_mutex); |
63 | next_tick = w->at + TICK / TICK_CYCLES * (TICK_CYCLES - 1); |
54 | next_tick = w->at; |
64 | SMUTEX_UNLOCK (evthread_mutex); |
55 | SMUTEX_UNLOCK (evthread_mutex); |
65 | |
|
|
66 | ev_async_send (EV_DEFAULT_UC, &tick_watcher); |
|
|
67 | } |
|
|
68 | |
56 | |
69 | coroapi::cede_pending = 1; |
57 | coroapi::cede_pending = 1; |
|
|
58 | |
|
|
59 | ev_async_send (EV_DEFAULT_UC, &tick_watcher); |
70 | } |
60 | } |
71 | |
61 | |
72 | static void |
62 | static void |
73 | tick_cb (EV_P_ ev_async *w, int revents) |
63 | tick_cb (EV_P_ ev_async *w, int revents) |
74 | { |
64 | { |
75 | cfperl_tick (); |
65 | cfperl_tick (); |
76 | } |
66 | } |
77 | |
67 | |
78 | ///////////////////////////////////////////////////////////////////////////// |
68 | ///////////////////////////////////////////////////////////////////////////// |
79 | |
69 | |
|
|
70 | static SMUTEX(cb_mutex); |
|
|
71 | static SCOND(cb_done); |
|
|
72 | |
80 | static ev_async async_watcher; |
73 | static ev_async async_watcher; |
81 | static ev_io aio1_watcher; |
74 | static ev_io aio_watcher; |
82 | static ev_idle aio2_watcher; |
|
|
83 | static EV_ATOMIC_T aio_pending; |
|
|
84 | |
|
|
85 | static void |
|
|
86 | aio2_cb (EV_P_ ev_idle *w, int revents) |
|
|
87 | { |
|
|
88 | IV reqs; |
|
|
89 | |
|
|
90 | CALL_BEGIN (0); |
|
|
91 | CALL_CALL ("IO::AIO::poll_cb", G_SCALAR); |
|
|
92 | |
|
|
93 | reqs = POPi; |
|
|
94 | if (count > 0 && reqs < 0) |
|
|
95 | ev_idle_start (EV_A, w); |
|
|
96 | else |
|
|
97 | ev_idle_stop (EV_A, w); |
|
|
98 | |
|
|
99 | CALL_END; |
|
|
100 | } |
|
|
101 | |
75 | |
102 | static void |
76 | static void |
103 | async_cb (EV_P_ ev_async *w, int revents) |
77 | async_cb (EV_P_ ev_async *w, int revents) |
104 | { |
78 | { |
105 | aio2_cb (EV_A, &aio2_watcher, 0); |
79 | CALL_BEGIN (0); |
|
|
80 | CALL_CALL ("IO::AIO::poll_cb", G_SCALAR); |
|
|
81 | IV reqs = POPi; |
|
|
82 | CALL_END; |
|
|
83 | |
|
|
84 | SMUTEX_LOCK (cb_mutex); |
|
|
85 | SCOND_SIGNAL (cb_done); |
|
|
86 | SMUTEX_UNLOCK (cb_mutex); |
106 | } |
87 | } |
107 | |
88 | |
108 | static void |
89 | static void |
109 | aio1_cb (EV_P_ ev_io *w, int revents) |
90 | aio_cb (EV_P_ ev_io *w, int revents) |
110 | { |
91 | { |
111 | char dummy; |
92 | ev_async_send (EV_DEFAULT_UC, &async_watcher); |
112 | |
93 | |
113 | if (read (w->fd, &dummy, 1) > 0) |
94 | coroapi::cede_pending = 1; // to decrease latency |
114 | { |
95 | |
115 | ev_async_send (EV_DEFAULT_UC, &async_watcher); |
96 | SCOND_WAIT (cb_done, cb_mutex); |
116 | coroapi::cede_pending = 1; |
|
|
117 | } |
|
|
118 | } |
97 | } |
119 | |
98 | |
120 | ///////////////////////////////////////////////////////////////////////////// |
99 | ///////////////////////////////////////////////////////////////////////////// |
121 | |
100 | |
122 | static void * |
101 | static void * |
123 | evthread_proc (void *arg) |
102 | evthread_proc (void *arg) |
124 | { |
103 | { |
|
|
104 | SMUTEX_LOCK (cb_mutex); |
|
|
105 | |
125 | ev_loop (loop, 0); |
106 | ev_run (loop, 0); |
126 | |
107 | |
127 | return 0; |
108 | return 0; |
128 | } |
109 | } |
129 | |
110 | |
130 | void evthread_start (int aiofd) |
111 | void evthread_start (int aiofd) |
… | |
… | |
138 | |
119 | |
139 | ev_async_init (&async_watcher, async_cb); |
120 | ev_async_init (&async_watcher, async_cb); |
140 | ev_set_priority (&async_watcher, 1); |
121 | ev_set_priority (&async_watcher, 1); |
141 | ev_async_start (EV_DEFAULT_UC, &async_watcher); |
122 | ev_async_start (EV_DEFAULT_UC, &async_watcher); |
142 | |
123 | |
143 | ev_idle_init (&aio2_watcher, aio2_cb); |
124 | // secondary loop, we use select/poll as epoll has very |
|
|
125 | // bad timing characteristics and we only watch a single low fd. |
|
|
126 | loop = ev_loop_new (EVBACKEND_SELECT); |
144 | |
127 | |
145 | // secondary loop |
|
|
146 | loop = ev_loop_new (0); |
|
|
147 | |
|
|
148 | ev_periodic_init (&cede_watcher, cede_cb, 0, TICK / TICK_CYCLES, 0); |
128 | ev_periodic_init (&cede_watcher, cede_cb, 0, TICK, 0); |
149 | ev_periodic_start (loop, &cede_watcher); |
129 | ev_periodic_start (loop, &cede_watcher); |
150 | |
130 | |
151 | ev_io_init (&aio1_watcher, aio1_cb, aiofd, EV_READ); |
131 | ev_io_init (&aio_watcher, aio_cb, aiofd, EV_READ); |
152 | ev_io_start (loop, &aio1_watcher); |
132 | ev_io_start (loop, &aio_watcher); |
153 | |
133 | |
154 | evthread.start (evthread_proc); |
134 | evthread.start (evthread_proc); |
155 | } |
135 | } |
156 | |
136 | |
157 | |
137 | |