task_bundle.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2011, 2013 Université de Bordeaux
  4. * Copyright (C) 2011 Télécom-SudParis
  5. * Copyright (C) 2012 INRIA
  6. *
  7. * StarPU is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * StarPU is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  17. */
  18. #include <starpu.h>
  19. #include <starpu_task_bundle.h>
  20. #include <core/task_bundle.h>
  21. #include <starpu_scheduler.h>
  22. #include <common/config.h>
  23. #include <common/utils.h>
  24. #include <common/list.h>
  25. #include <common/thread.h>
  26. /* Initialize a task bundle */
  27. void starpu_task_bundle_create(starpu_task_bundle_t *bundle)
  28. {
  29. _STARPU_MALLOC(*bundle, sizeof(struct _starpu_task_bundle));
  30. STARPU_PTHREAD_MUTEX_INIT(&(*bundle)->mutex, NULL);
  31. /* Of course at the beginning a bundle is open,
  32. * user can insert and remove tasks from it */
  33. (*bundle)->closed = 0;
  34. /* Start with an empty list */
  35. (*bundle)->list = NULL;
  36. }
  37. int starpu_task_bundle_insert(starpu_task_bundle_t bundle, struct starpu_task *task)
  38. {
  39. STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
  40. if (bundle->closed)
  41. {
  42. /* The bundle is closed, we cannot add task anymore */
  43. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  44. return -EPERM;
  45. }
  46. if (task->status != STARPU_TASK_INVALID)
  47. {
  48. /* The task has already been submitted, it's too late to put it
  49. * into a bundle now. */
  50. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  51. return -EINVAL;
  52. }
  53. /* Insert a task at the end of the bundle */
  54. struct _starpu_task_bundle_entry *entry;
  55. _STARPU_MALLOC(entry, sizeof(struct _starpu_task_bundle_entry));
  56. entry->task = task;
  57. entry->next = NULL;
  58. if (!bundle->list)
  59. {
  60. bundle->list = entry;
  61. }
  62. else
  63. {
  64. struct _starpu_task_bundle_entry *item;
  65. item = bundle->list;
  66. while (item->next)
  67. item = item->next;
  68. item->next = entry;
  69. }
  70. /* Mark the task as belonging the bundle */
  71. task->bundle = bundle;
  72. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  73. return 0;
  74. }
  75. int starpu_task_bundle_remove(starpu_task_bundle_t bundle, struct starpu_task *task)
  76. {
  77. struct _starpu_task_bundle_entry *item;
  78. STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
  79. item = bundle->list;
  80. /* List is empty, there is no way the task
  81. * belong to it */
  82. if (!item)
  83. {
  84. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  85. return -ENOENT;
  86. }
  87. STARPU_ASSERT_MSG(task->bundle == bundle, "Task %p was not in bundle %p, but in bundle %p", task, bundle, task->bundle);
  88. task->bundle = NULL;
  89. if (item->task == task)
  90. {
  91. /* Remove the first element */
  92. bundle->list = item->next;
  93. free(item);
  94. /* If the list is now empty, deinitialize the bundle */
  95. if (bundle->closed && bundle->list == NULL)
  96. {
  97. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  98. _starpu_task_bundle_destroy(bundle);
  99. return 0;
  100. }
  101. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  102. return 0;
  103. }
  104. /* Go through the list until we find the right task,
  105. * then we delete it */
  106. while (item->next)
  107. {
  108. struct _starpu_task_bundle_entry *next;
  109. next = item->next;
  110. if (next->task == task)
  111. {
  112. /* Remove the next element */
  113. item->next = next->next;
  114. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  115. free(next);
  116. return 0;
  117. }
  118. item = next;
  119. }
  120. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  121. /* We could not find the task in the bundle */
  122. return -ENOENT;
  123. }
  124. /* Close a bundle. No task can be added to a closed bundle. Tasks can still be
  125. * removed from a closed bundle. A closed bundle automatically gets
  126. * deinitialized when it becomes empty. A closed bundle cannot be reopened. */
  127. void starpu_task_bundle_close(starpu_task_bundle_t bundle)
  128. {
  129. STARPU_PTHREAD_MUTEX_LOCK(&bundle->mutex);
  130. /* If the bundle is already empty, we deinitialize it now as the
  131. * user closed it and thus don't intend to insert new tasks in it. */
  132. if (bundle->list == NULL)
  133. {
  134. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  135. _starpu_task_bundle_destroy(bundle);
  136. return;
  137. }
  138. /* Mark the bundle as closed */
  139. bundle->closed = 1;
  140. STARPU_PTHREAD_MUTEX_UNLOCK(&bundle->mutex);
  141. }
  142. void _starpu_task_bundle_destroy(starpu_task_bundle_t bundle)
  143. {
  144. /* Remove all entries from the bundle (which is likely to be empty) */
  145. while (bundle->list)
  146. {
  147. struct _starpu_task_bundle_entry *entry = bundle->list;
  148. bundle->list = bundle->list->next;
  149. free(entry);
  150. }
  151. STARPU_PTHREAD_MUTEX_DESTROY(&bundle->mutex);
  152. free(bundle);
  153. }
  154. void _insertion_handle_sorted(struct _starpu_handle_list **listp, starpu_data_handle_t handle, enum starpu_data_access_mode mode)
  155. {
  156. STARPU_ASSERT(listp);
  157. struct _starpu_handle_list *list = *listp;
  158. /* If the list is empty or the handle's address the smallest among the
  159. * list, we insert it as first element */
  160. if (!list || list->handle > handle)
  161. {
  162. struct _starpu_handle_list *link;
  163. _STARPU_MALLOC(link, sizeof(struct _starpu_handle_list));
  164. link->handle = handle;
  165. link->mode = mode;
  166. link->next = list;
  167. *listp = link;
  168. return;
  169. }
  170. struct _starpu_handle_list *prev = list;
  171. /* Look for the same handle if already present in the list.
  172. * Else place it right before the smallest following handle */
  173. while (list && (handle >= list->handle))
  174. {
  175. prev = list;
  176. list = list->next;
  177. }
  178. if (prev->handle == handle)
  179. {
  180. /* The handle is already in the list, the merge both the access modes */
  181. prev->mode = (enum starpu_data_access_mode) ((int) prev->mode | (int) mode);
  182. }
  183. else
  184. {
  185. /* The handle was not in the list, we insert it after 'prev', thus right before
  186. * 'list' which is the smallest following handle */
  187. struct _starpu_handle_list *link;
  188. _STARPU_MALLOC(link, sizeof(struct _starpu_handle_list));
  189. link->handle = handle;
  190. link->mode = mode;
  191. link->next = prev->next;
  192. prev->next = link;
  193. }
  194. }