Pārlūkot izejas kodu

Refactoring scheduling context lists in order to exhibit true contexts priorities.

Terry Cojean 10 gadi atpakaļ
vecāks
revīzija
36b10bf351

+ 28 - 35
src/core/sched_ctx.c

@@ -40,10 +40,10 @@ static void _starpu_sched_ctx_set_master(struct _starpu_sched_ctx *sched_ctx, in
 
 static void _starpu_worker_gets_into_ctx(unsigned sched_ctx_id, struct _starpu_worker *worker)
 {
-	unsigned ret_sched_ctx = _starpu_sched_ctx_list_get_sched_ctx(worker->sched_ctx_list, sched_ctx_id);
+	unsigned ret_sched_ctx = _starpu_sched_ctx_elt_exists(worker->sched_ctx_list, sched_ctx_id);
 	/* the worker was planning to go away in another ctx but finally he changed his mind &
 	   he's staying */
-	if (ret_sched_ctx == STARPU_NMAX_SCHED_CTXS)
+	if (!ret_sched_ctx)
 	{
 		/* add context to worker */
 		_starpu_sched_ctx_list_add(&worker->sched_ctx_list, sched_ctx_id);
@@ -57,9 +57,9 @@ static void _starpu_worker_gets_into_ctx(unsigned sched_ctx_id, struct _starpu_w
 
 void _starpu_worker_gets_out_of_ctx(unsigned sched_ctx_id, struct _starpu_worker *worker)
 {
-	unsigned ret_sched_ctx = _starpu_sched_ctx_list_get_sched_ctx(worker->sched_ctx_list, sched_ctx_id);
+	unsigned ret_sched_ctx = _starpu_sched_ctx_elt_exists(worker->sched_ctx_list, sched_ctx_id);
 	/* remove context from worker */
-	if(ret_sched_ctx != STARPU_NMAX_SCHED_CTXS)
+	if(ret_sched_ctx)
 	{
 		/* don't remove scheduling data here, there might be tasks running and when post_exec
 		   executes scheduling data is not there any more, do it when deleting context, then
@@ -550,8 +550,6 @@ struct _starpu_sched_ctx* _starpu_create_sched_ctx(struct starpu_sched_policy *p
 		for(i = 0; i < nworkers; i++)
 		{
 			struct _starpu_worker *worker = _starpu_get_worker_struct(i);
-			worker->sched_ctx_list = (struct _starpu_sched_ctx_list*)malloc(sizeof(struct _starpu_sched_ctx_list));
-			_starpu_sched_ctx_list_init(worker->sched_ctx_list);
 			_starpu_sched_ctx_list_add(&worker->sched_ctx_list, sched_ctx->id);
 			worker->nsched_ctxs++;
 		}
@@ -1820,15 +1818,7 @@ void starpu_sched_ctx_set_priority(int *workers, int nworkers, unsigned sched_ct
 		{
 			worker = _starpu_get_worker_struct(workers[w]);
 			STARPU_PTHREAD_MUTEX_LOCK(&worker->sched_mutex);
-			struct _starpu_sched_ctx_list *l = NULL;
-			for (l = worker->sched_ctx_list; l; l = l->next)
-			{
-				if(l->sched_ctx == sched_ctx_id)
-				{
-					l->priority = priority;
-					break;
-				}
-			}
+			_starpu_sched_ctx_list_move(&worker->sched_ctx_list, sched_ctx_id, priority);
 			STARPU_PTHREAD_MUTEX_UNLOCK(&worker->sched_mutex);
 		}
 	}
@@ -1838,23 +1828,19 @@ void starpu_sched_ctx_set_priority(int *workers, int nworkers, unsigned sched_ct
 unsigned starpu_sched_ctx_get_priority(int workerid, unsigned sched_ctx_id)
 {
 	struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
-	struct _starpu_sched_ctx_list *l = NULL;
-	for (l = worker->sched_ctx_list; l; l = l->next)
-	{
-		if(l->sched_ctx == sched_ctx_id)
-		{
-			return l->priority;
-		}
-	}
-	return 1;
+	return _starpu_sched_ctx_elt_get_priority(worker->sched_ctx_list, sched_ctx_id);
 }
 
 unsigned _starpu_sched_ctx_last_worker_awake(struct _starpu_worker *worker)
 {
-	struct _starpu_sched_ctx_list *l = NULL;
-        for (l = worker->sched_ctx_list; l; l = l->next)
-        {
-		struct _starpu_sched_ctx *sched_ctx = _starpu_get_sched_ctx_struct(l->sched_ctx);
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
+
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
+	{
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		struct _starpu_sched_ctx *sched_ctx = _starpu_get_sched_ctx_struct(e->sched_ctx);
 
 		unsigned last_worker_awake = 1;
 		struct starpu_worker_collection *workers = sched_ctx->workers;
@@ -1941,24 +1927,31 @@ void starpu_sched_ctx_bind_current_thread_to_cpuid(unsigned cpuid STARPU_ATTRIBU
 unsigned starpu_sched_ctx_worker_is_master_for_child_ctx(int workerid, unsigned sched_ctx_id)
 {
 	struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
-	struct _starpu_sched_ctx_list *l = NULL;
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
 	struct _starpu_sched_ctx *sched_ctx = NULL;
-	for (l = worker->sched_ctx_list; l; l = l->next)
+
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
 	{
-		 sched_ctx = _starpu_get_sched_ctx_struct(l->sched_ctx);
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		sched_ctx = _starpu_get_sched_ctx_struct(e->sched_ctx);
 		if(sched_ctx-> main_master == workerid && sched_ctx->nesting_sched_ctx == sched_ctx_id)
 			return sched_ctx->id;
 	}
 	return STARPU_NMAX_SCHED_CTXS;
-
 }
 
 struct _starpu_sched_ctx *_starpu_sched_ctx_get_sched_ctx_for_worker_and_job(struct _starpu_worker *worker, struct _starpu_job *j)
 {
-	struct _starpu_sched_ctx_list *l = NULL;
-	for (l = worker->sched_ctx_list; l; l = l->next)
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
+
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
 	{
-		struct _starpu_sched_ctx *sched_ctx = _starpu_get_sched_ctx_struct(l->sched_ctx);
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		struct _starpu_sched_ctx *sched_ctx = _starpu_get_sched_ctx_struct(e->sched_ctx);
 		if (j->task->sched_ctx == sched_ctx->id)
 			return sched_ctx;
 	}

+ 376 - 35
src/core/sched_ctx_list.c

@@ -17,61 +17,298 @@
 #include <starpu.h>
 #include "sched_ctx_list.h"
 
-void _starpu_sched_ctx_list_init(struct _starpu_sched_ctx_list *list)
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_find(struct _starpu_sched_ctx_list *list,
+							 unsigned sched_ctx)
 {
-	list->next = NULL;
-	list->sched_ctx = STARPU_NMAX_SCHED_CTXS;
-	list->priority = 1;
+	struct _starpu_sched_ctx_list *l = NULL;
+	struct _starpu_sched_ctx_elt *e = NULL;
+	unsigned found = 0;
+
+	for (l = list; l && !found; l=l->next)
+	{
+		e=l->head; //Go in a circle once before stopping
+		do
+		{
+			if (e->sched_ctx == sched_ctx)
+			{
+				found = 1;
+				break;
+			}
+			e = e->next;
+		}
+		while (e != l->head);
+	}
+
+	return found ? e : NULL;
+}
+
+void _starpu_sched_ctx_elt_init(struct _starpu_sched_ctx_elt *elt, unsigned sched_ctx)
+{
+	elt->sched_ctx = sched_ctx;
+	elt->task_number = 0;
+	elt->parent = NULL;
+	elt->next = NULL;
+	elt->prev = NULL;
+}
+
+void _starpu_sched_ctx_elt_ensure_consistency(struct _starpu_sched_ctx_list *list,
+					      unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *elt = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	if (elt->task_number>0)
+		elt->task_number = 0;
+}
+
+/* Adds a new element after the head of the given list. */
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add_after(struct _starpu_sched_ctx_list *list,
+							      unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *head, *next;
+	struct _starpu_sched_ctx_elt *elt = (struct _starpu_sched_ctx_elt*)malloc(sizeof(struct _starpu_sched_ctx_elt));
+
+	_starpu_sched_ctx_elt_init(elt, sched_ctx);
+	elt->parent = list;
+
+	head = list->head;
+	if (head != NULL)
+	{
+		next = head->next;
+		head->next = elt;
+		elt->prev = head;
+
+		/** We know next != NULL since it is at least head **/
+		elt->next = next;
+		next->prev = elt;
+	}
+	else
+	{
+		elt->next = elt;
+		elt->prev = elt;
+		list->head = elt;
+	}
+
+	return elt;
 }
 
-void _starpu_sched_ctx_list_add(struct _starpu_sched_ctx_list **list, unsigned sched_ctx)
+/* Adds a new element before the head of the given list. */
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add_before(struct _starpu_sched_ctx_list *list,
+							       unsigned sched_ctx)
 {
-	if((*list)->sched_ctx == STARPU_NMAX_SCHED_CTXS)
-		(*list)->sched_ctx = sched_ctx;
+	struct _starpu_sched_ctx_elt *head, *prev;
+	struct _starpu_sched_ctx_elt *elt = (struct _starpu_sched_ctx_elt*)malloc(sizeof(struct _starpu_sched_ctx_elt));
+
+	_starpu_sched_ctx_elt_init(elt, sched_ctx);
+	elt->parent = list;
+
+	head = list->head;
+	if (head != NULL)
+	{
+		prev = head->prev;
+		head->prev = elt;
+		elt->next = head;
+
+		elt->prev = prev;
+		prev->next = elt;
+	}
 	else
 	{
-		struct _starpu_sched_ctx_list *l = (struct _starpu_sched_ctx_list*)malloc(sizeof(struct _starpu_sched_ctx_list));
-		l->sched_ctx = sched_ctx;
-		l->priority = 1;
-		l->next = *list;
-		*list = l;
+		elt->next = elt;
+		elt->prev = elt;
+		list->head = elt;
 	}
+	return elt;
+}
+
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add(struct _starpu_sched_ctx_list *list,
+							unsigned sched_ctx)
+{
+	return _starpu_sched_ctx_elt_add_after(list, sched_ctx);
+}
+
+/* Remove elt from list */
+void _starpu_sched_ctx_elt_remove(struct _starpu_sched_ctx_list *list,
+				 struct _starpu_sched_ctx_elt **elt)
+{
+	(*elt)->prev->next = (*elt)->next;
+	(*elt)->next->prev = (*elt)->prev;
+
+	if ((*elt)->next == (*elt)) //singleton
+		list->head = NULL;
+	else if ((*elt)->next != (*elt) && list->head == (*elt))
+		list->head = (*elt)->next;
+
+	free(*elt);
+	*elt = NULL;
+	return;
+}
+
+int _starpu_sched_ctx_elt_exists(struct _starpu_sched_ctx_list *list,
+				 unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *e = NULL;
+	e = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	return (e == NULL) ? 0 : 1;
+}
+
+int _starpu_sched_ctx_elt_get_priority(struct _starpu_sched_ctx_list *list,
+				       unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *e = NULL;
+	e = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	return (e == NULL) ? 0 : e->parent->priority;
 }
 
-void _starpu_sched_ctx_list_remove(struct _starpu_sched_ctx_list **list, unsigned sched_ctx)
+struct _starpu_sched_ctx_list* _starpu_sched_ctx_list_find(struct _starpu_sched_ctx_list *list,
+							   unsigned prio)
 {
 	struct _starpu_sched_ctx_list *l = NULL;
-	struct _starpu_sched_ctx_list *prev = NULL;
-	for (l = (*list); l; l = l->next)
+
+	for (l = list; l != NULL ; l=l->next)
+	{
+		if (l->priority == prio)
+			break;
+	}
+
+	return l;
+}
+
+/* Adds sched_ctx in a priority list. We consider that we don't add two times
+ * the same sched_ctx. Returns head of list. */
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_list_add_prio(struct _starpu_sched_ctx_list **list,
+							      unsigned prio, unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_list *parent_list = NULL, *prev = NULL, *last = NULL;
+	struct _starpu_sched_ctx_list *l = *list;
+
+	for (l = *list; l != NULL; l=l->next)
 	{
-		if(l->sched_ctx == sched_ctx)
+		if (l->priority <= prio)
 			break;
-		prev = l;
+		last = l;
+	}
+
+	if (l != NULL && l->priority == prio)
+	{
+		parent_list = l;
 	}
-	struct _starpu_sched_ctx_list *next = NULL;
-	if(l->next)
-		next = l->next;
-	free(l);
-	l = NULL;
-	
-	if(next)
+	else //l's priority is inferior or inexistant, add before
 	{
-		if(prev)
-			prev->next = next;
+		parent_list = (struct _starpu_sched_ctx_list*)malloc(sizeof(struct _starpu_sched_ctx_list));
+		parent_list->priority = prio;
+		parent_list->next = l;
+		parent_list->head = NULL;
+		parent_list->prev = NULL;
+		if (l != NULL)
+		{
+			prev = l->prev;
+			l->prev = parent_list;
+			if (prev != NULL)
+			{
+				prev->next = parent_list;
+				parent_list->prev = prev;
+			}
+			else
+			{
+				*list = parent_list;
+			}
+		}
 		else
-			*list = next;
+		{
+			if (last == NULL)
+			{
+				*list = parent_list;
+			}
+			else
+			{
+				last->next = parent_list;
+				parent_list->prev = last;
+			}
+		}
 	}
+
+	return _starpu_sched_ctx_elt_add(parent_list, sched_ctx);
 }
 
-unsigned _starpu_sched_ctx_list_get_sched_ctx(struct _starpu_sched_ctx_list *list, unsigned sched_ctx)
+int _starpu_sched_ctx_list_add(struct _starpu_sched_ctx_list **list,
+			       unsigned sched_ctx)
 {
-	struct _starpu_sched_ctx_list *l = NULL;
-	for (l = list; l; l = l->next)
+	return _starpu_sched_ctx_list_add_prio(list, 0, sched_ctx) != NULL ? 0 : 1;
+}
+
+void _starpu_sched_ctx_list_remove_elt(struct _starpu_sched_ctx_list **list,
+				      struct _starpu_sched_ctx_elt *rm)
+{
+	struct _starpu_sched_ctx_list *parent;
+
+	parent = rm->parent;
+
+	_starpu_sched_ctx_elt_remove(parent, &rm);
+
+	/* Automatically clean up useless prio list */
+	if (parent->head == NULL)
 	{
-		if(l->sched_ctx == sched_ctx)
-			return sched_ctx;
+		if (parent->prev == NULL)
+		{
+			*list = parent->next;
+			parent->next->prev = NULL;
+		}
+		else
+		{
+			parent->prev->next = parent->next;
+			parent->next->prev = parent->prev;
+		}
+		free(parent);
+		parent = NULL;
 	}
-	return STARPU_NMAX_SCHED_CTXS;
+	return;
+}
+
+/* Searches for a context and remove it */
+int _starpu_sched_ctx_list_remove(struct _starpu_sched_ctx_list **list,
+				  unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *rm;
+	rm = _starpu_sched_ctx_elt_find(*list, sched_ctx);
+
+	if (rm == NULL)
+		return -1;
+
+	_starpu_sched_ctx_list_remove_elt(list, rm);
+	return 0;
+}
+
+int _starpu_sched_ctx_list_move(struct _starpu_sched_ctx_list **list,
+				unsigned sched_ctx, unsigned prio_to)
+{
+	struct _starpu_sched_ctx_elt *elt = _starpu_sched_ctx_elt_find(*list, sched_ctx);
+	long task_number = 0;
+	if (elt == NULL)
+		return -1;
+
+	task_number = elt->task_number;
+	_starpu_sched_ctx_list_remove_elt(list, elt);
+	elt = _starpu_sched_ctx_list_add_prio(list, prio_to, sched_ctx);
+	elt->task_number = task_number;
+
+	return 0;
+}
+
+int _starpu_sched_ctx_list_exists(struct _starpu_sched_ctx_list *list,
+					   unsigned prio)
+{
+	struct _starpu_sched_ctx_list *l = NULL;
+	l = _starpu_sched_ctx_list_find(list, prio);
+	return ((l == NULL && list->priority == prio) || l != NULL) ? 1 : 0;
+}
+
+void _starpu_sched_ctx_list_remove_all(struct _starpu_sched_ctx_list *list)
+{
+	struct _starpu_sched_ctx_elt *next = NULL;
+
+	while (list->head != NULL)
+		_starpu_sched_ctx_elt_remove(list, &list->head);
+
+	free(list);
 }
 
 void _starpu_sched_ctx_list_delete(struct _starpu_sched_ctx_list **list)
@@ -79,10 +316,114 @@ void _starpu_sched_ctx_list_delete(struct _starpu_sched_ctx_list **list)
 	while(*list)
 	{
 		struct _starpu_sched_ctx_list *next = (*list)->next;
-		free(*list);
+		_starpu_sched_ctx_list_remove_all(*list);
 		*list = NULL;
 		if(next)
 			*list = next;
 	}
-		
+}
+
+int _starpu_sched_ctx_list_iterator_init(struct _starpu_sched_ctx_list *list,
+					 struct _starpu_sched_ctx_list_iterator *it)
+{
+	it->list_head = list;
+	it->cursor = NULL;
+
+	return 0;
+}
+
+int _starpu_sched_ctx_list_iterator_has_next(struct _starpu_sched_ctx_list_iterator *it)
+{
+	struct _starpu_sched_ctx_list *parent;
+	if (it->cursor == NULL)
+	{
+		if (it->list_head != NULL)
+			return it->list_head->head != NULL;
+		else
+			return 0;
+	}
+	else
+	{
+		parent = it->cursor->parent;
+		if (it->cursor->next == parent->head)
+			return parent->next != NULL;
+	}
+
+	return 1;
+}
+
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_list_iterator_get_next(struct _starpu_sched_ctx_list_iterator *it)
+{
+	struct _starpu_sched_ctx_elt *ret=NULL, *current;
+	struct _starpu_sched_ctx_list *parent;
+	current = it->cursor;
+
+	if (current != NULL)
+	{
+		parent = it->cursor->parent;
+		if (current->next == parent->head)
+		{
+			if (parent->next != NULL)
+			{
+				it->cursor = parent->next->head;
+				ret = parent->next->head;
+			} //else ret = NULL (end)
+		}
+		else
+		{
+			it->cursor = current->next;
+			ret = it->cursor;
+		}
+	}
+	else
+	{
+		it->cursor = it->list_head->head;
+		ret = it->cursor;
+	}
+
+	return ret;
+}
+
+int _starpu_sched_ctx_list_push_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *elt = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	if (elt == NULL)
+		return -1;
+
+	if (elt->task_number < 0)
+		elt->task_number = 1;
+	else
+		elt->task_number++;
+
+	return 0;
+}
+
+
+int _starpu_sched_ctx_list_pop_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *elt = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	if (elt == NULL)
+		return -1;
+
+	if (elt->task_number > 0)
+		elt->task_number--;
+
+	/** Balance circular lists **/
+	elt->parent->head = elt->next;
+
+	return 0;
+}
+
+int _starpu_sched_ctx_list_pop_all_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx)
+{
+	struct _starpu_sched_ctx_elt *elt = _starpu_sched_ctx_elt_find(list, sched_ctx);
+	if (elt == NULL)
+		return -1;
+
+	elt->task_number = 0;
+
+	/** Balance circular lists **/
+	elt->parent->head = elt->next;
+
+	return 0;
 }

+ 51 - 5
src/core/sched_ctx_list.h

@@ -17,17 +17,63 @@
 #ifndef __SCHED_CONTEXT_LIST_H__
 #define __SCHED_CONTEXT_LIST_H__
 
+/* Represents a non circular list of priorities and contains a list of sched context */
+struct _starpu_sched_ctx_elt;
 struct _starpu_sched_ctx_list
 {
+	struct _starpu_sched_ctx_list *prev;
 	struct _starpu_sched_ctx_list *next;
-	unsigned sched_ctx;
+	struct _starpu_sched_ctx_elt *head;
 	unsigned priority;
 };
 
-void _starpu_sched_ctx_list_init(struct _starpu_sched_ctx_list *list);
-void _starpu_sched_ctx_list_add(struct _starpu_sched_ctx_list **list, unsigned sched_ctx);
-void _starpu_sched_ctx_list_remove(struct _starpu_sched_ctx_list **list, unsigned sched_ctx);
-unsigned _starpu_sched_ctx_list_get_sched_ctx(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+/* Represents a circular list of sched context. */
+struct _starpu_sched_ctx_elt
+{
+	struct _starpu_sched_ctx_elt *prev;
+	struct _starpu_sched_ctx_elt *next;
+	struct _starpu_sched_ctx_list *parent;
+	unsigned sched_ctx;
+	long task_number;
+};
+
+struct _starpu_sched_ctx_list_iterator
+{
+	struct _starpu_sched_ctx_list *list_head;
+	struct _starpu_sched_ctx_elt *cursor;
+};
+
+/* Element (sched_ctx) level operations */
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_find(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+void _starpu_sched_ctx_elt_ensure_consistency(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+void _starpu_sched_ctx_elt_init(struct _starpu_sched_ctx_elt *elt, unsigned sched_ctx);
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add_after(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add_before(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_elt_add(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+void _starpu_sched_ctx_elt_remove(struct _starpu_sched_ctx_list *list, struct _starpu_sched_ctx_elt **elt);
+int _starpu_sched_ctx_elt_exists(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+int _starpu_sched_ctx_elt_get_priority(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+
+
+/* List (priority) level operations */
+struct _starpu_sched_ctx_list* _starpu_sched_ctx_list_find(struct _starpu_sched_ctx_list *list, unsigned prio);
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_list_add_prio(struct _starpu_sched_ctx_list **list, unsigned prio, unsigned sched_ctx);
+int _starpu_sched_ctx_list_add(struct _starpu_sched_ctx_list **list, unsigned sched_ctx);
+void _starpu_sched_ctx_list_remove_elt(struct _starpu_sched_ctx_list **list, struct _starpu_sched_ctx_elt *rm);
+int _starpu_sched_ctx_list_remove(struct _starpu_sched_ctx_list **list, unsigned sched_ctx);
+int _starpu_sched_ctx_list_move(struct _starpu_sched_ctx_list **list, unsigned sched_ctx, unsigned prio_to);
+int _starpu_sched_ctx_list_exists(struct _starpu_sched_ctx_list *list, unsigned prio);
+void _starpu_sched_ctx_list_remove_all(struct _starpu_sched_ctx_list *list);
 void _starpu_sched_ctx_list_delete(struct _starpu_sched_ctx_list **list);
 
+/* Task number management */
+int _starpu_sched_ctx_list_push_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+int _starpu_sched_ctx_list_pop_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+int _starpu_sched_ctx_list_pop_all_event(struct _starpu_sched_ctx_list *list, unsigned sched_ctx);
+
+/* Iterator operations */
+int _starpu_sched_ctx_list_iterator_init(struct _starpu_sched_ctx_list *list, struct _starpu_sched_ctx_list_iterator *it);
+int _starpu_sched_ctx_list_iterator_has_next(struct _starpu_sched_ctx_list_iterator *it);
+struct _starpu_sched_ctx_elt* _starpu_sched_ctx_list_iterator_get_next(struct _starpu_sched_ctx_list_iterator *it);
+
 #endif // __SCHED_CONTEXT_H__

+ 24 - 74
src/core/sched_policy.c

@@ -208,10 +208,14 @@ static void _starpu_push_task_on_specific_worker_notify_sched(struct starpu_task
 {
 	/* if we push a task on a specific worker, notify all the sched_ctxs the worker belongs to */
 	struct _starpu_sched_ctx *sched_ctx;
-	struct _starpu_sched_ctx_list *l = NULL;
-        for (l = worker->sched_ctx_list; l; l = l->next)
-        {
-		sched_ctx = _starpu_get_sched_ctx_struct(l->sched_ctx);
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
+
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
+	{
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		sched_ctx = _starpu_get_sched_ctx_struct(e->sched_ctx);
 		if (sched_ctx->sched_policy != NULL && sched_ctx->sched_policy->push_task_notify)
 		{
 			_STARPU_TRACE_WORKER_SCHEDULING_PUSH;
@@ -669,79 +673,18 @@ struct starpu_task *_starpu_create_conversion_task_for_arch(starpu_data_handle_t
 static
 struct _starpu_sched_ctx* _get_next_sched_ctx_to_pop_into(struct _starpu_worker *worker)
 {
-	struct _starpu_sched_ctx_list *l = NULL;
-	for (l = worker->sched_ctx_list; l; l = l->next)
-	{
-		if(worker->removed_from_ctx[l->sched_ctx] == 1)
-		{
-			return	_starpu_get_sched_ctx_struct(l->sched_ctx);
-		}
-	}
-
-	unsigned are_2_priorities = 0;
-	for (l = worker->sched_ctx_list; l; l = l->next)
-	{
-		if(l->priority != worker->pop_ctx_priority)
-		{
-			are_2_priorities = 1;
-			break;
-		}
-	}
-
-	if(!worker->reverse_phase[worker->pop_ctx_priority])
-	{
-		/* find a context in which the worker hasn't poped yet */
-		for (l = worker->sched_ctx_list; l; l = l->next)
-		{
-			if(l->priority == worker->pop_ctx_priority)
-			{
-				if(!worker->poped_in_ctx[l->sched_ctx])
-				{
-					worker->poped_in_ctx[l->sched_ctx] = !worker->poped_in_ctx[l->sched_ctx];
-					return	_starpu_get_sched_ctx_struct(l->sched_ctx);
-				}
-			}
-		}
-		worker->reverse_phase[worker->pop_ctx_priority] = !worker->reverse_phase[worker->pop_ctx_priority];
-		if(are_2_priorities)
-			worker->pop_ctx_priority = !worker->pop_ctx_priority;
-	}
-	are_2_priorities = 0;
-	if(worker->reverse_phase[worker->pop_ctx_priority])
-	{
-		/* if the context has already poped in every one start from the begining */
-		for (l = worker->sched_ctx_list; l; l = l->next)
-		{
-			if(l->priority == worker->pop_ctx_priority)
-			{
-				if(worker->poped_in_ctx[l->sched_ctx])
-				{
-					worker->poped_in_ctx[l->sched_ctx] = !worker->poped_in_ctx[l->sched_ctx];
-					return	_starpu_get_sched_ctx_struct(l->sched_ctx);
-				}
-			}
-		}
-		worker->reverse_phase[worker->pop_ctx_priority] = !worker->reverse_phase[worker->pop_ctx_priority];
-		if(are_2_priorities)
-			worker->pop_ctx_priority = !worker->pop_ctx_priority;
-	}
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
+	unsigned first_sched_ctx = _starpu_get_initial_sched_ctx()->id;
 
-	unsigned first_sched_ctx = STARPU_NMAX_SCHED_CTXS;
-	for (l = worker->sched_ctx_list; l; l = l->next)
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
 	{
-		if(l->priority == worker->pop_ctx_priority)
-		{
-			first_sched_ctx = l->sched_ctx;
-			break;
-		}
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		if (e->task_number > 0)
+			return _starpu_get_sched_ctx_struct(e->sched_ctx);
 	}
-
-//	if(worker->pop_ctx_priority == 0 && first_sched_ctx == STARPU_NMAX_SCHED_CTXS)
-	if(first_sched_ctx == STARPU_NMAX_SCHED_CTXS)
-		first_sched_ctx = worker->sched_ctx_list->sched_ctx;
-
-	worker->poped_in_ctx[first_sched_ctx] = !worker->poped_in_ctx[first_sched_ctx];
-	return _starpu_get_sched_ctx_struct(first_sched_ctx);
+	return _starpu_get_sched_ctx_struct(STARPU_GLOBAL_SCHED_CTX);
 }
 
 struct starpu_task *_starpu_pop_task(struct _starpu_worker *worker)
@@ -781,6 +724,13 @@ pick:
 			{
 				while(1)
 				{
+					/** Caution
+					 * If you use multiple contexts your scheduler *needs*
+					 * to update the variable task_number of the ctx list.
+					 * This is done using functions :
+					 *   _starpu_sched_ctx_list_pop_event(...)
+					 *   _starpu_sched_ctx_list_push_event(...)
+					**/
 					sched_ctx = _get_next_sched_ctx_to_pop_into(worker);
 
 					if(worker->removed_from_ctx[sched_ctx->id] == 1 && worker->shares_tasks_lists[sched_ctx->id] == 1)

+ 7 - 3
src/core/workers.c

@@ -2178,10 +2178,14 @@ unsigned starpu_worker_get_sched_ctx_list(int workerid, unsigned **sched_ctxs)
 	unsigned nsched_ctxs = _starpu_worker_get_nsched_ctxs(workerid);
 	*sched_ctxs = (unsigned*)malloc(nsched_ctxs*sizeof(unsigned));
 	struct _starpu_worker *worker = _starpu_get_worker_struct(workerid);
-	struct _starpu_sched_ctx_list *l = NULL;
-	for (l = worker->sched_ctx_list; l; l = l->next)
+	struct _starpu_sched_ctx_elt *e = NULL;
+	struct _starpu_sched_ctx_list_iterator list_it;
+
+	_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+	while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
 	{
-		(*sched_ctxs)[s++] = l->sched_ctx;
+		e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+		(*sched_ctxs)[s++] = e->sched_ctx;
 	}
 	return nsched_ctxs;
 }

+ 7 - 3
src/drivers/driver_common/driver_common.c

@@ -342,10 +342,14 @@ struct starpu_task *_starpu_get_worker_task(struct _starpu_worker *worker, int w
 	while(needed)
 	{
 		struct _starpu_sched_ctx *sched_ctx = NULL;
-		struct _starpu_sched_ctx_list *l = NULL;
-		for (l = worker->sched_ctx_list; l; l = l->next)
+		struct _starpu_sched_ctx_elt *e = NULL;
+		struct _starpu_sched_ctx_list_iterator list_it;
+
+		_starpu_sched_ctx_list_iterator_init(worker->sched_ctx_list, &list_it);
+		while (_starpu_sched_ctx_list_iterator_has_next(&list_it))
 		{
-			sched_ctx = _starpu_get_sched_ctx_struct(l->sched_ctx);
+			e = _starpu_sched_ctx_list_iterator_get_next(&list_it);
+			sched_ctx = _starpu_get_sched_ctx_struct(e->sched_ctx);
 			if(sched_ctx && sched_ctx->id > 0 && sched_ctx->id < STARPU_NMAX_SCHED_CTXS)
 			{
 				STARPU_PTHREAD_MUTEX_LOCK(&sched_ctx->parallel_sect_mutex[workerid]);

+ 20 - 2
src/sched_policies/deque_modeling_policy_data_aware.c

@@ -23,6 +23,7 @@
 #include <starpu_scheduler.h>
 
 #include <common/fxt.h>
+#include <core/workers.h>
 #include <core/task.h>
 
 #include <sched_policies/fifo_queues.h>
@@ -185,6 +186,7 @@ static struct starpu_task *dmda_pop_ready_task(unsigned sched_ctx_id)
 	struct _starpu_dmda_data *dt = (struct _starpu_dmda_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 
 	struct starpu_task *task;
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	int workerid = starpu_worker_get_id();
 	struct _starpu_fifo_taskq *fifo = dt->queue_array[workerid];
@@ -212,6 +214,9 @@ static struct starpu_task *dmda_pop_ready_task(unsigned sched_ctx_id)
 			
 		}
 
+		ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+		_starpu_sched_ctx_list_pop_event(ctx_list, sched_ctx_id);
+
 #ifdef STARPU_VERBOSE
 		if (task->cl)
 		{
@@ -232,6 +237,7 @@ static struct starpu_task *dmda_pop_task(unsigned sched_ctx_id)
 	struct _starpu_dmda_data *dt = (struct _starpu_dmda_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 
 	struct starpu_task *task;
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	int workerid = starpu_worker_get_id();
 	struct _starpu_fifo_taskq *fifo = dt->queue_array[workerid];
@@ -261,7 +267,8 @@ static struct starpu_task *dmda_pop_task(unsigned sched_ctx_id)
 
 		}
 
-
+		ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+		_starpu_sched_ctx_list_pop_event(ctx_list, sched_ctx_id);
 		  
 #ifdef STARPU_VERBOSE
 		if (task->cl)
@@ -281,6 +288,7 @@ static struct starpu_task *dmda_pop_task(unsigned sched_ctx_id)
 static struct starpu_task *dmda_pop_every_task(unsigned sched_ctx_id)
 {
 	struct _starpu_dmda_data *dt = (struct _starpu_dmda_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	struct starpu_task *new_list;
 
@@ -293,6 +301,10 @@ static struct starpu_task *dmda_pop_every_task(unsigned sched_ctx_id)
 	STARPU_PTHREAD_MUTEX_LOCK(sched_mutex);
 	new_list = _starpu_fifo_pop_every_task(fifo, workerid);
 	STARPU_PTHREAD_MUTEX_UNLOCK(sched_mutex);
+
+	ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+	_starpu_sched_ctx_list_pop_all_event(ctx_list, sched_ctx_id);
+
 	while (new_list)
 	{
 		double transfer_model = new_list->predicted_transfer;
@@ -323,9 +335,11 @@ static int push_task_on_best_worker(struct starpu_task *task, int best_workerid,
 				    int prio, unsigned sched_ctx_id)
 {
 	struct _starpu_dmda_data *dt = (struct _starpu_dmda_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
-	/* make sure someone coule execute that task ! */
+	/* make sure someone could execute that task ! */
 	STARPU_ASSERT(best_workerid != -1);
 	unsigned child_sched_ctx = starpu_sched_ctx_worker_is_master_for_child_ctx(best_workerid, sched_ctx_id);
+	struct _starpu_sched_ctx_list *ctx_list;
+
         if(child_sched_ctx != STARPU_NMAX_SCHED_CTXS)
         {
                 starpu_sched_ctx_move_task_to_ctx(task, child_sched_ctx);
@@ -447,6 +461,9 @@ static int push_task_on_best_worker(struct starpu_task *task, int best_workerid,
 		STARPU_PTHREAD_MUTEX_UNLOCK(sched_mutex);
 	}
 
+	ctx_list = _starpu_get_worker_struct(best_workerid)->sched_ctx_list;
+	_starpu_sched_ctx_list_push_event(ctx_list, sched_ctx_id);
+
 	return ret;
 }
 
@@ -1087,6 +1104,7 @@ static void dmda_pre_exec_hook(struct starpu_task *task)
 
 static void dmda_push_task_notify(struct starpu_task *task, int workerid, int perf_workerid, unsigned sched_ctx_id)
 {
+	struct _starpu_sched_ctx_list *ctx_list;
 	struct _starpu_dmda_data *dt = (struct _starpu_dmda_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 	struct _starpu_fifo_taskq *fifo = dt->queue_array[workerid];
 	/* Compute the expected penality */

+ 51 - 1
src/sched_policies/eager_central_policy.c

@@ -25,6 +25,7 @@
 #include <sched_policies/fifo_queues.h>
 #include <common/thread.h>
 #include <starpu_bitmap.h>
+#include <core/workers.h>
 
 struct _starpu_eager_center_policy_data
 {
@@ -77,7 +78,8 @@ static int push_task_eager_policy(struct starpu_task *task)
 {
 	unsigned sched_ctx_id = task->sched_ctx;
 	struct _starpu_eager_center_policy_data *data = (struct _starpu_eager_center_policy_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
-		
+	struct _starpu_sched_ctx_list *ctx_list;
+
 	STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
 	starpu_task_list_push_back(&data->fifo->taskq,task);
 	data->fifo->ntasks++;
@@ -116,6 +118,14 @@ static int push_task_eager_policy(struct starpu_task *task)
 #else
 			dowake[worker] = 1;
 #endif
+
+			/* If we have only one sched_ctx we don't need to use these. */
+			/* We will use the global one anyway. */
+			if (_starpu_get_nsched_ctxs() > 1)
+			{
+				ctx_list = _starpu_get_worker_struct(worker)->sched_ctx_list;
+				_starpu_sched_ctx_list_push_event(ctx_list, sched_ctx_id);
+			}
 		}
 	}
 	/* Let the task free */
@@ -141,10 +151,29 @@ static struct starpu_task *pop_every_task_eager_policy(unsigned sched_ctx_id)
 {
 	struct _starpu_eager_center_policy_data *data = (struct _starpu_eager_center_policy_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 	int workerid = starpu_worker_get_id();
+	struct _starpu_sched_ctx_list *ctx_list;
 	
 	STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
 	struct starpu_task* task = _starpu_fifo_pop_every_task(data->fifo, workerid);
 	STARPU_PTHREAD_MUTEX_UNLOCK(&data->policy_mutex);
+
+	if (_starpu_get_nsched_ctxs() > 1) {
+		unsigned worker = 0;
+		struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
+		struct starpu_sched_ctx_iterator it;
+		workers->init_iterator_for_parallel_tasks(workers, &it, task);
+		while(workers->has_next(workers, &it))
+		{
+			worker = workers->get_next(workers, &it);
+
+			unsigned nimpl;
+			if (starpu_worker_can_execute_task_first_impl(workerid, task, &nimpl)) {
+				ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+				_starpu_sched_ctx_list_pop_all_event(ctx_list, sched_ctx_id);
+			}
+		}
+	}
+
 	return task;
 }
 
@@ -154,6 +183,7 @@ static struct starpu_task *pop_task_eager_policy(unsigned sched_ctx_id)
 	struct _starpu_eager_center_policy_data *data = (struct _starpu_eager_center_policy_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 
 	struct starpu_task *task = NULL;
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	/* block until some event happens */
 	/* Here helgrind would shout that this is unprotected, this is just an
@@ -179,6 +209,26 @@ static struct starpu_task *pop_task_eager_policy(unsigned sched_ctx_id)
 
 	if(task)
 	{
+		/* If we have only one sched_ctx we don't need to use these. */
+		/* We will use the global one anyway. */
+		if (_starpu_get_nsched_ctxs() > 1)
+		{
+			unsigned worker = 0;
+			struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
+			struct starpu_sched_ctx_iterator it;
+			workers->init_iterator_for_parallel_tasks(workers, &it, task);
+			while(workers->has_next(workers, &it))
+			{
+				worker = workers->get_next(workers, &it);
+
+				unsigned nimpl;
+				if (starpu_worker_can_execute_task_first_impl(workerid, task, &nimpl)) {
+					ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+					_starpu_sched_ctx_list_pop_event(ctx_list, sched_ctx_id);
+				}
+			}
+		}
+
 		unsigned child_sched_ctx = starpu_sched_ctx_worker_is_master_for_child_ctx(workerid, sched_ctx_id);
 		if(child_sched_ctx != STARPU_NMAX_SCHED_CTXS)
 		{

+ 29 - 1
src/sched_policies/eager_central_priority_policy.c

@@ -26,6 +26,7 @@
 #include <starpu_bitmap.h>
 
 #include <common/fxt.h>
+#include <core/workers.h>
 
 #define DEFAULT_MIN_LEVEL	(-5)
 #define DEFAULT_MAX_LEVEL	(+5)
@@ -124,6 +125,7 @@ static int _starpu_priority_push_task(struct starpu_task *task)
 	unsigned sched_ctx_id = task->sched_ctx;
 	struct _starpu_eager_central_prio_data *data = (struct _starpu_eager_central_prio_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 	struct _starpu_priority_taskq *taskq = data->taskq;
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	STARPU_PTHREAD_MUTEX_LOCK(&data->policy_mutex);
 	unsigned priolevel = task->priority - STARPU_MIN_PRIO;
@@ -163,6 +165,11 @@ static int _starpu_priority_push_task(struct starpu_task *task)
 #else
 			dowake[worker] = 1;
 #endif
+			if (_starpu_get_nsched_ctxs() > 1)
+			{
+				ctx_list = _starpu_get_worker_struct(worker)->sched_ctx_list;
+				_starpu_sched_ctx_list_push_event(ctx_list, sched_ctx_id);
+			}
 		}
 	}
 	/* Let the task free */
@@ -193,6 +200,7 @@ static struct starpu_task *_starpu_priority_pop_task(unsigned sched_ctx_id)
 	struct _starpu_eager_central_prio_data *data = (struct _starpu_eager_central_prio_data*)starpu_sched_ctx_get_policy_data(sched_ctx_id);
 
 	struct _starpu_priority_taskq *taskq = data->taskq;
+	struct _starpu_sched_ctx_list *ctx_list;
 
 	/* block until some event happens */
 	/* Here helgrind would shout that this is unprotected, this is just an
@@ -285,7 +293,27 @@ static struct starpu_task *_starpu_priority_pop_task(unsigned sched_ctx_id)
 
 	if(chosen_task)
 	{
-		unsigned child_sched_ctx = starpu_sched_ctx_worker_is_master_for_child_ctx(workerid, sched_ctx_id);
+		/* If we have only one sched_ctx we don't need to use these. */
+		/* We will use the global one anyway. */
+		if (_starpu_get_nsched_ctxs() > 1)
+		{
+			unsigned worker = 0;
+			struct starpu_worker_collection *workers = starpu_sched_ctx_get_worker_collection(sched_ctx_id);
+			struct starpu_sched_ctx_iterator it;
+			workers->init_iterator_for_parallel_tasks(workers, &it, chosen_task);
+			while(workers->has_next(workers, &it))
+			{
+				worker = workers->get_next(workers, &it);
+
+				unsigned nimpl;
+				if (starpu_worker_can_execute_task_first_impl(workerid, chosen_task, &nimpl)) {
+					ctx_list = _starpu_get_worker_struct(workerid)->sched_ctx_list;
+					_starpu_sched_ctx_list_pop_event(ctx_list, sched_ctx_id);
+				}
+			}
+		}
+
+                unsigned child_sched_ctx = starpu_sched_ctx_worker_is_master_for_child_ctx(workerid, sched_ctx_id);
 		if(child_sched_ctx != STARPU_NMAX_SCHED_CTXS)
 		{
 			starpu_sched_ctx_move_task_to_ctx(chosen_task, child_sched_ctx);

+ 4 - 0
tests/Makefile.am

@@ -233,6 +233,7 @@ noinst_PROGRAMS =				\
 	microbenchs/redundant_buffer		\
 	microbenchs/local_pingpong		\
 	microbenchs/matrix_as_vector		\
+	sched_ctx/sched_ctx_list		\
 	openmp/init_exit_01			\
 	openmp/init_exit_02			\
 	openmp/environment			\
@@ -498,6 +499,9 @@ main_subgraph_repeat_regenerate_tag_SOURCES +=		\
 	main/increment.cu
 endif
 
+sched_ctx_sched_ctx_list_SOURCES =	\
+	sched_ctx/sched_ctx_list.c
+
 openmp_init_exit_01_SOURCES = 	\
 	openmp/init_exit_01.c
 

+ 195 - 0
tests/sched_ctx/sched_ctx_list.c

@@ -0,0 +1,195 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2015  INRIA
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <config.h>
+#include <starpu.h>
+#include "../helper.h"
+#include "../../src/core/sched_ctx_list.h"
+
+int main(int argc, char **argv)
+{
+	struct _starpu_sched_ctx_list *ctx_list = NULL, *found_list;
+	struct _starpu_sched_ctx_elt *elt;
+	struct _starpu_sched_ctx_list_iterator it;
+	int ret=1, global=1;
+
+	/* Check prio list addition */
+	ret &= (_starpu_sched_ctx_list_add_prio(&ctx_list, 50, 0) != NULL);
+	ret &= (ctx_list->priority == 50);
+	ret &= (_starpu_sched_ctx_list_add_prio(&ctx_list, 999, 2) != NULL);
+	ret &= (ctx_list->priority == 999);
+	ret &= (ctx_list->next->priority == 50);
+	ret &= !_starpu_sched_ctx_list_add(&ctx_list, 1);
+	ret &= (ctx_list->next->next->priority == 0);
+
+	/* Check elements added */
+	ret &= (ctx_list->head->sched_ctx == 2);
+	ret &= (ctx_list->next->head->sched_ctx == 0);
+	ret &= (ctx_list->next->next->head->sched_ctx == 1);
+
+	/* Check singleton status */
+	ret &= (ctx_list->next->head->prev->sched_ctx == 0);
+	ret &= (ctx_list->next->head->next->sched_ctx == 0);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_add");
+
+	/* Check addition to existing list */
+	ret = 1;
+	elt = _starpu_sched_ctx_elt_add(ctx_list->next, 3);
+	ret &= (ctx_list->next->head->next->sched_ctx == 3);
+	ret &= (ctx_list->next->head->prev->sched_ctx == 3);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_elt_add");
+
+	/* Find element */
+	ret = 1;
+	elt = _starpu_sched_ctx_elt_find(ctx_list, 3);
+	ret &= (elt != NULL && elt->sched_ctx == 3);
+	elt = _starpu_sched_ctx_elt_find(ctx_list, 5);
+	ret &= (elt == NULL);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_elt_find");
+
+	/* Find list */
+	ret = 1;
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 0);
+	ret &= (found_list->priority == 0);
+	ret &= (found_list->prev->priority == 50);
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 999);
+	ret &= (found_list->priority==999);
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 42);
+	ret &= (found_list == NULL);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_find");
+
+	/* List exists */
+	ret = 1;
+	ret &= _starpu_sched_ctx_list_exists(ctx_list, 999);
+	ret &= _starpu_sched_ctx_list_exists(ctx_list, 50);
+	ret &= _starpu_sched_ctx_list_exists(ctx_list, 0);
+	ret &= !_starpu_sched_ctx_list_exists(ctx_list, 42);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_exists");
+
+	/* Iterator */
+	ret = 1;
+	ret &= !_starpu_sched_ctx_list_iterator_init(ctx_list, &it);
+	ret &= _starpu_sched_ctx_list_iterator_has_next(&it);
+	elt = _starpu_sched_ctx_list_iterator_get_next(&it);
+	ret &= (elt->sched_ctx == 2);
+	ret &= _starpu_sched_ctx_list_iterator_has_next(&it);
+	elt = _starpu_sched_ctx_list_iterator_get_next(&it);
+	ret &= (elt->sched_ctx == 0);
+	ret &= _starpu_sched_ctx_list_iterator_has_next(&it);
+	elt = _starpu_sched_ctx_list_iterator_get_next(&it);
+	ret &= (elt->sched_ctx == 3);
+	ret &= _starpu_sched_ctx_list_iterator_has_next(&it);
+	elt = _starpu_sched_ctx_list_iterator_get_next(&it);
+	ret &= (elt->sched_ctx == 1);
+	ret &= !_starpu_sched_ctx_list_iterator_has_next(&it);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_iterator");
+
+	/* Add element before head */
+	ret = 1;
+	elt = _starpu_sched_ctx_elt_add_before(ctx_list->next, 4);
+	ret &= (ctx_list->next->head->prev->sched_ctx == 4);
+	ret &= (ctx_list->next->head->next->next->sched_ctx == 4);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_elt_add_before");
+
+	/* Let's move it */
+	ret = 1;
+	ret &= !_starpu_sched_ctx_list_move(&ctx_list, 4, 1002);
+	ret &= (ctx_list->priority == 1002);
+	ret &= (ctx_list->head->sched_ctx == 4);
+	ret &= (ctx_list->head->next->sched_ctx == 4);
+	ret &= (ctx_list->next->next->head->prev->sched_ctx != 4);
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_move");
+
+	/* Let's remove it */
+	ret = 1;
+	elt = _starpu_sched_ctx_elt_find(ctx_list, 4);
+	_starpu_sched_ctx_list_remove_elt(&ctx_list, elt);
+	//ret &= (elt == NULL);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 4) == NULL);
+	ret &= (ctx_list->next->head->next->sched_ctx == 3);
+	ret &= (ctx_list->next->head->prev->sched_ctx == 3);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_elt_remove");
+
+	/* Let's remove head of that same ctx */
+	ret = 1;
+	ret &= !_starpu_sched_ctx_list_remove(&ctx_list, 0);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 0) == NULL);
+	ret &= (ctx_list->next->head->sched_ctx == 3);
+	ret &= (ctx_list->next->head->next->sched_ctx == 3);
+	ret &= (ctx_list->next->head->prev->sched_ctx == 3);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_remove");
+
+	/* Remove the last one of this list, we get an empty ctx */
+	ret = 1;
+	ret &= !_starpu_sched_ctx_list_remove(&ctx_list, 3);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 3) == NULL);
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 50);
+	ret &= (found_list == NULL && ctx_list->priority != 50);
+	ret &= (ctx_list->next->priority == 0);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_remove");
+
+	/* Add an element to a new prio then remove it to ensure prio list is cleaned correctly */
+	ret = 1;
+	ret &= (_starpu_sched_ctx_list_add_prio(&ctx_list, 100000, 75) != NULL);
+	ret &= (ctx_list->priority == 100000);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 75) != NULL);
+	ret &= (ctx_list->head->sched_ctx == 75);
+	ret &= !_starpu_sched_ctx_list_remove(&ctx_list, 75);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 75) == NULL);
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 100000);
+	ret &= (found_list == NULL && ctx_list->priority != 100000);
+	ret &= (ctx_list->priority == 999);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_remove");
+
+	/* Delete this list, the function is internal only so we need to modify the list pointers too */
+	ret = 1;
+	found_list = ctx_list->next;
+	_starpu_sched_ctx_list_remove_all(ctx_list);
+	ctx_list = found_list;
+	found_list = _starpu_sched_ctx_list_find(ctx_list, 999);
+	ret &= (found_list == NULL && ctx_list->priority != 999);
+	ret &= (_starpu_sched_ctx_elt_find(ctx_list, 2) == NULL);
+	ret &= (ctx_list->priority == 0);
+	ret &= (ctx_list->head->sched_ctx == 1); //as before
+	ret &= (ctx_list->head->next->sched_ctx == 1);
+	ret &= (ctx_list->head->prev->sched_ctx == 1);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_remove_all");
+
+	/* Let's add some things again then clean everything */
+	ret = 1;
+	ret &= (_starpu_sched_ctx_list_add_prio(&ctx_list, 1000, 42) != NULL);
+	ret &= (_starpu_sched_ctx_list_add_prio(&ctx_list, 1000, 43) != NULL);
+	_starpu_sched_ctx_list_delete(&ctx_list);
+	ret &= (ctx_list == NULL);
+	global &= ret;
+	STARPU_CHECK_RETURN_VALUE_IS(ret, 1, "_starpu_sched_ctx_list_delete");
+
+	STARPU_CHECK_RETURN_VALUE_IS(global, 1, "_starpu_sched_ctx_(list|elt) global status");
+
+	return 0;
+}