]>
Commit | Line | Data |
---|---|---|
f740a279 | 1 | |
429fdbec | 2 | /* |
262a0e14 | 3 | * $Id$ |
429fdbec | 4 | * |
b510f3a1 | 5 | * DEBUG: section 02 Unlink Daemon |
429fdbec | 6 | * AUTHOR: Duane Wessels |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
429fdbec | 10 | * |
2b6662ba | 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. | |
429fdbec | 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. | |
26ac0430 | 24 | * |
429fdbec | 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. | |
26ac0430 | 29 | * |
429fdbec | 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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
429fdbec | 34 | */ |
35 | ||
582c2af2 FC |
36 | #include "squid.h" |
37 | #include "fde.h" | |
38 | #include "globals.h" | |
39 | #include "xusleep.h" | |
40 | #include "protos.h" | |
5c3c8c03 | 41 | #include "SquidTime.h" |
e4f1fdae | 42 | #include "StatCounters.h" |
c521ad17 | 43 | #include "SwapDir.h" |
528b2c61 | 44 | |
429fdbec | 45 | /* This code gets linked to Squid */ |
46 | ||
06f8f350 | 47 | static int unlinkd_wfd = -1; |
48 | static int unlinkd_rfd = -1; | |
429fdbec | 49 | |
b5d712b5 | 50 | static void * hIpc; |
5c3c8c03 | 51 | static pid_t pid; |
52 | ||
9bc73deb | 53 | #define UNLINKD_QUEUE_LIMIT 20 |
54 | ||
429fdbec | 55 | void |
56 | unlinkdUnlink(const char *path) | |
57 | { | |
9bc73deb | 58 | char buf[MAXPATHLEN]; |
429fdbec | 59 | int l; |
e053c141 | 60 | int bytes_written; |
9bc73deb | 61 | static int queuelen = 0; |
62e76326 | 62 | |
06f8f350 | 63 | if (unlinkd_wfd < 0) { |
62e76326 | 64 | debug_trap("unlinkdUnlink: unlinkd_wfd < 0"); |
65 | safeunlink(path, 0); | |
66 | return; | |
429fdbec | 67 | } |
62e76326 | 68 | |
9bc73deb | 69 | /* |
9ece7c7c | 70 | * If the queue length is greater than our limit, then we pause |
71 | * for a small amount of time, hoping that unlinkd has some | |
72 | * feedback for us. Maybe it just needs a slice of the CPU's | |
73 | * time. | |
74 | */ | |
9bc73deb | 75 | if (queuelen >= UNLINKD_QUEUE_LIMIT) { |
a1ad2f9b | 76 | #if defined(USE_EPOLL) || defined(USE_KQUEUE) || defined(USE_DEVPOLL) |
26ac0430 AJ |
77 | /* |
78 | * DPW 2007-04-23 | |
79 | * We can't use fd_set when using epoll() or kqueue(). In | |
80 | * these cases we block for 10 ms. | |
81 | */ | |
82 | xusleep(10000); | |
9ece7c7c | 83 | #else |
26ac0430 AJ |
84 | /* |
85 | * DPW 2007-04-23 | |
86 | * When we can use select, block for up to 100 ms. | |
87 | */ | |
e7a67ff1 | 88 | struct timeval to; |
89 | fd_set R; | |
90 | FD_ZERO(&R); | |
91 | FD_SET(unlinkd_rfd, &R); | |
92 | to.tv_sec = 0; | |
93 | to.tv_usec = 100000; | |
94 | select(unlinkd_rfd + 1, &R, NULL, NULL, &to); | |
9ece7c7c | 95 | #endif |
9bc73deb | 96 | } |
62e76326 | 97 | |
9bc73deb | 98 | /* |
62e76326 | 99 | * If there is at least one outstanding unlink request, then |
100 | * try to read a response. If there's nothing to read we'll | |
101 | * get an EWOULDBLOCK or whatever. If we get a response, then | |
102 | * decrement the queue size by the number of newlines read. | |
103 | */ | |
9bc73deb | 104 | if (queuelen > 0) { |
e053c141 | 105 | int bytes_read; |
62e76326 | 106 | int i; |
107 | char rbuf[512]; | |
e053c141 | 108 | bytes_read = read(unlinkd_rfd, rbuf, 511); |
62e76326 | 109 | |
e053c141 FC |
110 | if (bytes_read > 0) { |
111 | rbuf[bytes_read] = '\0'; | |
62e76326 | 112 | |
5db6bf73 | 113 | for (i = 0; i < bytes_read; ++i) |
62e76326 | 114 | if ('\n' == rbuf[i]) |
5e263176 | 115 | --queuelen; |
62e76326 | 116 | |
117 | assert(queuelen >= 0); | |
118 | } | |
9bc73deb | 119 | } |
62e76326 | 120 | |
9bc73deb | 121 | l = strlen(path); |
122 | assert(l < MAXPATHLEN); | |
123 | xstrncpy(buf, path, MAXPATHLEN); | |
5db6bf73 FC |
124 | buf[l] = '\n'; |
125 | ++l; | |
e053c141 | 126 | bytes_written = write(unlinkd_wfd, buf, l); |
62e76326 | 127 | |
e053c141 | 128 | if (bytes_written < 0) { |
e0236918 | 129 | debugs(2, DBG_IMPORTANT, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerror()); |
62e76326 | 130 | safeunlink(path, 0); |
131 | return; | |
e053c141 | 132 | } else if (bytes_written != l) { |
e0236918 | 133 | debugs(2, DBG_IMPORTANT, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes"); |
62e76326 | 134 | safeunlink(path, 0); |
135 | return; | |
9bc73deb | 136 | } |
62e76326 | 137 | |
e4f1fdae | 138 | ++statCounter.unlink.requests; |
5f0c8452 | 139 | /* |
62e76326 | 140 | * Increment this syscalls counter here, even though the syscall |
141 | * is executed by the helper process. We try to be consistent | |
142 | * in counting unlink operations. | |
143 | */ | |
e4f1fdae | 144 | ++statCounter.syscalls.disk.unlinks; |
5db6bf73 | 145 | ++queuelen; |
429fdbec | 146 | } |
147 | ||
148 | void | |
149 | unlinkdClose(void) | |
1191b93b | 150 | #if _SQUID_MSWIN_ |
5c3c8c03 | 151 | { |
152 | ||
26ac0430 | 153 | if (unlinkd_wfd > -1) { |
e0236918 | 154 | debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd); |
5c3c8c03 | 155 | shutdown(unlinkd_wfd, SD_BOTH); |
156 | comm_close(unlinkd_wfd); | |
157 | ||
158 | if (unlinkd_wfd != unlinkd_rfd) | |
159 | comm_close(unlinkd_rfd); | |
160 | ||
161 | unlinkd_wfd = -1; | |
162 | ||
163 | unlinkd_rfd = -1; | |
c521ad17 | 164 | } |
5c3c8c03 | 165 | |
26ac0430 | 166 | if (hIpc) { |
5c3c8c03 | 167 | if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) { |
168 | getCurrentTime(); | |
e0236918 | 169 | debugs(2, DBG_IMPORTANT, "unlinkdClose: WARNING: (unlinkd," << pid << "d) didn't exit in 5 seconds"); |
5c3c8c03 | 170 | } |
171 | ||
172 | CloseHandle(hIpc); | |
173 | } | |
174 | } | |
175 | #else | |
429fdbec | 176 | { |
5c3c8c03 | 177 | |
3502d32f | 178 | if (unlinkd_wfd < 0) |
62e76326 | 179 | return; |
180 | ||
e0236918 | 181 | debugs(2, DBG_IMPORTANT, "Closing unlinkd pipe on FD " << unlinkd_wfd); |
62e76326 | 182 | |
06f8f350 | 183 | file_close(unlinkd_wfd); |
62e76326 | 184 | |
18e72ae1 | 185 | if (unlinkd_wfd != unlinkd_rfd) |
62e76326 | 186 | file_close(unlinkd_rfd); |
187 | ||
06f8f350 | 188 | unlinkd_wfd = -1; |
62e76326 | 189 | |
06f8f350 | 190 | unlinkd_rfd = -1; |
429fdbec | 191 | } |
192 | ||
5c3c8c03 | 193 | #endif |
194 | ||
c521ad17 DK |
195 | bool |
196 | unlinkdNeeded(void) | |
197 | { | |
198 | // we should start unlinkd if there are any cache_dirs using it | |
199 | for (int i = 0; i < Config.cacheSwap.n_configured; ++i) { | |
200 | const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i]; | |
201 | if (sd->unlinkdUseful()) | |
202 | return true; | |
203 | } | |
204 | ||
205 | return false; | |
206 | } | |
207 | ||
429fdbec | 208 | void |
209 | unlinkdInit(void) | |
210 | { | |
c521ad17 DK |
211 | if (unlinkd_wfd >= 0) |
212 | return; // unlinkd already started | |
213 | ||
a2c963ae | 214 | const char *args[2]; |
b7ac5457 | 215 | Ip::Address localhost; |
62e76326 | 216 | |
06f8f350 | 217 | args[0] = "(unlinkd)"; |
218 | args[1] = NULL; | |
cc192b50 | 219 | localhost.SetLocalhost(); |
220 | ||
b5d712b5 | 221 | pid = ipcCreate( |
8a09e810 | 222 | #if USE_POLL && _SQUID_OSF_ |
b5d712b5 | 223 | /* pipes and poll() don't get along on DUNIX -DW */ |
224 | IPC_STREAM, | |
8a09e810 | 225 | #elif _SQUID_MSWIN_ |
26ac0430 AJ |
226 | /* select() will fail on a pipe */ |
227 | IPC_TCP_SOCKET, | |
2b9a692c | 228 | #else |
26ac0430 AJ |
229 | /* We currently need to use FIFO.. see below */ |
230 | IPC_FIFO, | |
2b9a692c | 231 | #endif |
b5d712b5 | 232 | Config.Program.unlinkd, |
233 | args, | |
234 | "unlinkd", | |
cc192b50 | 235 | localhost, |
b5d712b5 | 236 | &unlinkd_rfd, |
237 | &unlinkd_wfd, | |
238 | &hIpc); | |
62e76326 | 239 | |
5c3c8c03 | 240 | if (pid < 0) |
62e76326 | 241 | fatal("Failed to create unlinkd subprocess"); |
b5d712b5 | 242 | |
9ece7c7c | 243 | xusleep(250000); |
b5d712b5 | 244 | |
06f8f350 | 245 | fd_note(unlinkd_wfd, "squid -> unlinkd"); |
b5d712b5 | 246 | |
06f8f350 | 247 | fd_note(unlinkd_rfd, "unlinkd -> squid"); |
b5d712b5 | 248 | |
933dd095 AJ |
249 | commUnsetFdTimeout(unlinkd_rfd); |
250 | commUnsetFdTimeout(unlinkd_wfd); | |
b5d712b5 | 251 | |
9bc73deb | 252 | /* |
62e76326 | 253 | * unlinkd_rfd should already be non-blocking because of |
254 | * ipcCreate. We change unlinkd_wfd to blocking mode because | |
255 | * we never want to lose an unlink request, and we don't have | |
256 | * code to retry if we get EWOULDBLOCK. Unfortunately, we can | |
257 | * do this only for the IPC_FIFO case. | |
258 | */ | |
7e3ce7b9 | 259 | assert(fd_table[unlinkd_rfd].flags.nonblocking); |
b5d712b5 | 260 | |
7e3ce7b9 | 261 | if (FD_PIPE == fd_table[unlinkd_wfd].type) |
62e76326 | 262 | commUnsetNonBlocking(unlinkd_wfd); |
b5d712b5 | 263 | |
e0236918 | 264 | debugs(2, DBG_IMPORTANT, "Unlinkd pipe opened on FD " << unlinkd_wfd); |
5c3c8c03 | 265 | |
1191b93b | 266 | #if _SQUID_MSWIN_ |
5c3c8c03 | 267 | |
4a7a3d56 | 268 | debugs(2, 4, "Unlinkd handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid); |
5c3c8c03 | 269 | |
270 | #endif | |
271 | ||
429fdbec | 272 | } |