From 998ebfc01bd55438b34b5a8f7aae7bbe69a83db5 Mon Sep 17 00:00:00 2001
From: Alexander Boettcher <alexander.boettcher@genode-labs.com>
Date: Tue, 7 Aug 2012 13:19:28 +0200
Subject: [PATCH] NOVA: Fix cleanup of received capabilities, #268

MsgBuf has to keep the number of received capabilities in order
to free/know correctly unused and unwanted capabilities. Explicitly
call rcv_msg->post_ipc to store this information in a MsgBuf.

Don't reset rcv_msg in ipc.cc, since this is used during
un-marshalling of caps in ipc.h afterwards. The MsgBuf is reseted when its
de-constructor is called.
---
 base-nova/include/base/ipc_msgbuf.h | 24 ++++++++++++++++--------
 base-nova/src/base/ipc/ipc.cc       |  3 +--
 base-nova/src/base/server/server.cc |  1 +
 3 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/base-nova/include/base/ipc_msgbuf.h b/base-nova/include/base/ipc_msgbuf.h
index c18a85a37c..5bcec79ac7 100644
--- a/base-nova/include/base/ipc_msgbuf.h
+++ b/base-nova/include/base/ipc_msgbuf.h
@@ -50,7 +50,7 @@ namespace Genode {
 			/**
 			 * Base of portal receive window
 			 */
-			int _rcv_pt_base;
+			addr_t _rcv_pt_base;
 
 			struct {
 				addr_t sel;
@@ -64,9 +64,9 @@ namespace Genode {
 			unsigned _rcv_pt_sel_max;
 
 			/**
-			 * Flag set to true if receive window must be re-initialized
+			 * Number of capabilities which has been received, reported by the kernel.
 			 */
-			bool _rcv_dirty;
+			unsigned _rcv_items;
 
 			char _msg_start[];  /* symbol marks start of message */
 
@@ -75,12 +75,17 @@ namespace Genode {
 			/**
 			 * Constructor
 			 */
-			Msgbuf_base() : _rcv_dirty(true)
+			Msgbuf_base() : _rcv_pt_base(~0UL), _rcv_items(0)
 			{
 				rcv_reset();
 				snd_reset();
 			}
 
+			~Msgbuf_base()
+			{
+				rcv_reset();
+			}
+
 			/*
 			 * Begin of actual message buffer
 			 */
@@ -156,11 +161,16 @@ namespace Genode {
 					return 0;
 			}
 
+			/**
+			 * Return true if receive window must be re-initialized
+			 */
+			bool rcv_invalid() { return _rcv_pt_base == ~0UL; }
+
 			/**
 			 * Return true if receive window must be re-initialized
 			 *
 			 * After reading portal selectors from the message buffer using
-			 * 'rcv_pt_sel()', we assume that the IDC call populared the
+			 * 'rcv_pt_sel()', we assume that the IDC call populated the
 			 * current receive window with one or more portal capabilities.
 			 * To enable the reception of portal capability selectors for the
 			 * next IDC, we need a fresh receive window.
@@ -231,10 +241,8 @@ namespace Genode {
 			 */
 			void rcv_prepare_pt_sel_window(Nova::Utcb *utcb)
 			{
-				if (rcv_dirty()) {
+				if (rcv_invalid() || rcv_cleanup(true))
 					_rcv_pt_base = cap_selector_allocator()->alloc(MAX_CAP_ARGS_LOG2);
-					_rcv_dirty = false;
-				}
 
 				/* register receive window at the UTCB */
 				utcb->crd_rcv = Nova::Obj_crd(rcv_pt_base(),MAX_CAP_ARGS_LOG2);
diff --git a/base-nova/src/base/ipc/ipc.cc b/base-nova/src/base/ipc/ipc.cc
index 8047de2a4a..fa29666d44 100644
--- a/base-nova/src/base/ipc/ipc.cc
+++ b/base-nova/src/base/ipc/ipc.cc
@@ -49,8 +49,6 @@ static void copy_utcb_to_msgbuf(Nova::Utcb *utcb, Msgbuf_base *rcv_msg)
 	mword_t *dst = (mword_t *)&msg_buf[0];
 	for (unsigned i = 0; i < num_msg_words; i++)
 		*dst++ = *src++;
-
-	rcv_msg->rcv_reset();
 }
 
 
@@ -151,6 +149,7 @@ void Ipc_client::_call()
 		PERR("call returned %u", res);
 	}
 
+	_rcv_msg->post_ipc(utcb);
 	copy_utcb_to_msgbuf(utcb, _rcv_msg);
 	_snd_msg->snd_reset();
 
diff --git a/base-nova/src/base/server/server.cc b/base-nova/src/base/server/server.cc
index a504e64085..14e1bc40ec 100644
--- a/base-nova/src/base/server/server.cc
+++ b/base-nova/src/base/server/server.cc
@@ -133,6 +133,7 @@ void Rpc_entrypoint::_activation_entry()
 	Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(Thread_base::myself());
 
 	Ipc_server srv(&ep->_snd_buf, &ep->_rcv_buf);
+	ep->_rcv_buf.post_ipc(reinterpret_cast<Nova::Utcb *>(ep->utcb()));
 
 	/* destination of next reply */
 	srv.dst(Native_capability(id_pt, srv.badge()));