source: trunk/src/ct/mainloop.c @ 1114

Revision 1114, 2.5 KB checked in by alonbl, 3 years ago (diff)

Support event mode for drivers

Current implementation forces poll loop every one second or so,
this consume CPU and power.

This changeset adds the ability for a driver to provide file
descriptor for event handling, removing the need to poll.

Only Linux USB interface was modified to use this new interface.

All other environments will fall-back into the poll mode.

New driver methods:

before_command

Executed before command, makes it easy to remove event capture.

after_command

Execute after command, makes it easy to add event capture.

get_eventfd

Get an event fd out of the driver, if unsupported -1 should
be returned, this fall-back into the poll mode.

event

Event method to call with th evntfd is signaled.

before_command

Execute whatever needed before executing a command. Useful
if driver need to turn off event capture.

after_command

Execute whatever needed before blocking. Useful if driver
need to turn on event capture.

New device methods:

get_eventfd

Gets eventfd if available.

New USB methods:

ifd_usb_get_eventfd

Get event fd to poll for events.

ifd_usb_capture_event

None blocking capture.

New CT socket methods:

error

Called with POLLERR is received.

New configuration file options:

force_poll

Force polling, default is true (as correct behavior),
until Linux kernel will resolve its issues.

New command-line options:

ifdhandler -p

Force polling.

Linux specific notes:

This enable safe detection of device removal and allow USB drivers
to stop polling device, even if they do not have interrupt interface.

As OpenCT uses /dev/bus/usb namespace if exists, and this feature worked
only on usbfs prior to linux-2.6.28, it will not work with older kernels.

linux-2.6.28 has a bug that cause the signal not to be sent if kernel
is configured without CONFIG_USB_DEVICEFS, see [1].

linux-2.6.29 is expected to solve this issue.

Even if ccid driver works correctly, as it uses interrupt endpoint,
by default polling will be forced.

[1]  http://marc.info/?t=123075926900001&r=1&w=2

M src/ifd/ifdhandler.c
M src/ifd/utils.c
M src/ifd/process.c
M src/ifd/sys-osx.c
M src/ifd/sys-null.c
M src/ifd/device.c
M src/ifd/internal.h
M src/ifd/usb.c
M src/ifd/reader.c
M src/ifd/sys-linux.c
M src/ifd/sys-bsd.c
M src/ifd/sys-solaris.c
M src/ifd/sys-sunray.c
M src/include/openct/driver.h
M src/include/openct/device.h
M src/include/openct/ifd.h
M src/include/openct/socket.h
M src/ct/mainloop.c
M etc/openct.conf.in

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Resource manager daemon - main loop
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 */
6
7#ifdef HAVE_CONFIG_H
8#include <config.h>
9#endif
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <sys/poll.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <errno.h>
18
19#include <openct/socket.h>
20#include <openct/server.h>
21#include <openct/logging.h>
22
23#define IFD_MAX_SOCKETS 256
24
25static ct_socket_t sock_head;
26static int leave_mainloop;
27
28void ct_mainloop_add_socket(ct_socket_t * sock)
29{
30        if (sock)
31                ct_socket_link(&sock_head, sock);
32}
33
34/*
35 * Main loop
36 */
37void ct_mainloop(void)
38{
39        leave_mainloop = 0;
40        while (!leave_mainloop) {
41                struct pollfd pfd[IFD_MAX_SOCKETS + 1];
42                ct_socket_t *poll_socket[IFD_MAX_SOCKETS];
43                ct_socket_t *sock, *next;
44                unsigned int nsockets = 0, npoll = 0;
45                unsigned int n = 0, listening;
46                int have_driver_with_poll = 0;
47                int rc;
48
49                /* Zap poll structure */
50                memset(pfd, 0, sizeof(pfd));
51
52                /* Count active sockets, and decide whether to
53                 * accept additional connections or not. */
54                for (sock = sock_head.next; sock; sock = next) {
55                        next = sock->next;
56                        /* Kill any dead or excess sockets */
57                        if (sock->fd < 0 || nsockets == IFD_MAX_SOCKETS) {
58                                ct_socket_free(sock);
59                        } else {
60                                nsockets++;
61                        }
62                }
63                listening = (nsockets < IFD_MAX_SOCKETS) ? POLLIN : 0;
64
65                /* Now loop over all sockets and set up the poll structs */
66                for (sock = sock_head.next; sock; sock = sock->next) {
67                        poll_socket[npoll] = sock;
68                        if (sock->poll) {
69                                have_driver_with_poll = 1;
70                                if (sock->poll(sock, &pfd[npoll]) == 1)
71                                        npoll++;
72                        } else {
73                                if (sock->listener)
74                                        sock->events = listening;
75
76                                pfd[npoll].fd = sock->fd;
77                                pfd[npoll].events = sock->events;
78                                npoll++;
79                        }
80                }
81
82                if (npoll == 0)
83                        break;
84
85                rc = poll(pfd, npoll, have_driver_with_poll ? 1000 : -1);
86                if (rc < 0) {
87                        if (errno == EINTR)
88                                continue;
89                        ct_error("poll: %m");
90                        break;
91                }
92
93                for (n = 0; n < npoll; n++) {
94                        sock = poll_socket[n];
95                        if (sock->poll) {
96                                if (sock->poll(sock, &pfd[n]) < 0) {
97                                        ct_socket_free(sock);
98                                        continue;
99                                }
100                                continue;
101                        }
102
103                        if (pfd[n].revents & POLLERR) {
104                                if (sock->error(sock) < 0) {
105                                        ct_socket_free(sock);
106                                        continue;
107                                }
108                        }
109                        if (pfd[n].revents & POLLOUT) {
110                                if (sock->send(sock) < 0) {
111                                        ct_socket_free(sock);
112                                        continue;
113                                }
114                        }
115                        if (pfd[n].revents & POLLIN) {
116                                if ((rc = sock->recv(sock)) < 0) {
117                                        ct_socket_free(sock);
118                                        continue;
119                                }
120                        }
121                }
122        }
123}
124
125void ct_mainloop_leave(void)
126{
127        leave_mainloop = 1;
128}
Note: See TracBrowser for help on using the repository browser.