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_GFLEXQ_H 00019 #define CUFLOW_GFLEXQ_H 00020 00021 #include <cuflow/fwd.h> 00022 #include <cuflow/gworkq.h> 00023 #include <cucon/list.h> 00024 00025 CU_BEGIN_DECLARATIONS 00026 /*!\defgroup cuflow_gflexq_h cuflow/gflexq.h Global Work Queue with Flexible Priority 00027 * @{\ingroup cuflow_oldsmp_mod 00028 * 00029 * \deprecated Use \ref cuflow_sched_h "cuflow/sched.h" provides a simpler and 00030 * more efficient alternative. 00031 * 00032 * This module provides a data structure \ref cuflow_gflexq, a work 00033 * queue linked to the global work queue at a modifiable priority. 00034 * These queues are hierachical, each queue can have several subqueues, 00035 * and several queues can share the same subqueue. The hierachical 00036 * structure is used to bump up the priority of all dependent calculations 00037 * when a high priority job requires the calculation represented by a 00038 * queue (and its subqueues). 00039 * 00040 * The main purpose of all this is to implement \ref cuflow_promise_h 00041 * "promises", which present a high-level interface for work-sharing 00042 * between threads and guard the result so that it is not accessed 00043 * before it is finished. */ 00044 00045 /*!A work queue linked to the global work queue at a flexible priority. */ 00046 struct cuflow_gflexq 00047 { 00048 cu_inherit (cuflow_workq); 00049 AO_t priority; 00050 cuflow_gflexq_t next, prev; /* gworkq links */ 00051 struct cucon_list subqueue_list; 00052 }; 00053 00054 typedef struct cuflow_gflexq_entry *cuflow_gflexq_entry_t; 00055 /*!The state saved by \ref cuflow_gflexq_enter. */ 00056 struct cuflow_gflexq_entry 00057 { 00058 cuflow_gflexq_t gflexq; 00059 cucon_listnode_t subqueue_it; 00060 }; 00061 00062 /*!Construct \a flexq with initial priority \a initpri. */ 00063 void cuflow_gflexq_init(cuflow_gflexq_t flexq, cuflow_priority_t initpri); 00064 00065 /*!Return an empty queue with initial priority \a initpri. */ 00066 cuflow_gflexq_t cuflow_gflexq_new(cuflow_priority_t initpri); 00067 00068 /*!The priority at which work on \a flexq will be run. */ 00069 CU_SINLINE cuflow_priority_t 00070 cuflow_gflexq_priority(cuflow_gflexq_t flexq) 00071 { return AO_load_acquire_read(&flexq->priority); } 00072 00073 /* Set the priority for work queued on \a flexq. This can be called at 00074 * any time, and will cause already scheduled work on \a flexq to be run 00075 * at the new priority. Consider \ref cuflow_gflexq_raise_priority 00076 * if you are using hierachical queues. */ 00077 /*void cuflow_gflexq_set_priority(cuflow_gflexq_t flexq, 00078 cuflow_priority_t new_priority);*/ 00079 00080 /*!Raise the priority of \a flexq and all subqueues to at least \a 00081 * min_priority. This function will never lower the priority of any 00082 * queues. This semantics is acertains that when the same work is 00083 * requested by functions running at different priorities, it will be 00084 * scheduled at the highest priority amoung the requestors. */ 00085 void cuflow_gflexq_raise_priority(cuflow_gflexq_t flexq, 00086 cuflow_priority_t min_priority); 00087 00088 void cuflow_gflexq_raise_priority_glck(cuflow_gflexq_t flexq, 00089 cuflow_priority_t min_priority); 00090 00091 /*!Schedule \a fn on \a flexq. If the queue is empty, this will cause 00092 * \a flexq to be activated by putting it on the global queue at the 00093 * predefined priority. */ 00094 void cuflow_gflexq_sched(cuflow_gflexq_t flexq, cuflow_workq_fn_t fn); 00095 00096 void cuflow_gflexq_sched_glck(cuflow_gflexq_t flexq, cuflow_workq_fn_t fn); 00097 00098 /*!Set \a flexq as the work queue for subsequent \ref cuflow_gworkq_sched 00099 * operations, and save the current state to \a entry for restoration 00100 * with \ref cuflow_gflexq_leave. Several context may enter the same 00101 * queue, which implies that one queue can have several parent queues. 00102 * When the priority of a parent queue is raised, it affects all subqueues 00103 * recursively. */ 00104 void cuflow_gflexq_enter(cuflow_gflexq_t flexq, cuflow_gflexq_entry_t entry); 00105 00106 /*!Same as \ref cuflow_gflexq_enter, but assuming gworkq-lock is held. */ 00107 void cuflow_gflexq_enter_glck(cuflow_gflexq_t flexq, 00108 cuflow_gflexq_entry_t entry); 00109 00110 /*!Drop the current work queue and restore the state saved in \a entry, 00111 * as obtain from the matching \ref cuflow_gflexq_enter. This operation 00112 * also unlinks the subqueue, so that it will no longer be affected by 00113 * changes to the priority of its no-longer parent. */ 00114 void cuflow_gflexq_leave(cuflow_gflexq_entry_t entry); 00115 00116 /*!Same as \ref cuflow_gflexq_leave, but assuming gworkq-lock is held. */ 00117 void cuflow_gflexq_leave_glck(cuflow_gflexq_entry_t entry); 00118 00119 /*!@}*/ 00120 CU_END_DECLARATIONS 00121 00122 #endif