Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 2a2fbc84d3b2a2ff06b9bb236ff8e813c17ce223)
+++ kernel/generic/src/ipc/ipc.c	(revision 43e2cbcf82bf0d553c0cb190d4043a6eed86a617)
@@ -59,4 +59,6 @@
 #include <ipc/irq.h>
 
+static void ipc_forget_call(call_t *);
+
 /** Open channel that is assigned automatically to new tasks */
 answerbox_t *ipc_phone_0 = NULL;
@@ -209,9 +211,50 @@
 		return rc;
 	}
-	// TODO: forget the call if interrupted
-	(void) ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
+
+	call_t *answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
+	    SYNCH_FLAGS_INTERRUPTIBLE);
+	if (!answer) {
+
+		/*
+		 * The sleep was interrupted.
+		 *
+		 * There are two possibilities now:
+		 * 1) the call gets answered before we manage to forget it
+		 * 2) we manage to forget the call before it gets answered
+		 */
+
+		spinlock_lock(&request->forget_lock);
+		spinlock_lock(&TASK->active_calls_lock);
+
+		ASSERT(!request->forget);
+
+		bool answered = !request->active;
+		if (!answered) {
+			/*
+			 * The call is not yet answered and we won the race to
+			 * forget it.
+			 */
+			ipc_forget_call(request);	/* releases locks */
+			rc = EINTR;
+			
+		} else {
+			spinlock_unlock(&TASK->active_calls_lock);
+			spinlock_unlock(&request->forget_lock);
+		}
+
+		if (answered) {
+			/*
+			 * The other side won the race to answer the call.
+			 * It is safe to wait for the answer uninterruptibly
+			 * now.
+			 */
+			answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
+			    SYNCH_FLAGS_NONE);
+		}
+	}
+	ASSERT(!answer || request == answer);
 	
 	slab_free(ipc_answerbox_slab, mybox);
-	return EOK;
+	return rc;
 }
 
@@ -621,4 +664,34 @@
 }
 
+static void ipc_forget_call(call_t *call)
+{
+	ASSERT(spinlock_locked(&TASK->active_calls_lock));
+	ASSERT(spinlock_locked(&call->forget_lock));
+
+	/*
+	 * Forget the call and donate it to the task which holds up the answer.
+	 */
+
+	call->forget = true;
+	call->sender = NULL;
+	list_remove(&call->ta_link);
+
+	/*
+	 * The call may be freed by _ipc_answer_free_call() before we are done
+	 * with it; to avoid working with a destroyed call_t structure, we
+	 * must hold a reference to it.
+	 */
+	ipc_call_hold(call);
+
+	spinlock_unlock(&call->forget_lock);
+	spinlock_unlock(&TASK->active_calls_lock);
+
+	atomic_dec(&call->caller_phone->active_calls);
+
+	SYSIPC_OP(request_forget, call);
+
+	ipc_call_release(call);
+}
+
 static void ipc_forget_all_active_calls(void)
 {
@@ -649,27 +722,5 @@
 	}
 
-	/*
-	 * Forget the call and donate it to the task which holds up the answer.
-	 */
-
-	call->forget = true;
-	call->sender = NULL;
-	list_remove(&call->ta_link);
-
-	/*
-	 * The call may be freed by _ipc_answer_free_call() before we are done
-	 * with it; to avoid working with a destroyed call_t structure, we
-	 * must hold a reference to it.
-	 */
-	ipc_call_hold(call);
-
-	spinlock_unlock(&call->forget_lock);
-	spinlock_unlock(&TASK->active_calls_lock);
-
-	atomic_dec(&call->caller_phone->active_calls);
-
-	SYSIPC_OP(request_forget, call);
-
-	ipc_call_release(call);
+	ipc_forget_call(call);
 
 	goto restart;
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 2a2fbc84d3b2a2ff06b9bb236ff8e813c17ce223)
+++ kernel/generic/src/ipc/sysipc.c	(revision 43e2cbcf82bf0d553c0cb190d4043a6eed86a617)
@@ -285,5 +285,10 @@
 #endif
 
-		rc = ipc_call_sync(phone, call); 
+		ipc_call_hold(call);
+		rc = ipc_call_sync(phone, call);
+		spinlock_lock(&call->forget_lock);
+		bool forgotten = call->forget;
+		spinlock_unlock(&call->forget_lock);
+		ipc_call_release(call);
 
 #ifdef CONFIG_UDEBUG
@@ -291,6 +296,23 @@
 #endif
 
-		if (rc != EOK)
-			return EINTR;
+		if (rc != EOK) {
+			if (!forgotten) {
+				/*
+				 * There was an error, but it did not result
+				 * in the call being forgotten. In fact, the
+				 * call was not even sent. We are still
+				 * its owners and are responsible for its
+				 * deallocation.
+				 */
+				ipc_call_free(call);
+			} else {
+				/*
+				 * The call was forgotten and it changed hands.
+				 * We are no longer expected to free it.
+				 */
+				ASSERT(rc == EINTR);
+			}
+			return rc;	
+		}
 
 		process_answer(call);
