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 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
/*
-- This file is free software, which comes along with SmartEiffel. This
-- software 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. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You are allowed to redistribute it and sell it, alone or as a part of
-- another product.
-- Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
-- Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
-- http://SmartEiffel.loria.fr
--
*/
/*
This file (SmartEiffel/sys/runtime/scoop_thread.h) is automatically included
when separate objects are created.
*/
/**
* @name Thread processors
*
* Only the POSIX semantics is supported as for now (February 4th 2003). It
* will have to be expanded in the future, to support at least Windows
* threads.
*
* @author Cyril Adrian
*/
//@{
#include <pthread.h>
#include <stdarg.h>
#define SE_SCOOP_THREAD 1
#define SE_SCOOP_THREAD_TYPE 0
typedef struct se_message se_message_t;
typedef struct se_queue_wait se_queue_wait_t;
typedef struct se_thread_mutex se_thread_mutex_t;
typedef struct se_thread se_thread_t;
typedef struct se_thread_once se_thread_once_t;
typedef struct se_subsystem_thread se_subsystem_thread_t;
typedef struct se_origin_thread se_origin_thread_t;
/**
* The message queue of a processor
*/
struct se_message {
/// Next message in queue, #NULL# if none.
se_message_t* next;
/// The client processor
pthread_t caller;
/// The message function ({\em agent})
void (* agent)(void*,int,void*);
/// Some data passed to the guard and the message
void* data;
/// Length of the data
int length;
/// The result location. #NULL# when the message is a command.
void* result;
/// Is the result available: non zero when true
volatile int result_available;
/// The subsystem originator of a query. #NULL# when no query was started.
se_origin_t* origin;
#ifndef SE_BOOST
/// Used to detect bad memory management
int is_free;
#endif
se_subsystem_thread_t* client;
};
/**
* The subsystem monitor queue
*/
struct se_queue_wait {
/// Next entry in queue
se_queue_wait_t* next;
/// The waiting processor
se_subsystem_t* subsystem;
};
/**
* A mutex used to correctly define P() and V() with POSIX-compliant code.
*/
struct se_thread_mutex {
/// A counter
int count;
/// The true mutex. POSIX requires the same thread to do the lock() and
/// unlock()
pthread_mutex_t mutex;
/// A condition to synchronize the threads
pthread_cond_t cond;
};
/**
* An Eiffel once object shell: an access key, and the Eiffel object
*/
struct se_thread_once {
// The key to access the object
char* key;
// The Eiffel "once" object
void* once;
// Next key
se_thread_once_t* next;
};
/**
* Extension of se_origin
*/
struct se_origin_thread {
/// The "parent" structure
se_origin_t super;
/// A mutex
pthread_mutex_t modify;
};
/**
* Extension of se_subsystem
*/
struct se_subsystem_thread {
/// The "parent" structure
se_subsystem_t super;
/// The processor
pthread_t thread;
/** Lock Manager */
//@{
/**
* This counter is used when the subsystem is a client of a call. It counts
* how many objects still have to be awaited for before we can dream of any
* locking.
*/
int lock_count;
/**
* This counter is used to count the number of providers that are ready to
* serve the current subsystem. The subsystem will enter the critical
* section when ready_lock_count == lock_count.
*/
int ready_lock_count;
/**
* A locker to protect lock_count and ready_lock_count
*/
pthread_mutex_t modify_lock_count;
/**
* This queue is used when the subsystem is a supplier. It holds all the
* clients which wait to lock this subsystem. If #NULL#, no one waits for
* this subsystem.
*/
int lock_waiters_count;
se_queue_wait_t* lock_waiters_head;
se_queue_wait_t* lock_waiters_tail;
/**
* The current locker
*/
se_subsystem_t* locker;
/**
* A mutex to protect the lock_waiters modification
*/
pthread_mutex_t modify_locker;
pthread_mutex_t lock_signal_mutex;
pthread_cond_t lock_signal_cond;
/**
* Origin of a query
*/
se_origin_t* origin;
pthread_mutex_t modify_origin;
//@}
/** Message queue handling */
//@{
/**
* A mutex used when adding or removing elements in the message queue. The
* counter is used to count the number of messages in the queue. The
* condition is used to signal the presence of a new message in the queue.
*/
se_thread_mutex_t message_queue_mutex;
/**
* The head of the message queue; #NULL# when empty.
*/
se_message_t* queue_head;
/**
* The tail of the message queue
*/
se_message_t* queue_tail;
//@}
/** Global subsystem maintenance */
//@{
/**
* Non-zero when the processor must terminate
*/
int stop_processor;
/**
* The number of objects in this subsystem.
*/
int count;
/**
* A mutex used when reading/writing the number of objects in this
* subsystem.
*/
pthread_mutex_t modify_count;
#ifndef SE_BOOST
/**
* A mutex used when modifying the Dump Stack.
*/
pthread_mutex_t modify_ds;
/**
* One Dump Stack per thread! Declared #void*# because se_dump_stack is
* declared later on...
*/
void* dst;
/**
* Non-0 when printing the Dump Stack
*/
int print_dst;
#endif
//@}
/**
* Thread-once handling. There is no need for any lock since only the
* current processor can access those objects.
*/
//@{
/** The head of the once objects */
se_thread_once_t* once_head;
/** The once object last accessed */
se_thread_once_t* once_memory;
//@}
};
//@}
/**
* This function is called by SmartEiffel if some thread-type processors are
* created. (That is, always...)
*/
extern void init_scoop_thread();
/**
* Returns the current running processor.
*/
se_subsystem_t* se_current_subsystem_thread();
extern int se_thread_count;
extern pthread_mutex_t se_thread_mutex;
#define state(thread_subsystem) (thread_subsystem)->super.state
#define state_wait_request(thread_subsystem) do { state(thread_subsystem) = SCOOP_PROCESSOR_WAITING_REQUEST; } while(0)
#define state_run(thread_subsystem) do { state(thread_subsystem) = SCOOP_PROCESSOR_RUNNING; } while(0)
#define state_block(thread_subsystem) do { state(thread_subsystem) = SCOOP_PROCESSOR_BLOCKED; } while(0)
#define state_wait_result(thread_subsystem) do { state(thread_subsystem) = SCOOP_PROCESSOR_WAITING_RESULT; } while(0)
#ifndef SE_BOOST
/**
* Debug file, set to the value of the SCOOP_DEBUG environment variable.
*/
extern FILE* scoop_debug_file;
extern pthread_mutex_t scoop_debug_file_mutex;
void se_scoop_debug(char* format, ...) {
va_list args;
va_start(args, format);
if (scoop_debug_file != NULL) {
scoop_check_call(pthread_mutex_lock(&scoop_debug_file_mutex));
{
vfprintf(scoop_debug_file, format, args);
fflush(scoop_debug_file);
}
scoop_check_call(pthread_mutex_unlock(&scoop_debug_file_mutex));
}
va_end(args);
}
#define se_scoop_trace(trace) do { \
se_scoop_debug("%s:%d\t%s\n", __FILE__, __LINE__, trace); \
if (scoop_debug_file != NULL) { \
scoop_check_call(pthread_mutex_lock(&scoop_debug_file_mutex)); \
{ \
fprintf(scoop_debug_file, "%s:%d\t%s\n", __FILE__, __LINE__, trace); \
fflush(scoop_debug_file); \
} \
scoop_check_call(pthread_mutex_unlock(&scoop_debug_file_mutex)); \
} \
else { \
fprintf(SE_ERR, "%s:%d\t%s\n", __FILE__, __LINE__, trace); \
} \
} while(0)
#else
void se_scoop_debug(char* dummy, ...) {} // I hope C compilers optimize this away!
#define se_scoop_trace(trace) fprintf(SE_ERR, "%s:%d\t%s\n", __FILE__, __LINE__, trace)
#endif
|