sysdeps_qemu.c revision c2db2b6accc7888df514261a7240e7759df95a4c
1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "sockets.h"
13#include "sysdeps.h"
14#include "vl.h"
15
16#define  DEBUG  1
17
18#define  D_ACTIVE  DEBUG
19
20#if DEBUG
21#define  D(...)  do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
22#else
23#define  D(...)  ((void)0)
24#endif
25
26/** TIME
27 **/
28
29SysTime
30sys_time_ms( void )
31{
32    return qemu_get_clock( rt_clock );
33}
34
35/** TIMERS
36 **/
37
38typedef struct SysTimerRec_ {
39    QEMUTimer*    timer;
40    QEMUTimerCB*  callback;
41    void*         opaque;
42    SysTimer      next;
43} SysTimerRec;
44
45#define  MAX_TIMERS  32
46
47static SysTimerRec  _s_timers0[ MAX_TIMERS ];
48static SysTimer     _s_free_timers;
49
50static void
51sys_init_timers( void )
52{
53    int  nn;
54    for (nn = 0; nn < MAX_TIMERS-1; nn++)
55        _s_timers0[nn].next = _s_timers0 + (nn+1);
56
57    _s_free_timers = _s_timers0;
58}
59
60static SysTimer
61sys_timer_alloc( void )
62{
63    SysTimer  timer = _s_free_timers;
64
65    if (timer != NULL) {
66        _s_free_timers = timer->next;
67        timer->next    = NULL;
68        timer->timer   = NULL;
69    }
70    return timer;
71}
72
73
74static void
75sys_timer_free( SysTimer  timer )
76{
77    if (timer->timer) {
78        qemu_del_timer( timer->timer );
79        qemu_free_timer( timer->timer );
80        timer->timer = NULL;
81    }
82    timer->next    = _s_free_timers;
83    _s_free_timers = timer;
84}
85
86
87SysTimer   sys_timer_create( void )
88{
89    SysTimer  timer = sys_timer_alloc();
90    return timer;
91}
92
93void
94sys_timer_set( SysTimer  timer, SysTime  when, SysCallback   _callback, void*  opaque )
95{
96    QEMUTimerCB*  callback = (QEMUTimerCB*)_callback;
97
98    if (callback == NULL) {  /* unsetting the timer */
99        if (timer->timer) {
100            qemu_del_timer( timer->timer );
101            qemu_free_timer( timer->timer );
102            timer->timer = NULL;
103        }
104        timer->callback = callback;
105        timer->opaque   = NULL;
106        return;
107    }
108
109    if ( timer->timer ) {
110         if ( timer->callback == callback && timer->opaque == opaque )
111            goto ReuseTimer;
112
113         /* need to replace the timer */
114         qemu_free_timer( timer->timer );
115    }
116
117    timer->timer    = qemu_new_timer( rt_clock, callback, opaque );
118    timer->callback = callback;
119    timer->opaque   = opaque;
120
121ReuseTimer:
122    qemu_mod_timer( timer->timer, when );
123}
124
125void
126sys_timer_unset( SysTimer  timer )
127{
128    if (timer->timer) {
129        qemu_del_timer( timer->timer );
130    }
131}
132
133void
134sys_timer_destroy( SysTimer  timer )
135{
136    sys_timer_free( timer );
137}
138
139
140/** CHANNELS
141 **/
142
143typedef struct SysChannelRec_ {
144    int                 fd;
145    SysChannelCallback  callback;
146    void*               opaque;
147    SysChannel          next;
148} SysChannelRec;
149
150#define  MAX_CHANNELS  16
151
152static SysChannelRec  _s_channels0[ MAX_CHANNELS ];
153static SysChannel     _s_free_channels;
154
155static void
156sys_init_channels( void )
157{
158    int  nn;
159
160    for ( nn = 0; nn < MAX_CHANNELS-1; nn++ ) {
161        _s_channels0[nn].next = _s_channels0 + (nn+1);
162    }
163    _s_free_channels = _s_channels0;
164}
165
166static SysChannel
167sys_channel_alloc( )
168{
169    SysChannel  channel = _s_free_channels;
170    if (channel != NULL) {
171        _s_free_channels  = channel->next;
172        channel->next     = NULL;
173        channel->fd       = -1;
174        channel->callback = NULL;
175        channel->opaque   = NULL;
176    }
177    return channel;
178}
179
180static void
181sys_channel_free( SysChannel  channel )
182{
183    if (channel->fd >= 0) {
184        socket_close( channel->fd );
185        channel->fd = -1;
186    }
187    channel->next    = _s_free_channels;
188    _s_free_channels = channel;
189}
190
191
192static void
193sys_channel_read_handler( void*  _channel )
194{
195    SysChannel  channel = _channel;
196    D( "%s: read event for channel %p:%d\n", __FUNCTION__,
197       channel, channel->fd );
198    channel->callback( channel->opaque, SYS_EVENT_READ );
199}
200
201static void
202sys_channel_write_handler( void*  _channel )
203{
204    SysChannel  channel = _channel;
205    D( "%s: write event for channel %p:%d\n", __FUNCTION__, channel, channel->fd );
206    channel->callback( channel->opaque, SYS_EVENT_WRITE );
207}
208
209void
210sys_channel_on( SysChannel          channel,
211                int                 events,
212                SysChannelCallback  event_callback,
213                void*               event_opaque )
214{
215    IOHandler*  read_handler  = NULL;
216    IOHandler*  write_handler = NULL;
217
218    if (events & SYS_EVENT_READ) {
219        read_handler = sys_channel_read_handler;
220    }
221    if (events & SYS_EVENT_WRITE) {
222        write_handler = sys_channel_write_handler;
223    }
224    channel->callback = event_callback;
225    channel->opaque   = event_opaque;
226    qemu_set_fd_handler( channel->fd, read_handler, write_handler, channel );
227}
228
229int
230sys_channel_read( SysChannel  channel, void*  buffer, int  size )
231{
232    int   len = size;
233    char* buf = (char*) buffer;
234
235    while (len > 0) {
236        int  ret = socket_recv(channel->fd, buf, len);
237        if (ret < 0) {
238            if (errno == EINTR)
239                continue;
240            if (errno == EWOULDBLOCK)
241                break;
242            D( "%s: after reading %d bytes, recv() returned error %d: %s\n",
243                __FUNCTION__, size - len, errno, errno_str);
244            return -1;
245        } else if (ret == 0) {
246            break;
247        } else {
248            buf += ret;
249            len -= ret;
250        }
251    }
252    return size - len;
253}
254
255
256int
257sys_channel_write( SysChannel  channel, const void*  buffer, int  size )
258{
259    int         len = size;
260    const char* buf = (const char*) buffer;
261
262    while (len > 0) {
263        int  ret = socket_send(channel->fd, buf, len);
264        if (ret < 0) {
265            if (errno == EINTR)
266                continue;
267            if (errno == EWOULDBLOCK)
268                break;
269            D( "%s: send() returned error %d: %s\n",
270                __FUNCTION__, errno, errno_str);
271            return -1;
272        } else if (ret == 0) {
273            break;
274        } else {
275            buf += ret;
276            len -= ret;
277        }
278    }
279    return size - len;
280}
281
282void  sys_channel_close( SysChannel  channel )
283{
284    qemu_set_fd_handler( channel->fd, NULL, NULL, NULL );
285    sys_channel_free( channel );
286}
287
288void  sys_main_init( void )
289{
290    sys_init_channels();
291    sys_init_timers();
292}
293
294
295int   sys_main_loop( void )
296{
297    /* no looping, qemu has its own event loop */
298    return 0;
299}
300
301
302
303
304SysChannel
305sys_channel_create_tcp_server( int port )
306{
307    SysChannel  channel = sys_channel_alloc();
308
309    channel->fd = socket_anyaddr_server( port, SOCKET_STREAM );
310    if (channel->fd < 0) {
311        D( "%s: failed to created network socket on TCP:%d\n",
312            __FUNCTION__, port );
313        sys_channel_free( channel );
314        return NULL;
315    }
316
317    D( "%s: server channel %p:%d now listening on port %d\n",
318       __FUNCTION__, channel, channel->fd, port );
319
320    return channel;
321}
322
323
324SysChannel
325sys_channel_create_tcp_handler( SysChannel  server_channel )
326{
327    SysChannel  channel = sys_channel_alloc();
328
329    D( "%s: creating handler from server channel %p:%d\n", __FUNCTION__,
330       server_channel, server_channel->fd );
331
332    channel->fd = socket_accept_any( server_channel->fd );
333    if (channel->fd < 0) {
334        perror( "accept" );
335        sys_channel_free( channel );
336        return NULL;
337    }
338
339    /* disable Nagle algorithm */
340    socket_set_lowlatency( channel->fd );
341
342    D( "%s: handler %p:%d created from server %p:%d\n", __FUNCTION__,
343        server_channel, server_channel->fd, channel, channel->fd );
344
345     return channel;
346}
347
348
349SysChannel
350sys_channel_create_tcp_client( const char*  hostname, int  port )
351{
352    SysChannel  channel = sys_channel_alloc();
353
354    channel->fd = socket_network_client( hostname, port, SOCKET_STREAM );
355    if (channel->fd < 0) {
356        sys_channel_free(channel);
357        return NULL;
358    };
359
360    /* set to non-blocking and disable Nagle algorithm */
361    socket_set_nonblock( channel->fd );
362    socket_set_lowlatency( channel->fd );
363
364    return channel;
365}
366
367