]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Write.cc
3 #include "ClientInfo.h"
5 #include "comm/Connection.h"
6 #include "comm/IoCallback.h"
7 #include "comm/Write.h"
9 #include "StatCounters.h"
10 #include "SquidTime.h"
14 Comm::Write(const Comm::ConnectionPointer
&conn
, MemBuf
*mb
, AsyncCall::Pointer
&callback
)
16 Comm::Write(conn
, mb
->buf
, mb
->size
, callback
, mb
->freeFunc());
20 Comm::Write(const Comm::ConnectionPointer
&conn
, const char *buf
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
22 debugs(5, 5, HERE
<< conn
<< ": sz " << size
<< ": asynCall " << callback
);
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());
30 fd_table
[conn
->fd
].writeStart
= squid_curtime
;
33 ccb
->setCallback(IOCB_WRITE
, callback
, (char *)buf
, free_func
, size
);
34 ccb
->selectOrQueueWrite();
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.
43 Comm::HandleWrite(int fd
, void *data
)
45 Comm::IoCallback
*state
= static_cast<Comm::IoCallback
*>(data
);
49 assert(state
->conn
!= NULL
&& state
->conn
->fd
== fd
);
51 PROF_start(commHandleWrite
);
52 debugs(5, 5, HERE
<< state
->conn
<< ": off " <<
53 (long int) state
->offset
<< ", sz " << (long int) state
->size
<< ".");
55 nleft
= state
->size
- state
->offset
;
58 ClientInfo
* clientInfo
=fd_table
[fd
].clientInfo
;
60 if (clientInfo
&& !clientInfo
->writeLimitingActive
)
61 clientInfo
= NULL
; // we only care about quota limits here
64 assert(clientInfo
->selectWaiting
);
65 clientInfo
->selectWaiting
= false;
67 assert(clientInfo
->hasQueue());
68 assert(clientInfo
->quotaPeekFd() == fd
);
69 clientInfo
->quotaDequeue(); // we will write or requeue below
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
);
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
;
89 #endif /* USE_DELAY_POOLS */
91 /* actually WRITE data */
92 len
= FD_WRITE_METHOD(fd
, state
->buf
+ state
->offset
, nleft
);
93 debugs(5, 5, HERE
<< "write() returns " << len
);
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;
106 // even if we wrote nothing, we were served; give others a chance
107 clientInfo
->kickQuotaQueue();
109 #endif /* USE_DELAY_POOLS */
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
;
118 /* Note we even call write if nleft == 0 */
121 debugs(5, DBG_IMPORTANT
, "FD " << fd
<< " write failure: connection closed with " << nleft
<< " bytes remaining.");
123 state
->finish(nleft
? COMM_ERROR
: COMM_OK
, errno
);
124 } else if (len
< 0) {
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();
133 debugs(50, 2, HERE
<< "FD " << fd
<< " write failure: " << xstrerror() << ".");
134 state
->finish(nleft
? COMM_ERROR
: COMM_OK
, errno
);
137 /* A successful write, continue */
138 state
->offset
+= len
;
140 if (state
->offset
< state
->size
) {
141 /* Not done, reinstall the write handler and write some more */
142 state
->selectOrQueueWrite();
144 state
->finish(nleft
? COMM_OK
: COMM_ERROR
, errno
);
148 PROF_stop(commHandleWrite
);