2005-05-14 Gabor Kelemen <kelemeng@gnome.hu>
[beagle.git] / glue / inotify-glue.c
blobe40dc7565770c3ff0b9a8a2a4c0bfb9082a502ac
1 /*
2 * inotify-glue.c
4 * Copyright (C) 2004 Novell, Inc.
6 */
8 /*
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/select.h>
37 #include "inotify.h"
39 #define SYSFS_PREFIX "/sys/class/misc/inotify"
41 #define SYSFS_MAX_USER_DEVICES SYSFS_PREFIX "/max_user_devices"
42 #define SYSFS_MAX_USER_WATCHES SYSFS_PREFIX "/max_user_watches"
43 #define SYSFS_MAX_QUEUED_EVENTS SYSFS_PREFIX "/max_queued_events"
45 /* Inotify sysfs knobs, initialized to their pre-sysfs defaults */
46 static int max_user_devices = 8;
47 static int max_user_watches = 8192;
48 static unsigned int max_queued_events = 256;
50 /* Paranoid code to read an integer from a sysfs (well, any) file. */
51 static void
52 read_int (const char *filename, int *var)
54 int fd, n;
55 char buffer[32];
56 char *buffer_endptr = NULL;
58 fd = open (filename, O_RDONLY);
59 if (fd == -1)
60 return;
61 if (read (fd, buffer, 31) > 0) {
62 n = (int) strtol (buffer, &buffer_endptr, 10);
63 if (*buffer != '\0' && *buffer_endptr == '\0')
64 *var = n;
66 close (fd);
70 void
71 inotify_glue_init (void)
73 static int initialized = 0;
74 if (initialized)
75 return;
76 initialized = 1;
78 read_int (SYSFS_MAX_USER_DEVICES, &max_user_devices);
79 read_int (SYSFS_MAX_USER_WATCHES, &max_user_watches);
80 read_int (SYSFS_MAX_QUEUED_EVENTS, &max_queued_events);
84 int
85 inotify_glue_watch (int fd, const char *filename, __u32 mask)
87 struct inotify_watch_request iwr;
88 int file_fd, wd;
90 file_fd = open (filename, O_RDONLY);
91 if (file_fd < 0) {
92 perror ("open");
93 return -1;
96 iwr.fd = file_fd;
97 iwr.mask = mask;
99 wd = ioctl (fd, INOTIFY_WATCH, &iwr);
100 if (wd < 0)
101 perror ("ioctl");
103 if (close (file_fd))
104 perror ("close");
106 return wd;
111 inotify_glue_ignore (int fd, __s32 wd)
113 int ret;
115 ret = ioctl (fd, INOTIFY_IGNORE, &wd);
116 if (ret < 0)
117 perror ("ioctl");
119 return ret;
123 #define MAX_PENDING_COUNT 5
124 #define PENDING_PAUSE_MICROSECONDS 2000
125 #define PENDING_THRESHOLD(qsize) ((qsize) >> 1)
126 #define PENDING_MARGINAL_COST(p) ((unsigned int)(1 << (p)))
128 void
129 inotify_snarf_events (int fd, int timeout_secs, int *nr, void **buffer_out)
131 struct timeval timeout;
132 fd_set read_fds;
133 int select_retval;
134 unsigned int prev_pending = 0, pending_count = 0;
135 static struct inotify_event *buffer = NULL;
136 static size_t buffer_size;
138 /* Allocate our buffer the first time we try to read events. */
139 if (buffer == NULL) {
140 /* guess the avg len */
141 buffer_size = sizeof (struct inotify_event) + 16;
142 buffer_size *= max_queued_events;
143 buffer = malloc (buffer_size);
144 if (!buffer) {
145 perror ("malloc");
146 *buffer_out = NULL;
147 return;
151 /* Set nr to 0, so it will be sure to contain something
152 valid if the select times out. */
153 *nr = 0;
155 /* Wait for the file descriptor to be ready to read. */
157 timeout.tv_sec = timeout_secs;
158 timeout.tv_usec = 0;
160 FD_ZERO (&read_fds);
161 FD_SET (fd, &read_fds);
163 select_retval = select (fd + 1, &read_fds, NULL, NULL, &timeout);
165 /* If we time out or get an error, just return */
166 if (select_retval <= 0)
167 return;
169 /* Reading events in groups significantly helps performance.
170 * If there are some events (but not too many!) ready, wait a
171 * bit more to see if more events come in. */
173 while (pending_count < MAX_PENDING_COUNT) {
174 unsigned int pending;
176 if (ioctl (fd, FIONREAD, &pending) == -1)
177 break;
178 pending /= sizeof (struct inotify_event) + 16; /* guess len */
180 /* Don't wait if the number of pending events is too close
181 * to the maximum queue size. */
182 if (pending > PENDING_THRESHOLD (max_queued_events))
183 break;
185 /* With each successive iteration, the minimum rate for
186 * further sleep doubles. */
187 if (pending-prev_pending < PENDING_MARGINAL_COST(pending_count))
188 break;
190 prev_pending = pending;
191 ++pending_count;
193 timeout.tv_sec = 0;
194 timeout.tv_usec = PENDING_PAUSE_MICROSECONDS;
195 select (0, NULL, NULL, NULL, &timeout);
198 *nr = read (fd, buffer, buffer_size);
200 *buffer_out = buffer;