]> git.ipfire.org Git - thirdparty/squid.git/blob - src/unlinkd.cc
Bug 1579, 1475 - fix unlinkd to reduce the number of fd_set references
[thirdparty/squid.git] / src / unlinkd.cc
1
2 /*
3 * $Id: unlinkd.cc,v 1.57 2006/09/10 03:20:37 adrian Exp $
4 *
5 * DEBUG: section 2 Unlink Daemon
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 #ifdef UNLINK_DAEMON
39
40 /* This is the external unlinkd process */
41
42 #define UNLINK_BUF_LEN 1024
43
44 int
45 main(int argc, char *argv[])
46 {
47 char buf[UNLINK_BUF_LEN];
48 char *t;
49 int x;
50 setbuf(stdin, NULL);
51 setbuf(stdout, NULL);
52 close(2);
53 open(_PATH_DEVNULL, O_RDWR);
54
55 while (fgets(buf, UNLINK_BUF_LEN, stdin)) {
56 if ((t = strchr(buf, '\n')))
57 *t = '\0';
58
59 #if USE_TRUNCATE
60
61 x = truncate(buf, 0);
62
63 #else
64
65 x = unlink(buf);
66
67 #endif
68
69 if (x < 0)
70 printf("ERR\n");
71 else
72 printf("OK\n");
73 }
74
75 exit(0);
76 }
77
78 #else /* UNLINK_DAEMON */
79
80 #include "SquidTime.h"
81 #include "fde.h"
82
83 /* This code gets linked to Squid */
84
85 static int unlinkd_wfd = -1;
86 static int unlinkd_rfd = -1;
87
88 static void * hIpc;
89 static pid_t pid;
90
91 #define UNLINKD_QUEUE_LIMIT 20
92
93 void
94 unlinkdUnlink(const char *path)
95 {
96 char buf[MAXPATHLEN];
97 int l;
98 int x;
99 static int queuelen = 0;
100
101 if (unlinkd_wfd < 0) {
102 debug_trap("unlinkdUnlink: unlinkd_wfd < 0");
103 safeunlink(path, 0);
104 return;
105 }
106
107 /*
108 * If the queue length is greater than our limit, then
109 * we pause for up to 100ms, hoping that unlinkd
110 * has some feedback for us. Maybe it just needs a slice
111 * of the CPU's time.
112 */
113 if (queuelen >= UNLINKD_QUEUE_LIMIT) {
114 usleep(100000);
115 }
116
117 /*
118 * If there is at least one outstanding unlink request, then
119 * try to read a response. If there's nothing to read we'll
120 * get an EWOULDBLOCK or whatever. If we get a response, then
121 * decrement the queue size by the number of newlines read.
122 */
123 if (queuelen > 0) {
124 int x;
125 int i;
126 char rbuf[512];
127 x = read(unlinkd_rfd, rbuf, 511);
128
129 if (x > 0) {
130 rbuf[x] = '\0';
131
132 for (i = 0; i < x; i++)
133 if ('\n' == rbuf[i])
134 queuelen--;
135
136 assert(queuelen >= 0);
137 }
138 }
139
140 l = strlen(path);
141 assert(l < MAXPATHLEN);
142 xstrncpy(buf, path, MAXPATHLEN);
143 buf[l++] = '\n';
144 x = write(unlinkd_wfd, buf, l);
145
146 if (x < 0) {
147 debug(2, 1) ("unlinkdUnlink: write FD %d failed: %s\n",
148 unlinkd_wfd, xstrerror());
149 safeunlink(path, 0);
150 return;
151 } else if (x != l) {
152 debug(2, 1) ("unlinkdUnlink: FD %d only wrote %d of %d bytes\n",
153 unlinkd_wfd, x, l);
154 safeunlink(path, 0);
155 return;
156 }
157
158 statCounter.unlink.requests++;
159 /*
160 * Increment this syscalls counter here, even though the syscall
161 * is executed by the helper process. We try to be consistent
162 * in counting unlink operations.
163 */
164 statCounter.syscalls.disk.unlinks++;
165 queuelen++;
166 }
167
168 void
169 unlinkdClose(void)
170 #ifdef _SQUID_MSWIN_
171 {
172
173 if (unlinkd_wfd > -1)
174 {
175 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
176 shutdown(unlinkd_wfd, SD_BOTH);
177 comm_close(unlinkd_wfd);
178
179 if (unlinkd_wfd != unlinkd_rfd)
180 comm_close(unlinkd_rfd);
181
182 unlinkd_wfd = -1;
183
184 unlinkd_rfd = -1;
185 } else
186 debugs(2, 0, "unlinkdClose: WARNING: unlinkd_wfd is " << unlinkd_wfd);
187
188 if (hIpc)
189 {
190 if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
191 getCurrentTime();
192 debugs(2, 1, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds");
193 }
194
195 CloseHandle(hIpc);
196 }
197 }
198 #else
199 {
200
201 if (unlinkd_wfd < 0)
202 return;
203
204 debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
205
206 file_close(unlinkd_wfd);
207
208 if (unlinkd_wfd != unlinkd_rfd)
209 file_close(unlinkd_rfd);
210
211 unlinkd_wfd = -1;
212
213 unlinkd_rfd = -1;
214 }
215
216 #endif
217
218 void
219 unlinkdInit(void)
220 {
221 const char *args[2];
222
223 struct timeval slp;
224 args[0] = "(unlinkd)";
225 args[1] = NULL;
226 pid = ipcCreate(
227 #if USE_POLL && defined(_SQUID_OSF_)
228 /* pipes and poll() don't get along on DUNIX -DW */
229 IPC_STREAM,
230 #elif defined(_SQUID_MSWIN_)
231 /* select() will fail on a pipe */
232 IPC_TCP_SOCKET,
233 #else
234 /* We currently need to use FIFO.. see below */
235 IPC_FIFO,
236 #endif
237 Config.Program.unlinkd,
238 args,
239 "unlinkd",
240 &unlinkd_rfd,
241 &unlinkd_wfd,
242 &hIpc);
243
244 if (pid < 0)
245 fatal("Failed to create unlinkd subprocess");
246
247 slp.tv_sec = 0;
248
249 slp.tv_usec = 250000;
250
251 select(0, NULL, NULL, NULL, &slp);
252
253 fd_note(unlinkd_wfd, "squid -> unlinkd");
254
255 fd_note(unlinkd_rfd, "unlinkd -> squid");
256
257 commSetTimeout(unlinkd_rfd, -1, NULL, NULL);
258
259 commSetTimeout(unlinkd_wfd, -1, NULL, NULL);
260
261 /*
262 * unlinkd_rfd should already be non-blocking because of
263 * ipcCreate. We change unlinkd_wfd to blocking mode because
264 * we never want to lose an unlink request, and we don't have
265 * code to retry if we get EWOULDBLOCK. Unfortunately, we can
266 * do this only for the IPC_FIFO case.
267 */
268 assert(fd_table[unlinkd_rfd].flags.nonblocking);
269
270 if (FD_PIPE == fd_table[unlinkd_wfd].type)
271 commUnsetNonBlocking(unlinkd_wfd);
272
273 debug(2, 1) ("Unlinkd pipe opened on FD %d\n", unlinkd_wfd);
274
275 #ifdef _SQUID_MSWIN_
276
277 debug(2, 4) ("Unlinkd handle: 0x%x, PID: %d\n", (unsigned)hIpc, pid);
278
279 #endif
280
281 }
282
283 #endif /* ndef UNLINK_DAEMON */