]> git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Write.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / comm / Write.cc
1 #include "squid.h"
2 #if USE_DELAY_POOLS
3 #include "ClientInfo.h"
4 #endif
5 #include "comm/Connection.h"
6 #include "comm/IoCallback.h"
7 #include "comm/Write.h"
8 #include "fde.h"
9 #include "StatCounters.h"
10 #include "SquidTime.h"
11 #include "MemBuf.h"
12
13 void
14 Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback)
15 {
16 Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc());
17 }
18
19 void
20 Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
21 {
22 debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback);
23
24 /* Make sure we are open, not closing, and not writing */
25 assert(fd_table[conn->fd].flags.open);
26 assert(!fd_table[conn->fd].closing());
27 Comm::IoCallback *ccb = COMMIO_FD_WRITECB(conn->fd);
28 assert(!ccb->active());
29
30 fd_table[conn->fd].writeStart = squid_curtime;
31 ccb->conn = conn;
32 /* Queue the write */
33 ccb->setCallback(IOCB_WRITE, callback, (char *)buf, free_func, size);
34 ccb->selectOrQueueWrite();
35 }
36
37 /** Write to FD.
38 * This function is used by the lowest level of IO loop which only has access to FD numbers.
39 * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections.
40 * Once the write has been concluded we schedule the waiting call with success/fail results.
41 */
42 void
43 Comm::HandleWrite(int fd, void *data)
44 {
45 Comm::IoCallback *state = static_cast<Comm::IoCallback *>(data);
46 int len = 0;
47 int nleft;
48
49 assert(state->conn != NULL && state->conn->fd == fd);
50
51 PROF_start(commHandleWrite);
52 debugs(5, 5, HERE << state->conn << ": off " <<
53 (long int) state->offset << ", sz " << (long int) state->size << ".");
54
55 nleft = state->size - state->offset;
56
57 #if USE_DELAY_POOLS
58 ClientInfo * clientInfo=fd_table[fd].clientInfo;
59
60 if (clientInfo && !clientInfo->writeLimitingActive)
61 clientInfo = NULL; // we only care about quota limits here
62
63 if (clientInfo) {
64 assert(clientInfo->selectWaiting);
65 clientInfo->selectWaiting = false;
66
67 assert(clientInfo->hasQueue());
68 assert(clientInfo->quotaPeekFd() == fd);
69 clientInfo->quotaDequeue(); // we will write or requeue below
70
71 if (nleft > 0) {
72 const int quota = clientInfo->quotaForDequed();
73 if (!quota) { // if no write quota left, queue this fd
74 state->quotaQueueReserv = clientInfo->quotaEnqueue(fd);
75 clientInfo->kickQuotaQueue();
76 PROF_stop(commHandleWrite);
77 return;
78 }
79
80 const int nleft_corrected = min(nleft, quota);
81 if (nleft != nleft_corrected) {
82 debugs(5, 5, HERE << state->conn << " writes only " <<
83 nleft_corrected << " out of " << nleft);
84 nleft = nleft_corrected;
85 }
86
87 }
88 }
89 #endif /* USE_DELAY_POOLS */
90
91 /* actually WRITE data */
92 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
93 debugs(5, 5, HERE << "write() returns " << len);
94
95 #if USE_DELAY_POOLS
96 if (clientInfo) {
97 if (len > 0) {
98 /* we wrote data - drain them from bucket */
99 clientInfo->bucketSize -= len;
100 if (clientInfo->bucketSize < 0.0) {
101 debugs(5,1, HERE << "drained too much"); // should not happen
102 clientInfo->bucketSize = 0;
103 }
104 }
105
106 // even if we wrote nothing, we were served; give others a chance
107 clientInfo->kickQuotaQueue();
108 }
109 #endif /* USE_DELAY_POOLS */
110
111 fd_bytes(fd, len, FD_WRITE);
112 ++statCounter.syscalls.sock.writes;
113 // After each successful partial write,
114 // reset fde::writeStart to the current time.
115 fd_table[fd].writeStart = squid_curtime;
116
117 if (len == 0) {
118 /* Note we even call write if nleft == 0 */
119 /* We're done */
120 if (nleft != 0)
121 debugs(5, DBG_IMPORTANT, "FD " << fd << " write failure: connection closed with " << nleft << " bytes remaining.");
122
123 state->finish(nleft ? COMM_ERROR : COMM_OK, errno);
124 } else if (len < 0) {
125 /* An error */
126 if (fd_table[fd].flags.socket_eof) {
127 debugs(50, 2, HERE << "FD " << fd << " write failure: " << xstrerror() << ".");
128 state->finish(nleft ? COMM_ERROR : COMM_OK, errno);
129 } else if (ignoreErrno(errno)) {
130 debugs(50, 9, HERE << "FD " << fd << " write failure: " << xstrerror() << ".");
131 state->selectOrQueueWrite();
132 } else {
133 debugs(50, 2, HERE << "FD " << fd << " write failure: " << xstrerror() << ".");
134 state->finish(nleft ? COMM_ERROR : COMM_OK, errno);
135 }
136 } else {
137 /* A successful write, continue */
138 state->offset += len;
139
140 if (state->offset < state->size) {
141 /* Not done, reinstall the write handler and write some more */
142 state->selectOrQueueWrite();
143 } else {
144 state->finish(nleft ? COMM_OK : COMM_ERROR, errno);
145 }
146 }
147
148 PROF_stop(commHandleWrite);
149 }