Welcome to mirror list, hosted at ThFree Co, Russian Federation.

threadpool-ms-io-epoll.c « metadata « mono - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: bf619214c8557f19a08553296a81a69719ee3d1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

#if defined(HAVE_EPOLL)

#include <sys/epoll.h>

#if defined(HOST_WIN32)
/* We assume that epoll is not available on windows */
#error
#endif

#define EPOLL_NEVENTS 128

static gint epoll_fd;
static struct epoll_event *epoll_events;

static gboolean
epoll_init (gint wakeup_pipe_fd)
{
	struct epoll_event event;

#ifdef EPOOL_CLOEXEC
	epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
#else
	epoll_fd = epoll_create (256);
	fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
#endif

	if (epoll_fd == -1) {
#ifdef EPOOL_CLOEXEC
		g_error ("epoll_init: epoll (EPOLL_CLOEXEC) failed, error (%d) %s\n", errno, g_strerror (errno));
#else
		g_error ("epoll_init: epoll (256) failed, error (%d) %s\n", errno, g_strerror (errno));
#endif
		return FALSE;
	}

	event.events = EPOLLIN;
	event.data.fd = wakeup_pipe_fd;
	if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, event.data.fd, &event) == -1) {
		g_error ("epoll_init: epoll_ctl () failed, error (%d) %s", errno, g_strerror (errno));
		close (epoll_fd);
		return FALSE;
	}

	epoll_events = g_new0 (struct epoll_event, EPOLL_NEVENTS);

	return TRUE;
}

static void
epoll_cleanup (void)
{
	g_free (epoll_events);
	close (epoll_fd);
}

static void
epoll_register_fd (gint fd, gint events, gboolean is_new)
{
	struct epoll_event event;

#ifndef EPOLLONESHOT
/* it was only defined on android in May 2013 */
#define EPOLLONESHOT 0x40000000
#endif

	event.data.fd = fd;
	event.events = EPOLLONESHOT;
	if ((events & EVENT_IN) != 0)
		event.events |= EPOLLIN;
	if ((events & EVENT_OUT) != 0)
		event.events |= EPOLLOUT;

	if (epoll_ctl (epoll_fd, is_new ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, event.data.fd, &event) == -1)
		g_error ("epoll_register_fd: epoll_ctl(%s) failed, error (%d) %s", is_new ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD", errno, g_strerror (errno));
}

static void
epoll_remove_fd (gint fd)
{
	if (epoll_ctl (epoll_fd, EPOLL_CTL_DEL, fd, NULL) == -1)
			g_error ("epoll_remove_fd: epoll_ctl (EPOLL_CTL_DEL) failed, error (%d) %s", errno, g_strerror (errno));
}

static gint
epoll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gpointer user_data)
{
	gint i, ready;

	memset (epoll_events, 0, sizeof (struct epoll_event) * EPOLL_NEVENTS);

	mono_gc_set_skip_thread (TRUE);

	ready = epoll_wait (epoll_fd, epoll_events, EPOLL_NEVENTS, -1);

	mono_gc_set_skip_thread (FALSE);

	if (ready == -1) {
		switch (errno) {
		case EINTR:
			mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
			ready = 0;
			break;
		default:
			g_error ("epoll_event_wait: epoll_wait () failed, error (%d) %s", errno, g_strerror (errno));
			break;
		}
	}

	if (ready == -1)
		return -1;

	for (i = 0; i < ready; ++i) {
		gint fd, events = 0;

		fd = epoll_events [i].data.fd;
		if (epoll_events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
			events |= EVENT_IN;
		if (epoll_events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
			events |= EVENT_OUT;

		callback (fd, events, user_data);
	}

	return 0;
}

static ThreadPoolIOBackend backend_epoll = {
	.init = epoll_init,
	.cleanup = epoll_cleanup,
	.register_fd = epoll_register_fd,
	.remove_fd = epoll_remove_fd,
	.event_wait = epoll_event_wait,
};

#endif