Index: webtraf.cc
===================================================================
RCS file: /usr/src/mash/repository/vint/ns-2/webcache/webtraf.cc,v
retrieving revision 1.5
diff -u -r1.5 webtraf.cc
--- webtraf.cc	1999/12/03 21:11:46	1.5
+++ webtraf.cc	2000/04/12 17:07:22
@@ -26,7 +26,7 @@
 //
 // Incorporation Polly's web traffic module into the PagePool framework
 //
-// $Header: /usr/src/mash/repository/vint/ns-2/webcache/webtraf.cc,v 1.5 1999/12/03 21:11:46 haoboy Exp $
+// $Header: /usr/src/mash/repository/vint/ns-2/webcache/webtraf.cc,v 1.7 2000/02/24 02:18:22 haoboy Exp $
 
 #include "config.h"
 #include <tclcl.h>
@@ -47,10 +47,12 @@
 		id_(id), sess_(sess), nObj_(nObj), curObj_(0), dst_(dst) {}
 	virtual ~WebPage() {}
 
-	void start() {
-		expire();
-		schedNext();
+	inline void start() {
+		// Call expire() and schedule the next one if needed
+		status_ = TIMER_PENDING;
+		handle(&event_);
 	}
+	inline int id() const { return id_; }
 	Node* dst() { return dst_; }
 
 private:
@@ -60,17 +62,23 @@
 				 (int)ceil(sess_->objSize()->value()));
 	}
 	virtual void handle(Event *e) {
-		TimerHandler::handle(e);
-		schedNext();
-	}
-	void schedNext() {
-		// Schedule next timer
-		if (++curObj_ >= nObj_) {
-			// We are done with this page, tell parent to delete me
+		// XXX Note when curObj_ == nObj_, we still schedule the timer
+		// once, but we do not actually send out requests. This extra
+		// schedule is only meant to be a hint to wait for the last
+		// request to finish, then we will ask our parent to delete
+		// this page.
+#if 0
+		fprintf(stderr, "Session %d handling page %d obj %d\n",
+			sess_->id(), id_, curObj_);
+#endif
+		if (curObj_ <= nObj_) {
+			// If this is not the last object, schedule the next 
+			// one. Otherwise stop and tell session to delete me.
+			TimerHandler::handle(e);
+			curObj_++;
+			sched(sess_->interObj()->value());
+		} else
 			sess_->donePage((void*)this);
-			return;
-		}
-		sched(sess_->interObj()->value());
 	}
 	int id_;
 	WebTrafSession* sess_;
@@ -92,7 +100,10 @@
 			donePage_, curPage_);
 		abort();
 	}
-
+	if (status_ != TIMER_IDLE) {
+		fprintf(stderr, "WebTrafSession must be idle when deleted.\n");
+		abort();
+	}
 	if (rvInterPage_ != NULL)
 		Tcl::instance().evalf("delete %s", rvInterPage_->name());
 	if (rvPageSize_ != NULL)
@@ -105,6 +116,10 @@
 
 void WebTrafSession::donePage(void* ClntData) 
 {
+#if 0
+	fprintf(stderr, "Session %d done page %d\n", id_, 
+		((WebPage*)ClntData)->id());
+#endif
 	delete (WebPage*)ClntData;
 	// If all pages are done, tell my parent to delete myself
 	if (++donePage_ >= nPage_)
@@ -119,19 +134,23 @@
 	// Make sure page size is not 0!
 	WebPage* pg = new WebPage(LASTPAGE_++, this, 
 				  (int)ceil(rvPageSize_->value()), dst);
+#if 0
+	printf("Session %d starting page %d, curpage %d \n", 
+	       id_, LASTPAGE_-1, curPage_);
+#endif
 	pg->start();
 }
 
 void WebTrafSession::handle(Event *e)
 {
+	// If I haven't scheduled all my pages, do the next one
 	TimerHandler::handle(e);
-	// If I've scheduled all my pages, don't schedule it any more.
-	if (++curPage_ >= nPage_)
-		return;
-#if 0
-	printf("Session %d schedule next page %d\n", id_, LASTPAGE_);
-#endif
-	sched(rvInterPage_->value());
+	// XXX Notice before each page is done, it will schedule itself 
+	// one more time, this makes sure that this session will not be
+	// deleted after the above call. Thus the following code will not
+	// be executed in the context of a deleted object. 
+	if (++curPage_ < nPage_)
+		sched(rvInterPage_->value());
 }
 
 // Launch a request for a particular object
@@ -154,9 +173,9 @@
 	// Debug only
 	// $numPacket_ $objectId_ $pageId_ $sessionId_ [$ns_ now] src dst
 #if 0
-	printf("%d \t %d \t %d \t %d \t %g %d %d\n", size, obj, page, id_,
-		Scheduler::instance().clock(), 
-	       src_->address(), dst->address());
+	printf("%d \t %d \t %d \t %d \t %g %d %d\n", size, obj, pg->id(), id_,
+	       Scheduler::instance().clock(), 
+	       src_->address(), pg->dst()->address());
 	printf("** Tcp agents %d, Tcp sinks %d\n", mgr_->nTcp(),mgr_->nSink());
 #endif
 }
