1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
|
/*
* task.h -- part of FractalNow
*
* Copyright (c) 2011 Marc Pegon <pe.marc@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* \file task.h
* \brief Header file related to tasks.
* \author Marc Pegon
*/
#ifndef __TASKS_H__
#define __TASKS_H__
#include "thread.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Task;
/**
* \struct CompositeTaskArguments
* \brief Arguments structure for composite tasks thread routine.
*
* This is for internal use only.
*/
/**
* \typedef CompositeTaskArguments
* \brief Convenient typedef for struct CompositeTaskArguments.
*/
typedef struct CompositeTaskArguments {
struct Task *thisTask;
/*!< Pointer to the composite task being run.*/
} CompositeTaskArguments;
/**
* \struct Task
* \brief Structure to control tasks execution by threads.
*
* Typically, executing a task by threads is done in 3
* steps:
* -create task
* -launch task
* -wait for it to finish
*
* Through the task structure, it is possible to cancel
* a task, to pause it and then resume it, as well to wait for
* it to finish (get task result).
*
* Some examples of use :\n
* 1) Launch task and wait for it to finish :\n
* task = CreateTask(message, threads, nbThreadsNeeded,
* args, s_elem, routine, freeArgs);\n
* LaunchTask(task, threads);\n
* res = GetTaskResult(task);
*
* 2) Launch threads, cancel task after some time, wait for it to
* finish.\n
* task = CreateTask(message, threads, nbThreadsNeeded, args,
s_elem, routine, freeArgs);\n
* sleep(2);\n
* CancelTask(task); // (send cancelation request)\n
* res = GetTaskResult(task); // wait for it to finish\n
*
* It is up to the thread routine to take into account cancellation
* request and finish earlier, via the CancelRequested function.
*
* Remark: note that although the functions described here deal
* with threads, they are not thread-safe (like all the functions
* in this library btw), i.e. the functions here should not be run
* concurrently by different threads (although, if necessary, it
* would be quite easy to make them thread-safe, by adding a mutex
* for each function).
*/
/**
* \typedef Task
* \brief Convenient typedef for struct Task.
*/
typedef struct Task {
int isComposite;
/*!< 1 if task consists of a sequence of subtasks.*/
int launchPrepared;
/*!< 1 if launch has been prepared (for composite tasks).*/
int hasBeenLaunched;
/*!< 1 if created task has already been launched.*/
int done;
/*!< 1 if task has already finished and threads have been joined.*/
int returnValue;
/*!< Task return value (0 if finished normally, 1 if canceled).*/
int cancel;
/*!< Integer used for cancellation request.*/
pthread_spinlock_t cancelMutex;
/*!< Mutex for cancel variable.*/
int pause;
/*!< Integer used to pause task.*/
pthread_spinlock_t pauseMutex;
/*!< Mutex for pause variable.*/
/* For composite tasks: */
CompositeTaskArguments compositeTaskArguments;
/*!< Arguments for composite tasks.*/
uint_fast32_t nbSubTasks;
/*!< Number of subtasks (for composite task only).*/
struct Task **subTasks;
/*!< Subtasks (for composite task only).*/
uint_fast32_t compositeTaskNbReady;
/*!< Number of threads ready to launch a new subtask.*/
int stopLaunchingSubTasks;
/*!< Instructs composite task routine to stop launching subtasks (cancel requested).*/
pthread_cond_t compositeTaskAllThreadsReadyCond;
/*!< Signaled when all threads are ready to launch new subtask.*/
/* For non-composite tasks: */
struct ThreadArgHeader *threadArgsHeaders;
/*!< Internal part of thread arguments (cancel and progress handling).*/
struct Threads *threads;
/*!< Pointer to threads to use for task.*/
uint_fast32_t nbThreadsNeeded;
/*!< Number of threads actually needed for task.*/
void *initialArgs;
/*!< Copy of initial arguments (as passed to CreateTask).*/
void *args;
/*!< Array of args passed to thread routine (with headers).*/
size_t s_elem;
/*!< Size of each argument.*/
void *(*threadsRoutine)(void *);
/*!< Task routine (to be executed by each thread).*/
void (*freeArg)(void *);
/*!< Routine to free each arg.*/
char *message;
/*!< Task message to print at launch and when it finishes.*/
} Task;
/**
* \fn Task *DoNothingTask()
* \brief Returns a newly-allocated task that does nothing.
*
* Convenient for working on empty image for example.
*
* \return Do-nothing task.
*/
Task *DoNothingTask();
/**
* \fn Task *CreateTask(const char message[], uint_fast32_t nbThreadsNeeded, const void *args, size_t s_elem, void *(*routine)(void *), void (*freeArg)(void *))
* \brief Create task.
*
* args is copied.\n
* Note that arguments passed to the thread routine are not
* exactly those passed to the function :\n
* A ThreadArgHeader structure is added at the beginning of the
* argument, which should be used to handle cancellation requests and
* task progress.\n
* The remaining bytes are the 'real' argument.\n
* Free argument routine will be called for each argument when task
* is free'd (can be NULL if arguments contain no dynamically
* allocated data).
*
* \param message Task message to print at launch and when task finishes.
* \param nbThreadsNeeded Number of threads needed to launch task.
* \param args Pointer to array of arguments for threads routines.
* \param s_elem Size of one argument (in bytes).
* \param routine Threads routine.
* \param freeArg Routine to free each argument.
* \return Corresponding newly-allocated task.
*/
Task *CreateTask(const char message[], uint_fast32_t nbThreadsNeeded,
const void *args, size_t s_elem, void *(*routine)(void *),
void (*freeArg)(void *));
/**
* \fn Task *CreateCompositeTask(const char message[], uint_fast32_t nbSubTasks, Task *subTasks[])
* \brief Create composite task.
*
* Create a "virtual" task made of subtasks.\n
* Array of subtasks pointers will be copied (though not the tasks
* themselves).
*
* \param message Task message to print at launch and when task finishes.
* \param nbSubTasks Number of subtasks.
* \param subTasks Array of subtasks.
* \return Newly-allocated composite task.
*/
Task *CreateCompositeTask(const char message[], uint_fast32_t nbSubTasks, Task *subTasks[]);
/**
* \fn void LaunchTask(Task *task, Threads *threads)
* \brief Launch task.
*
* Exit with error if task has already been launched.\n
* Exit with error if number of threads needed for task
* is greater than number of threads.\n
* Threads should *not* be busy when calling this
* function (unspecified behaviour otherwise).
*
* \param task Task to be launched.
* \param threads Threads that will execute task.
*/
void LaunchTask(Task *task, Threads *threads);
/**
* \fn int ExecuteTaskBlocking(Task *task, Threads *threads)
* \brief Execute task (blocking).
*
* Launch task and wait for it finish before returning.
* \see LaunchTask
*
* \param task Task to be executed.
* \param threads Threads that will be used to execute task.
* \return Task return value (0 if finished normally, 1 if cancelled);
*/
int ExecuteTaskBlocking(Task *task, Threads *threads);
/**
* \fn int TaskIsFinished(Task *task)
* \brief Test if task is finished.
*
* A not-yet-launched task is considered not finished
* (0 returned).
*
* \param task Task to be tested.
* \return 1 if task is finished, 0 otherwise.
*/
int TaskIsFinished(Task *task);
/**
* \fn int GetTaskResult(Task *task)
* \brief Get task result.
*
* Exit with error if task has not been launched yet.\n
* If task has already been launched but is not finished,\n
* the function will block until it is finished.\n
* Hence make sure that task is not paused when calling\n
* this function (deadlock).
*
* \param task Task to finish.
* \return 0 if task finished normally, 1 if it was cancelled, -1 if it has not yet been launched.
*/
int GetTaskResult(Task *task);
/**
* \fn void CancelTask(Task *task)
* \brief Send cancelation request to task.
*
* Note that the function returns immediately after
* sending the cancelation request.
* You can call GetTaskResult after CancelTask to
* make sure it is effectively canceled.\n
* It is up to the task routine to take the request into
* account, via the CancelRequested function.\n
* \see CancelRequested
* Does nothing if task has already finished.\n
*
* \param task Task to send cancellation request to.
*/
void CancelTask(Task *task);
/** \fn void PauseTask(Task *task)
* \brief Pause task.
*
* Function returns after task has effectively been paused
* (unlike CancelAction which only sends a request).\n
* You can use this function to access data being modified
* by task safely.\n
* Does nothing if task is already paused, has not been launched
* yet, or has already finished.
*
* \brief task Task to be paused.
*/
void PauseTask(Task *task);
/** \fn void ResumeTask(Task *task)
* \brief Resume task.
*
* Resume task after it has been paused.\n
* Does nothing if task has not been launched yet,
* or has already finished.
*/
void ResumeTask(Task *task);
/**
* \fn double GetTaskProgress(const Task *task)
* \brief Get task progress.
*
* Progress is a value between 0 (just begun) and 1 (done).\n
* Returns 0 if task has not been launched yet.
*
* \param task Task subject to request.
* \return Task progress.
*/
double GetTaskProgress(const Task *task);
/**
* \fn void FreeTask(Task *task)
* \brief Free task data.
*
* If task has been launched, it *must* have already finished:
* exit with error otherwise.\n
* Note: a prior call to GetTaskResult will ensure that task
* has finished, since it waits for action to finish.
*
* \param task Task to be free'd.
*/
void FreeTask(Task *task);
#ifdef __cplusplus
}
#endif
#endif
|