00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2005--2007 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CUFLOW_PROMISE_H 00019 #define CUFLOW_PROMISE_H 00020 00021 #include <cuflow/fwd.h> 00022 #include <cuflow/gworkq.h> 00023 00024 00025 CU_BEGIN_DECLARATIONS 00026 /*!\defgroup cuflow_promise_h cuflow/promise.h: Delayed Fulfillment of Computations 00027 * @{\ingroup cuflow_oldsmp_mod 00028 * 00029 * \deprecated Similar functionality is provided by \ref cuflow_sched_h 00030 * "cuflow/sched.h" using \ref cuflow_cdisj_h "cuflow/cdisj.h" for guarding the 00031 * result of a computation. 00032 * 00033 * A promise is a handle which contains a task to be performed at a later 00034 * time, and a state of the computation. The computation may schedule 00035 * further work on the \ref cuflow_gworkq_h "global work queue", in which 00036 * case other threads requesting the computation can take part in the 00037 * workload. 00038 * 00039 * The state is initially \ref cuflow_promise_state_latent. When the 00040 * promise is requested, the state is updated to 00041 * \ref cuflow_promise_state_initiated before the main task is called. 00042 * Subsequent states may be written to the promise by the computation 00043 * to represent various degrees of fulfillment. In the simplest case 00044 * there is one more states, meaning that the promise is fulfilled. When 00045 * working on recursive structures, a four-state promise may be needed, 00046 * where first additional state means that a data-structure is allocated 00047 * so that the pointer is available for linking, and the last state means 00048 * that the data structure is constructed and thus fully usable. */ 00049 00050 /*!The state of a promise. */ 00051 typedef int cuflow_promise_state_t; 00052 typedef cu_clop(cuflow_promise_initiator_t, void, cuflow_promise_t); 00053 00054 /*!The promise has not yet been requested. */ 00055 #define cuflow_promise_state_latent 0 00056 00057 /*!The promise has been requested and the main task have been started. */ 00058 #define cuflow_promise_state_initiated 1 00059 00060 /*!When this state or a higher state is written to the promise by the client 00061 * implementation, which may be either the initiator or a job submitted by it, 00062 * the reference to the work queue will be unlinked from the promise, so that 00063 * it can be freed by the collector when it becomes empty (though it will 00064 * usually already be empty). */ 00065 #define cuflow_promise_state_fulfilled 0x8000 00066 00067 struct cuflow_promise 00068 { 00069 AO_t state; 00070 union { 00071 cuflow_promise_initiator_t initiator; 00072 cuflow_gflexq_t gflexq; 00073 void *value; 00074 } u0; 00075 }; 00076 00077 /*!Construct \a promise which will be fulfilled by calling \a initiator 00078 * and performing any work which it passes onto the work queue of \a 00079 * promise. */ 00080 void cuflow_promise_init(cuflow_promise_t promise, 00081 cu_clop(initiator, void, cuflow_promise_t)); 00082 00083 void cuflowP_promise_process(cuflow_promise_t promise, 00084 cuflow_promise_state_t state); 00085 00086 /*!Return the current state of the promise. */ 00087 CU_SINLINE cuflow_promise_state_t 00088 cuflow_promise_state(cuflow_promise_t promise) 00089 { 00090 return AO_load_acquire_read(&promise->state); 00091 } 00092 00093 /*!Set the state of \a promise to \a state. 00094 * \pre \a state is greater than the current state. */ 00095 void cuflow_promise_set_state(cuflow_promise_t promise, 00096 cuflow_promise_state_t state); 00097 00098 /*!Set the state of \a promise to \a cuflow_promise_state_fulfilled and store 00099 * \a ptr with its value. Data stored before this state is reached must be 00100 * stored elsewhere, like after the promise struct, cf \ref cuflow_promise_mem, 00101 * or by embedding the promise struct in a larger struct. In that can you 00102 * may pass \a ptr to point to it, or <tt>\a ptr = NULL</tt>. */ 00103 void cuflow_promise_set_fulfilled(cuflow_promise_t promise, void *ptr); 00104 00105 /*!Increment the state of \a promise and return the post value. */ 00106 cuflow_promise_state_t 00107 cuflow_promise_increment_state(cuflow_promise_t promise); 00108 00109 /*!Fulfill \a promise upto \a state by calling the initiator if not already 00110 * done, then call the work queue and possibly wait for other threads which 00111 * process the promise, until the state is reached. */ 00112 CU_SINLINE void 00113 cuflow_promise_process(cuflow_promise_t promise, cuflow_promise_state_t state) 00114 { 00115 if (AO_load_acquire_read(&promise->state) < state) 00116 cuflowP_promise_process(promise, state); 00117 } 00118 00119 /*!Fulfill \a promise upto \a cuflow_promise_state_fulfilled, and return 00120 * the value that it set with \a cuflow_promise_set_fulfilled. Some 00121 * promises may wish to store the value elsewhere, like after the promise 00122 * struct. */ 00123 CU_SINLINE void * 00124 cuflow_promise_fulfill(cuflow_promise_t promise) 00125 { 00126 cuflow_promise_process(promise, cuflow_promise_state_fulfilled); 00127 return promise->u0.value; 00128 } 00129 00130 /*!Returns a pointer to the end of the \a promise struct itself, which may 00131 * be used by client, if allocated, to store working state or final data. */ 00132 CU_SINLINE void * 00133 cuflow_promise_mem(cuflow_promise_t promise) 00134 { 00135 return promise + 1; 00136 } 00137 00138 /*!@}*/ 00139 CU_END_DECLARATIONS 00140 00141 #endif