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