]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Write.cc
2 #include "comm/Connection.h"
3 #include "comm/IoCallback.h"
4 #include "comm/Write.h"
9 #include "profiler/Profiler.h"
10 #include "SquidTime.h"
11 #include "StatCounters.h"
14 #include "ClientInfo.h"
21 Comm::Write(const Comm::ConnectionPointer
&conn
, MemBuf
*mb
, AsyncCall::Pointer
&callback
)
23 Comm::Write(conn
, mb
->buf
, mb
->size
, callback
, mb
->freeFunc());
27 Comm::Write(const Comm::ConnectionPointer
&conn
, const char *buf
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
29 debugs(5, 5, HERE
<< conn
<< ": sz " << size
<< ": asynCall " << callback
);
31 /* Make sure we are open, not closing, and not writing */
32 assert(fd_table
[conn
->fd
].flags
.open
);
33 assert(!fd_table
[conn
->fd
].closing());
34 Comm::IoCallback
*ccb
= COMMIO_FD_WRITECB(conn
->fd
);
35 assert(!ccb
->active());
37 fd_table
[conn
->fd
].writeStart
= squid_curtime
;
40 ccb
->setCallback(IOCB_WRITE
, callback
, (char *)buf
, free_func
, size
);
41 ccb
->selectOrQueueWrite();
45 * This function is used by the lowest level of IO loop which only has access to FD numbers.
46 * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections.
47 * Once the write has been concluded we schedule the waiting call with success/fail results.
50 Comm::HandleWrite(int fd
, void *data
)
52 Comm::IoCallback
*state
= static_cast<Comm::IoCallback
*>(data
);
56 assert(state
->conn
!= NULL
&& state
->conn
->fd
== fd
);
58 PROF_start(commHandleWrite
);
59 debugs(5, 5, HERE
<< state
->conn
<< ": off " <<
60 (long int) state
->offset
<< ", sz " << (long int) state
->size
<< ".");
62 nleft
= state
->size
- state
->offset
;
65 ClientInfo
* clientInfo
=fd_table
[fd
].clientInfo
;
67 if (clientInfo
&& !clientInfo
->writeLimitingActive
)
68 clientInfo
= NULL
; // we only care about quota limits here
71 assert(clientInfo
->selectWaiting
);
72 clientInfo
->selectWaiting
= false;
74 assert(clientInfo
->hasQueue());
75 assert(clientInfo
->quotaPeekFd() == fd
);
76 clientInfo
->quotaDequeue(); // we will write or requeue below
79 const int quota
= clientInfo
->quotaForDequed();
80 if (!quota
) { // if no write quota left, queue this fd
81 state
->quotaQueueReserv
= clientInfo
->quotaEnqueue(fd
);
82 clientInfo
->kickQuotaQueue();
83 PROF_stop(commHandleWrite
);
87 const int nleft_corrected
= min(nleft
, quota
);
88 if (nleft
!= nleft_corrected
) {
89 debugs(5, 5, HERE
<< state
->conn
<< " writes only " <<
90 nleft_corrected
<< " out of " << nleft
);
91 nleft
= nleft_corrected
;
96 #endif /* USE_DELAY_POOLS */
98 /* actually WRITE data */
99 len
= FD_WRITE_METHOD(fd
, state
->buf
+ state
->offset
, nleft
);
100 debugs(5, 5, HERE
<< "write() returns " << len
);
105 /* we wrote data - drain them from bucket */
106 clientInfo
->bucketSize
-= len
;
107 if (clientInfo
->bucketSize
< 0.0) {
108 debugs(5, DBG_IMPORTANT
, HERE
<< "drained too much"); // should not happen
109 clientInfo
->bucketSize
= 0;
113 // even if we wrote nothing, we were served; give others a chance
114 clientInfo
->kickQuotaQueue();
116 #endif /* USE_DELAY_POOLS */
118 fd_bytes(fd
, len
, FD_WRITE
);
119 ++statCounter
.syscalls
.sock
.writes
;
120 // After each successful partial write,
121 // reset fde::writeStart to the current time.
122 fd_table
[fd
].writeStart
= squid_curtime
;
125 /* Note we even call write if nleft == 0 */
128 debugs(5, DBG_IMPORTANT
, "FD " << fd
<< " write failure: connection closed with " << nleft
<< " bytes remaining.");
130 state
->finish(nleft
? COMM_ERROR
: COMM_OK
, errno
);
131 } else if (len
< 0) {
133 if (fd_table
[fd
].flags
.socket_eof
) {
134 debugs(50, 2, HERE
<< "FD " << fd
<< " write failure: " << xstrerror() << ".");
135 state
->finish(nleft
? COMM_ERROR
: COMM_OK
, errno
);
136 } else if (ignoreErrno(errno
)) {
137 debugs(50, 9, HERE
<< "FD " << fd
<< " write failure: " << xstrerror() << ".");
138 state
->selectOrQueueWrite();
140 debugs(50, 2, HERE
<< "FD " << fd
<< " write failure: " << xstrerror() << ".");
141 state
->finish(nleft
? COMM_ERROR
: COMM_OK
, errno
);
144 /* A successful write, continue */
145 state
->offset
+= len
;
147 if (state
->offset
< state
->size
) {
148 /* Not done, reinstall the write handler and write some more */
149 state
->selectOrQueueWrite();
151 state
->finish(nleft
? COMM_OK
: COMM_ERROR
, errno
);
155 PROF_stop(commHandleWrite
);