]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Cleaned up ConnStateData's closing and destruction.
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 11 Sep 2008 04:54:34 +0000 (22:54 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 11 Sep 2008 04:54:34 +0000 (22:54 -0600)
1) Despite its name and the "if (open) close" use in ConnStateData destructor,
ConnStateData::close() was not closing anything. It was called from the Comm
close handler and from the destructor and would attempt to immediately delete
the ConnStateData object. Protecting code in deleteThis() may have prevented
the actual [double] delete from happening, but it is difficult to say exactly
what was going on when close() was being called from the destructor.

I converted ConnStateData::close to swanSong, which is the standard AsyncJob
cleanup method. As before, the method does not close anything (which may be
wrong). The swanSong method is never called directly by the user code. It is
called by lower layers just before the job is destroyed.

We may need to add Comm closing code to swanSong. For now, the updated
ConnStateData destructor will warn if ConnStateData forgot to close
the connection. The destructor will also warn if swanSong was not called,
which would mean that the job object is being deleted incorrectly.

2) Polished ClientSocketContext::writeComplete to distinguish
STREAM_UNPLANNED_COMPLETE from STREAM_FAILED closing state. This helps when
looking at stack traces.

3) Added an XXX comment about duplicated code.

4) Documented ClientSocketContext::initiateClose purpose and context.

src/client_side.cc
src/client_side.h

index 043d9026a7101fd0a1899d054c57a51379603a51..325f3649cc91c3447d4140d37dd4d2a410ae50f3 100644 (file)
@@ -602,14 +602,14 @@ ConnStateData::freeAllContexts()
 void ConnStateData::connStateClosed(const CommCloseCbParams &io)
 {
     assert (fd == io.fd);
-    close();
+    deleteThis("ConnStateData::connStateClosed");
 }
 
+// cleans up before destructor is called
 void
-ConnStateData::close()
+ConnStateData::swanSong()
 {
-    debugs(33, 3, "ConnStateData::close: FD " << fd);
-    deleteThis("ConnStateData::close");
+    debugs(33, 2, "ConnStateData::swanSong: FD " << fd);
     fd = -1;
     flags.readMoreRequests = false;
     clientdbEstablished(peer, -1);     /* decrement */
@@ -617,9 +617,12 @@ ConnStateData::close()
     freeAllContexts();
 
     if (auth_user_request != NULL) {
-        debugs(33, 4, "ConnStateData::close: freeing auth_user_request '" << auth_user_request << "' (this is '" << this << "')");
+        debugs(33, 4, "ConnStateData::swanSong: freeing auth_user_request '" << auth_user_request << "' (this is '" << this << "')");
         auth_user_request->onConnectionClose(this);
     }
+
+    BodyProducer::swanSong();
+    flags.swanSang = true;
 }
 
 bool
@@ -636,7 +639,10 @@ ConnStateData::~ConnStateData()
     debugs(33, 3, "ConnStateData::~ConnStateData: FD " << fd);
 
     if (isOpen())
-        close();
+        debugs(33, 1, "BUG: ConnStateData did not close FD " << fd);
+
+    if (!flags.swanSang)
+        debugs(33, 1, "BUG: ConnStateData was not destroyed properly; FD " << fd);
 
     AUTHUSERREQUESTUNLOCK(auth_user_request, "~conn");
 
@@ -1587,6 +1593,8 @@ ClientSocketContext::doClose()
     comm_close(fd());
 }
 
+/** Called to initiate (and possibly complete) closing of the context.
+ * The underlying socket may be already closed */
 void
 ClientSocketContext::initiateClose(const char *reason)
 {
@@ -1660,10 +1668,11 @@ ClientSocketContext::writeComplete(int fd, char *bufnotused, size_t size, comm_e
         return;
 
     case STREAM_UNPLANNED_COMPLETE:
-        /* fallthrough */
+        initiateClose("STREAM_UNPLANNED_COMPLETE");
+        return;
 
     case STREAM_FAILED:
-        initiateClose("STREAM_UNPLANNED_COMPLETE|STREAM_FAILED");
+        initiateClose("STREAM_FAILED");
         return;
 
     default:
@@ -2551,6 +2560,7 @@ ConnStateData::clientReadRequest(const CommIoCbParams &io)
          * The above check with connFinishedWithConn() only
          * succeeds _if_ the buffer is empty which it won't
          * be if we have an incomplete request.
+         * XXX: This duplicates ClientSocketContext::keepaliveNextRequest
          */
         if (getConcurrentRequestCount() == 0 && commIsHalfClosed(fd)) {
             debugs(33, 5, "clientReadRequest: FD " << fd << ": half-closed connection, no completed request parsed, connection closing.");
index 28eb767f2db25bc20d84054209f6139168146910..def37ed7cfef11679d8915d481ac0ad7848465b4 100644 (file)
@@ -142,7 +142,6 @@ public:
     ClientSocketContext::Pointer getCurrentContext() const;
     void addContextToQueue(ClientSocketContext * context);
     int getConcurrentRequestCount() const;
-    void close();
     bool isOpen() const;
 
     int fd;
@@ -188,6 +187,7 @@ public:
     struct
     {
         bool readMoreRequests;
+        bool swanSang; // XXX: temporary flag to check proper cleanup
     } flags;
     http_port_list *port;
 
@@ -213,6 +213,7 @@ public:
 
     // AsyncJob API
     virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
+    virtual void swanSong();
 
 #if USE_SSL
     bool switchToHttps();