| 283 | Maintenant, vous n'allez pas avoir à écrire le code des barrières mais voue allez devoir répondre à quelques questions |
| 284 | {{{#!c |
| 285 | #define MAGIC_BARRIER 0xDEADBABA |
| 286 | |
| 287 | struct thread_barrier_s { |
| 288 | int magic; ///< magic number to check the validity of the barrier |
| 289 | spinlock_t lock; ///< protection against parallel modifications |
| 290 | size_t expected; ///< number of expected threads |
| 291 | size_t waiting; ///< number of threads waiting |
| 292 | list_t wait; ///< list element to chain threads that are wainting for the mutex |
| 293 | }; |
| 294 | |
| 295 | int thread_barrier_init (thread_barrier_t * barrier, size_t count) |
| 296 | { |
| 297 | thread_barrier_t b = *barrier; // get the barrier pointer |
| 298 | |
| 299 | if (count == 0) return EINVAL; // count must be > 0 |
| 300 | |
| 301 | if (b == NULL) { // if we need a new barrier |
| 302 | b = kmalloc (sizeof (struct thread_barrier_s)); // allocates a new barrier |
| 303 | if (b == NULL) return ENOMEM; // test if there is enough memory |
| 304 | b->magic = MAGIC_BARRIER; // tell it is a BARRIER |
| 305 | b->lock = 0; // free the lock |
| 306 | b->expected = count; // init the expected threads |
| 307 | b->waiting = 0; // init the counter of waiting threads |
| 308 | list_init (&b->wait); // init the waiting list |
| 309 | *barrier = b; // at last, init. the return variable |
| 310 | return SUCCESS; // it's fine |
| 311 | } |
| 312 | |
| 313 | if (b && (b->magic != MAGIC_BARRIER)) return EINVAL; // it is not an old barrier |
| 314 | |
| 315 | spin_lock (&b->lock); // get the ownership |
| 316 | if (b->waiting != 0) { // if someone is waiting |
| 317 | spin_lock (&b->lock); // release the ownership |
| 318 | return EBUSY; // return an error |
| 319 | } |
| 320 | |
| 321 | b->expected = count; // set the number of expected threads |
| 322 | spin_lock (&b->lock); // release the ownership |
| 323 | |
| 324 | return SUCCESS; // it's fine |
| 325 | } |
| 326 | |
| 327 | int thread_barrier_wait (thread_barrier_t * barrier) |
| 328 | { |
| 329 | thread_barrier_t b = *barrier; // get the barrier pointer |
| 330 | |
| 331 | if (b == NULL) return EINVAL; // b is not created |
| 332 | if (b && (b->magic != MAGIC_BARRIER)) return EINVAL; // check that it is barrier (MAGIC) |
| 333 | |
| 334 | spin_lock (&b->lock); // get the ownership |
| 335 | b->waiting++; // the current thread is the newcomer |
| 336 | if (b->waiting == b->expected) { // |
| 337 | list_foreach (&b->wait, waiting_item) { // |
| 338 | list_unlink (waiting_item); // |
| 339 | thread_t t = thread_item (waiting_item); // get the pointer of a waiting thread |
| 340 | thread_notify (t); // |
| 341 | } |
| 342 | b->waiting = 0; // |
| 343 | spin_unlock (&b->lock); // |
| 344 | } else { |
| 345 | thread_addlast (&b->wait, ThreadCurrent); // the current thread in the wait. list |
| 346 | spin_unlock (&b->lock); // |
| 347 | thread_wait (); // |
| 348 | |
| 349 | return SUCCESS; // it's fine |
| 350 | } |