HClib  0.3
Documentation for Habanero-C Library API
 All Data Structures Functions Typedefs Enumerations Groups
ddf.c
1 /* Copyright (c) 2013, Rice University
2 
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are
5 met:
6 
7 1. Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9 2. Redistributions in binary form must reproduce the above
10  copyright notice, this list of conditions and the following
11  disclaimer in the documentation and/or other materials provided
12  with the distribution.
13 3. Neither the name of Rice University
14  nor the names of its contributors may be used to endorse or
15  promote products derived from this software without specific
16  prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30  */
31 
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 
36 // Control debug statements
37 #define DEBUG_DDF 0
38 
39 #include "runtime-hclib.h"
40 #include "rt-ddf.h"
41 #include "runtime-support.h"
42 
43 #define EMPTY_DATUM_ERROR_MSG "can not put sentinel value for \"uninitialized\" as a value into DDF"
44 
45 // For 'headDDTWaitList' when a DDF has been satisfied
46 #define DDF_SATISFIED NULL
47 
48 // Default value of a DDF datum
49 #define UNINITIALIZED_DDF_DATA_PTR NULL
50 
51 // For waiting frontier (last element of the list)
52 #define UNINITIALIZED_DDF_WAITLIST_PTR ((struct ddt_st *) -1)
53 
54 // struct ddf_st is the opaque we expose.
55 // We define a typedef in this unit for convenience
56 typedef struct ddf_st {
57  void * datum;
58  struct ddt_st * headDDTWaitList;
59 } ddf_t;
60 
61 
65 void ddt_init(ddt_t * ddt, ddf_t ** ddf_list) {
66  ddt->waitingFrontier = ddf_list;
67  ddt->nextDDTWaitingOnSameDDF = NULL;
68 }
69 
74  ddf_t * ddf = (ddf_t *) malloc(sizeof(ddf_t));
75  ddf->datum = NULL;
76  ddf->headDDTWaitList = UNINITIALIZED_DDF_WAITLIST_PTR;
77  return ddf;
78 }
79 
83 ddf_t ** ddf_create_n(size_t nb_ddfs, int null_terminated) {
84  ddf_t ** ddfs = (ddf_t **) malloc((sizeof(ddf_t*) * nb_ddfs));
85  int i = 0;
86  int lg = (null_terminated) ? nb_ddfs-1 : nb_ddfs;
87  while(i < lg) {
88  ddfs[i] = ddf_create();
89  i++;
90  }
91  if (null_terminated) {
92  ddfs[lg] = NULL;
93  }
94  return ddfs;
95 }
96 
100 void ddf_free(ddf_t * ddf) {
101  free(ddf);
102 }
103 
104 static int register_if_ddf_not_ready(ddt_t * ddt, ddf_t * ddf) {
105  int registered = 0;
106  ddt_t * headDDTWaitList = (ddt_t *) ddf->headDDTWaitList;
107  while (headDDTWaitList != DDF_SATISFIED && !registered) {
108  /* headDDTWaitList can not be DDF_SATISFIED in here */
109  ddt->nextDDTWaitingOnSameDDF = headDDTWaitList;
110 
111  // Try to add the ddt to the ddf's list of ddts waiting.
112  registered = __sync_bool_compare_and_swap(&(ddf->headDDTWaitList),
113  headDDTWaitList, ddt);
114 
115  /* may have failed because either some other task tried to be the head or a put occurred. */
116  if (!registered) {
117  headDDTWaitList = (ddt_t *) ddf->headDDTWaitList;
118  /* if waitListOfDDF was set to DDF_SATISFIED, the loop condition will handle that
119  * if another task was added, now try to add in front of that
120  */
121  }
122  }
123  if (DEBUG_DDF && registered) {
124  printf("ddf: %p registered %p as headDDT of ddf %p\n", ddt, ddf->headDDTWaitList, ddf);
125  }
126  return registered;
127 }
128 
133 int iterate_ddt_frontier(ddt_t * ddt) {
134  ddf_t ** currentDDF = ddt->waitingFrontier;
135 
136  if (DEBUG_DDF) {
137  printf("ddf: Trying to iterate ddt %p, frontier ddf is %p \n", ddt, currentDDF);
138  }
139  // Try and register on ddf until one is not ready.
140  while ((*currentDDF) && !register_if_ddf_not_ready(ddt, *currentDDF)) {
141  ++currentDDF;
142  }
143  // Here we either:
144  // - Have hit a ddf not ready (i.e. no 'put' on this one yet)
145  // - iterated over the whole list (i.e. all 'put' must have happened)
146  if (DEBUG_DDF) { printf("ddf: iterate result %d\n", (*currentDDF == NULL)); }
147  ddt->waitingFrontier = currentDDF;
148  return (*currentDDF == NULL);
149 }
150 
155 void * ddf_get(ddf_t * ddf) {
156  if (ddf->datum == UNINITIALIZED_DDF_DATA_PTR) {
157  return NULL;
158  }
159  return (void *) ddf->datum;
160 }
161 
167 void ddf_put(ddf_t * ddf, void * datum) {
168  assert(datum != UNINITIALIZED_DDF_DATA_PTR && EMPTY_DATUM_ERROR_MSG);
169  assert(ddf != NULL && "error: can't DDF is a pointer to NULL");
170  //TODO Limitation: not enough to guarantee single assignment
171  if (DEBUG_DDF) { printf("ddf: put datum %p\n", ddf->datum); }
172  assert(ddf->datum == NULL && "error: violated single assignment property for DDFs");
173 
174  volatile ddt_t * headDDTWaitList = NULL;
175  ddf->datum = datum;
176  headDDTWaitList = ddf->headDDTWaitList;
177  if (DEBUG_DDF) { printf("ddf: Retrieve ddf %p head's ddt %p\n", ddf, headDDTWaitList); }
178  // Try to cas the wait list to prevent new DDTs from registering on this ddf.
179  // When cas successed, new DDTs see the DDF has been satisfied and proceed.
180  while (!__sync_bool_compare_and_swap(&(ddf->headDDTWaitList),
181  (struct ddt_st *) headDDTWaitList, DDF_SATISFIED )) {
182  headDDTWaitList = ddf->headDDTWaitList;
183  }
184  if (DEBUG_DDF) {
185  printf("ddf: Put successful on ddf %p set head's ddf to %p\n", ddf, ddf->headDDTWaitList);
186  }
187  // Now iterate over the list of DDTs, and try to advance their frontier.
188  ddt_t * currDDT = (ddt_t *) headDDTWaitList;
189  while (currDDT != UNINITIALIZED_DDF_WAITLIST_PTR) {
190  if (DEBUG_DDF) { printf("ddf: Trying to iterate frontier of ddt %p\n", currDDT); }
191  if (iterate_ddt_frontier(currDDT)) {
192  // DDT eligible to scheduling
193  async_task_t * async_task = rt_ddt_to_async_task(currDDT);
194  if (DEBUG_DDF) { printf("ddf: async_task %p\n", async_task); }
195  try_schedule_async(async_task);
196  }
197  currDDT = currDDT->nextDDTWaitingOnSameDDF;
198  }
199 }