diff --git a/kernel/sched/pb.c b/kernel/sched/pb.c
index 1d9a011025fcf710903bb38ef66aa70777278132..e7633845b703c7fc9f26c007d1a2c7d210838544 100644
--- a/kernel/sched/pb.c
+++ b/kernel/sched/pb.c
@@ -40,6 +40,8 @@ SYSCALL_DEFINE1(pb_set_plan, pb_plan_t __user*, plan) {
 	unsigned long copied;
 	unsigned int i;
 	int res;
+
+	PBM* pbm;
 	
 	copied = copy_from_user(&_plan, plan, sizeof(pb_plan_t));
 	
@@ -68,8 +70,10 @@ SYSCALL_DEFINE1(pb_set_plan, pb_plan_t __user*, plan) {
 		return -1;
 	}
 
+	pbm = get_pbm_by_pid(last_plan_pid/*_plan.ref_pid (FIXME: THIS IS JUST FOR TESTING PURPOSES since it would be better to be able to insert the wanted pid as an argument)*/);
+
 	// prepare the plan runtime stack by pushing the root node of the reference model/plan
-	plan_rt_state_push(get_pbm_by_pid(last_plan_pid/*_plan.ref_pid (FIXME: THIS IS JUST FOR TESTING PURPOSES)*/)->root, task);
+	plan_rt_state_push(pbm->root, task);
 
 	rq = this_rq();
 
@@ -77,12 +81,18 @@ SYSCALL_DEFINE1(pb_set_plan, pb_plan_t __user*, plan) {
 	// it to contiue running instead of getting switched
 	reset_triggering_syscall_info();
 
-	// FIXME All new processes need to be initialized with the same initial settings as this one!
+	// Only the root process has the scheduling class manually set since it is already initialized
+	// for using the fair scheduler in the fork() syscall in pb_submitter which must happen before
+	// initializing the plan since knowledge of the PID of the root process is necessary to init
+	// the performance counting as soon as possible.
+	// BEWARE: This also means that the scheduling class of this root process needs to be reset to
+	// the fair scheduler on exit so that it can do the necessary cleanup in its data structures.
 	task->sched_class = &pb_sched_class;
 
 	pb_rq = &rq->pb;
 
 	pb_rq->root_proc = task;
+	pb_rq->num_exited_procs = pbm->child_count;
 
 	set_pb_plan_size(pb_rq, _plan.num_tasks);
 
@@ -223,15 +233,12 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 	u64 perf_counter;
 	u64 counter_diff;
 	u64 read_error;
-	bool premature_finish = false;
 	u64 expected_instr_count;
+	u64 diff_from_expected;
 	pbm_NODE* cur_node;
 	struct task_struct* cur_proc;
 	struct perf_event* pevent;
 
-	int fork_node_type;
-	pbm_NODE* fork_node;
-
 	bool process_exited = false;
 
 	printk("Dequeue task: %u\n", p->pid);
@@ -242,6 +249,7 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 	pb->waiting_on_io = 1;
 	c_entry_curr = pb->c_entry;
 
+	// safe current process for later use since the plan_rt_state might get modified
 	plan_rt_state_peek(&cur_node, &cur_proc);
 	pevent = get_pevent_by_pid(cur_proc->pid);
 	
@@ -258,24 +266,40 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 	switch(pb->triggering_syscall.type) {
 
 		case sched_trig_FORK:
-			// TODO If we do a fork: At which point is this called? before, during (between
-			//      parent and child) or after switching to the child?
-			printk(KERN_WARNING Bold Red "FORK TRIGGERED THIS!!!" End "\n");
-			// if a fork occured then the next node should be a fork node
-			fork_node = cur_node->children;
-			fork_node_type = fork_node->type;
-			if (FORK != fork_node_type) {
-				printk(KERN_WARNING "ERROR: Fork node expected but got: %i\n", fork_node_type);
+			{
+				int fork_node_type;
+				pbm_NODE* fork_node = cur_node->children;
+				fork_node_type = fork_node->type;
+
+				/**
+				* the scheduling class (pb) of the forked child is set in kernel/sched/core.c:sched_fork()
+				*/
+
+				printk(KERN_WARNING Bold Red "FORK TRIGGERED THIS!!!" End "\n");
+
+				// if a fork occured then the next node should be a fork node
+				if (FORK != fork_node_type) {
+					printk(KERN_WARNING "ERROR: Fork node expected but got: %i\n", fork_node_type);
+					//TODO: Delegate to higher instance
+				}
+
+				/**
+				* since we prepend the child node in pbm_fork() (see behave.c) the child of a
+				* fork-node is the child node (->children) while the parent is the next sibling
+				* (->next_sib).
+				*/
+
+				// update the parent node: Keep the process and replace the node before the fork
+				// with the _parent_ node after it
+				// Precondition: The plan_rt_state is not empty (since pb_set_plan() initialized it)
+				plan_rt_state_pop();
+				plan_rt_state_push(fork_node->children->next_sib, pb->triggering_syscall.origin);
+
+				// add the child
+				plan_rt_state_push(fork_node->children, pb->triggering_syscall.target);
+				plan_rt_state_debug_print();
+				break;
 			}
-			// set the scheduling policy
-			pb->triggering_syscall.target->sched_class = &pb_sched_class;
-			/* FIXME This does not work properly in case of the first (root) fork */ //<------------------------------------------------------
-			// since we prepend the child node in pbm_fork() (see behave.c) the child of a
-			// fork-node is the child node while the parent is the next sibling (next_sib).
-			plan_rt_state_push(fork_node->children,
-								pb->triggering_syscall.target); // .origin (for parent)
-			plan_rt_state_debug_print();
-			break;
 
 		case sched_trig_EXIT:
 			printk(KERN_WARNING Bold Red "EXIT TRIGGERED THIS!!!" End "\n");
@@ -317,15 +341,10 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 			*/
 			break;
 	}
-	// reset the info so that the relevant syscalls can be detected if they are the trigger
+	// reset the info so that the next relevant triggering syscall can be detected again
 	reset_triggering_syscall_info();
 
 	// printk(KERN_ALERT "DEBUG: Passed %s %d \n",__FUNCTION__,__LINE__);
-	/*
-	* dequeue_task() is called in __schedule() by deactivate_task() BEFORE pick_next_task() which
-	* means the state of the plan (e.g. in case of an exit) is not yet updated so we can assume
-	* that plan_rt_state still contains the current process as the head even if it is exiting!
-	*/
 	read_error = get_perf_counter(pevent, &perf_counter);
 	if (read_error) {
 		printk(KERN_WARNING "FETCHING PERFORMANCE COUNTER IN PB SCHEDULER FAILED WITH %llu\n", read_error);
@@ -334,30 +353,24 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 	printk(KERN_WARNING "COUNTER DIFF: %llu\n", counter_diff);
 	pb->plan[c_entry_curr].n_instr_counted = counter_diff;
 	pb->total_instr = perf_counter;
-	if (counter_diff < expected_instr_count) {
+	diff_from_expected = abs(counter_diff - expected_instr_count);
+	//TODO: Set proper threshold for significance (relative values would probably be better than absolutes)
+	if (diff_from_expected > 0) {
 		u64 under_time = expected_instr_count - counter_diff;
-
-		printk(KERN_WARNING "PB TASK %llu RAN %llu INSTRUCTIONS TOO SHORT\n", pb->plan[pb->c_entry].task_id, under_time);
-	} else if (counter_diff > expected_instr_count) {
-		//TODO: Check if actually an overflow occurs and an another calculation is necessary
-		// (setting a flag in the perf overflow_handler could be a solution)
-		u64 over_time = counter_diff - expected_instr_count;
-
-		printk(KERN_WARNING "PB TASK %llu RAN %llu INSTRUCTIONS TOO LONG\n", pb->plan[pb->c_entry].task_id, over_time);
+		printk(KERN_WARNING "PB TASK %u RAN %llu INSTRUCTIONS TOO %s\n", cur_proc->pid, under_time,
+				counter_diff < expected_instr_count ? "SHORT" : "LONG");
 	}
 
 	pb->c_entry++;
 
-	/**
-		* Don't schedule a task that is dead. (e.g. plan was incorrect and program finished quicker)
-		* TODO: if we have multiple tasks structs try the next plan entry
-		*/
-	if (!is_plan_finished(pb) && plan_rt_state_peek_proc()->state == TASK_DEAD) {
-		premature_finish = true;
+	//TODO: Can this actually happen? Can a process die without calling exit?
+	// remove a dead process which has not called exit from the plan
+	if (!process_exited && cur_proc->state == TASK_DEAD) {
+		plan_rt_state_pop();
 	}
 
-	if (is_plan_finished(pb) || premature_finish) {
-		if (premature_finish) {
+	if (is_plan_finished(pb)) {
+		if (!is_plan_successful(pb)) {
 			printk(KERN_WARNING "PLAN TERMINATED PREMATURELY \n");
 		}
 		else {
@@ -369,21 +382,12 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 	}
 	printk(KERN_WARNING Bold Yellow "Exited: %i .Proc state: %li (?= %i)" End "\n", process_exited, cur_proc->state, TASK_DEAD);
 
-	if (process_exited /*|| cur_proc->state == TASK_DEAD*/) {
-
+	if (process_exited && pb->root_proc == cur_proc) {
 		cur_proc->sched_class = &fair_sched_class;
-		/*
-		// set scheduler to CFS (see #normalize_rt_tasks(void))
-		struct sched_attr attr = {
-			.sched_policy = SCHED_NORMAL,
-			//.sched_priority = 0,
-			//.sched_nice	= 0
-		};
-		// this also calls set_curr_task() and check_class_changed() which is important (?)
-		sched_setattr(cur_proc, &attr);
-		*/
 		resched_curr(rq);
+	}
 
+		/*
 		// show all current processes (source: https://unix.stackexchange.com/questions/299140/linux-is-there-a-way-to-dump-the-task-run-queue/336663#336663)
 		{
 			struct task_struct *process, *thread;
@@ -405,7 +409,7 @@ static void dequeue_task_pb(struct rq *rq, struct task_struct *p, int flags)
 			}
 			rcu_read_unlock();
 		}
-	}
+		*/
 }
 
 static struct task_struct * pick_next_task_pb(struct rq *rq,
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 887afc18039bceb2ced70797c8f374ae045044a3..0dcfc39800898df9559709892f51eb3e83424950 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -926,6 +926,7 @@ static inline int is_plan_finished(struct pb_rq* pb)
  */
 static inline int is_plan_successful(struct pb_rq* pb)
 {
+	printk(KERN_WARNING "Plan successful? Exited processes: actual: %llu, expected: %llu\n", pb->num_exited_procs, plan_rt_state_num_exited_procs());
 	return is_plan_finished(pb) && pb->num_exited_procs == plan_rt_state_num_exited_procs();
 }