task_bundle.c 6.1 KB

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