예제 #1
0
void *hydrogen_routine(void *arg) {
    thread_data *t_data = (thread_data *)arg;
    int thread_id = t_data->t_id;

    // acquire lock on mutex before accessing shared memory
    semwait(&mutex);

    // if enough C is waiting, continue past barrier
    printf("HYDROGEN %d reached barrier.\n", thread_id);
    if (waiting_h >= 3 && waiting_c >= 1) {
        printf("~~~~ Crossed barrier, created a Methane!\n\n");
        // release 4 H
        int i;
        for(i = 0; i < 3; i++) {
            semsignal(&sem_h);
        }
        waiting_h -= 3;
        semsignal(&sem_c);
        waiting_c--;
        // release lock on mutex
        semsignal(&mutex);
    }
    else {
        // not enough H or C is waiting, so wait at barrier
        waiting_h++;
        printf("Waiting Atoms -- C: %d | H: %d\n", waiting_c, waiting_h);
        // release lock on mutex
        semsignal(&mutex);
        semwait(&sem_h);
    }

    pthread_exit(EXIT_SUCCESS);

}
예제 #2
0
파일: usb_mailbox.c 프로젝트: idmond/moped
/* @ingroup mailbox
 *
 * Allocate a mailbox that allows up to the specified number of outstanding
 * messages.
 *
 * @param count
 *      Maximum number of messages allowed for the mailbox.
 *
 * @return
 *      The index of the newly allocated mailbox, or ::SYSERR if all mailboxes
 *      are already in use or other resources could not be allocated.
 */
syscall mailboxAlloc(uint count)
{
    static uint nextmbx = 0;
    uint i;
    struct mbox *mbxptr;
    int retval = SYSERR;

    /* wait until other threads are done editing the mailbox table */
    wait(mboxtabsem);

    /* run through all mailboxes until we find a free one */
    for (i = 0; i < NMAILBOX; i++)
    {
        nextmbx = (nextmbx + 1) % NMAILBOX;
        mbxptr = &mboxtab[nextmbx];

        /* when we find a free mailbox set that one up and return it */
        if (MAILBOX_FREE == mbxptr->state)
        {
            /* get memory space for the message queue */
            mbxptr->msgs = memget(sizeof(int) * count);

            /* check if memory was allocated correctly */
            if (SYSERR == (int)mbxptr->msgs)
            {
                pi_printf("error: fail to mailbox memory\r\n");
                break;
            }

            /* initialize mailbox details and semaphores */
            mbxptr->count = 0;
            mbxptr->start = 0;
            mbxptr->max = count;
            usb_sem_new(&mbxptr->sender, 1024);
            usb_sem_new(&mbxptr->receiver, 0);
            if ((SYSERR == (int)mbxptr->sender) ||
                    (SYSERR == (int)mbxptr->receiver))
            {
                memfree(mbxptr->msgs, sizeof(int) * (mbxptr->max));
                semfree(mbxptr->sender);
                semfree(mbxptr->receiver);
                pi_printf("error: fail to allocate mailbox\r\n");
                break;
            }

            /* mark this mailbox as being used */
            mbxptr->state = MAILBOX_ALLOC;

            /* return value is index of the allocated mailbox */
            retval = nextmbx;
            break;
        }
    }

    /* signal this thread is done editing the mbox tab */
    semsignal(mboxtabsem);

    /* return either SYSERR or the index of the allocated mailbox */
    return retval;
}
예제 #3
0
파일: usb_mailbox.c 프로젝트: idmond/moped
/**
 * @ingroup mailbox
 *
 * Free the specified mailbox.
 *
 * @param box
 *      The index of the mailbox to free.
 *
 * @return
 *      ::OK if the mailbox was successfully freed, or ::SYSERR if @p box did
 *      not specify a valid allocated mailbox.
 */
syscall mailboxFree(mailbox box)
{
    struct mbox *mbxptr;
    int retval;

    if (!(0 <= box && box < NMAILBOX))
    {
        pi_printf("error: fail to mailbox free\r\n");
        return SYSERR;
    }

    mbxptr = &mboxtab[box];

    /* wait until other threads are done editing the mailbox table */
    wait(mboxtabsem);

    if (MAILBOX_ALLOC == mbxptr->state)
    {
        /* mark mailbox as no longer allocated  */
        mbxptr->state = MAILBOX_FREE;

        /* free semaphores related to this mailbox */
        semfree(mbxptr->sender);
        semfree(mbxptr->receiver);

        /* free memory that was used for the message queue */
        memfree(mbxptr->msgs, sizeof(int) * (mbxptr->max));

        retval = OK;
    }
    else
    {
        /* mailbox was not allocated  */
        pi_printf("error: mailbox was not allocated\r\n");
        retval = SYSERR;
    }

    /* signal that this thread is done editing the mailbox table */
    semsignal(mboxtabsem);

    return retval;
}
예제 #4
0
static void semwait(int sem)
{
    struct sembuf sbuf = { .sem_num = 0, .sem_op = -1, .sem_flg = 0 };
    assert (semop(sem, &sbuf, 1) != -1);
}

static void semsignal(int sem)
{
    struct sembuf sbuf = { .sem_num = 0, .sem_op = 1, .sem_flg = 0 };
    assert (semop(sem, &sbuf, 1) != -1);
}

static pid_t fork_generator(
    int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y,
    int left_x, int left_y
)
{
    pid_t child = fork();
    if (child != 0) { // Parent
        assert (child != -1);
        return child;
    } else // Child
        exit(generator(
            sem_labyrinth, shm_stats, shm_labyrinth, top_x, top_y, 
            left_x, left_y)
        );
}

// Retourne la cellule qui partage le même mur.
static CELL *cell_fellow(CELL *cell, WALL orientation);

// Retourne l'orientation opposée d'un mur
static WALL orientation_inv(WALL orientation);

// Vérifie que certains murs privés ne partagent pas à présent les mêmes groupes
// ou qu'ils ne sont pas devenus partagés lorsque on a lié les deux groupes.
static void update_private(
    LABYRINTH labyrinth, CELL walls[], int *last_private, int *first_shared
);

static int generator(
    int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y,
    int left_x, int left_y
)
{
    int size = LABYRINTH_SIZE / 2;

    // Récupère les mémoires partagées.
    PARAL_STATS *stats = (PARAL_STATS *) shmat(shm_stats, NULL, 0);
    assert (stats != (PARAL_STATS *) -1);
    LABYRINTH labyrinth = (LABYRINTH) shmat(shm_labyrinth, NULL, 0);
    assert (labyrinth != (LABYRINTH) -1);

    // Retiens les murs non ouverts dans la zone du générateur (indice de la
    // cellule avec orientation du mur, utilise les bits dédiés au groupe
    // pour encoder l'indice).
    // Ajoute les murs non partagés à partir de la gauche et ceux partagés à
    // partir de la droite du vecteur.
    int n_walls = 2 * size * size;
    int last_private = -1
      , first_shared = n_walls;
    CELL walls[n_walls];

    semwait(sem_labyrinth); // Accède en lecture à des cellules partagées.
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            int top_index  = (top_y + i)  * LABYRINTH_SIZE + top_x + j
              , left_index = (left_y + i) * LABYRINTH_SIZE + left_x + j;

            CELL *top_cell  = labyrinth + top_index
               , *left_cell = labyrinth + left_index;

            CELL top_fellow  = *cell_fellow(top_cell, WALL_TOP)
               , left_fellow = *cell_fellow(left_cell, WALL_LEFT);

            // Ajoute les murs sur des cases partagées à droite, les autres
            // à gauche.

            if (is_shared(*top_cell) && is_shared(top_fellow))
                walls[--first_shared] = WALL_TOP | (CELL) top_index;
            else
                walls[++last_private] = WALL_TOP | (CELL) top_index;

            if (is_shared(*left_cell) && is_shared(left_fellow))
                walls[--first_shared] = WALL_LEFT | (CELL) left_index;
            else
                walls[++last_private] = WALL_LEFT | (CELL) left_index;
        }
    }
    semsignal(sem_labyrinth);

    // Boucle tant qu'il reste des murs à supprimer.
    for (;;) {
        semwait(sem_labyrinth);

        // Vérifie que les murs partagés n'ont pas été supprimés par un autre
        // processus et qu'ils départagent toujours deux groupes différents.
        for (int i = n_walls - 1; i >= first_shared; i--) {
            CELL wall = walls[i];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);

            bool can_be_removed =
                   is_wall(*cell1, orientation)
                && cell_root(labyrinth, cell1) != cell_root(labyrinth, cell2);

            if (!can_be_removed) // Ne peut plus supprimer ce mur.
                walls[i++] = walls[first_shared++];
        }

        // Sélectionne au hasard un mur dans les murs restants.
        int n_remaining = (last_private + 1) + (n_walls - first_shared);
        if (n_remaining == 0) {
            semsignal(sem_labyrinth);
            break;
        }
        int random_index = rand() % n_remaining;

        if (random_index <= last_private) {
            stats->hits++;
            semsignal(sem_labyrinth);

            // Cette partie de l'algorithme peut s'effectuer en même temps sur
            // différents processus :

            CELL wall = walls[random_index];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);
            CELL *root1 = cell_root(labyrinth, cell1)
               , *root2 = cell_root(labyrinth, cell2);

            // Attache toujours une cellule qui n'appartient pas à un groupe
            // partagé à l'autre cellule. De cette manière, la racine d'un
            // groupe dont au moins une cellule est partagée sera une cellule
            // partagée. Ceci évite également de modifier une forêt qui pourrait
            // être modifiée par un autre processus au même moment.
            if (is_shared(*root1))
                cell_attach_group(root2, *root1);
            else
                cell_attach_group(root1, *root2);
            // Supprime le mur de la liste d'attente et des deux cellules.
            walls[random_index] = walls[last_private--];

            // Ces deux instructions sont équivalentes à ces deux instructions:
            // *cell1 &= ~orientation;
            // *cell2 &= ~orientation_inv(orientation);
            // A l'exception que le compilateur garantit que ces instructions
            // s'exécutent de manière atomique, et permet ainsi d'éviter que 
            // deux processus suppriment deux murs différents d'une même cellule
            // au même instant, ce qui engendrait une perte de l'une des deux
            // modifications.
            __sync_fetch_and_and(cell1, ~orientation);
            __sync_fetch_and_and(cell2, ~orientation_inv(orientation));
            // Une alternative aurait été d'acquérir la sémaphore sem_labyrinth
            // lorsque l'on change l'orientation d'une cellule qui est sur un
            // bord de la zone du générateur, mais cette méthode est
            // considérablement plus rapide.

            update_private(labyrinth, walls, &last_private, &first_shared);
        } else {
            stats->misses++;

            int wall_index = random_index - (last_private + 1) + first_shared;
            CELL wall = walls[wall_index];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);
            CELL *root1 = cell_root(labyrinth, cell1);

            cell_attach_group(root1, *cell2);

            // Supprime le mur de la liste d'attente et des deux cellules.
            walls[wall_index] = walls[first_shared++];
            *cell1 &= ~orientation;
            *cell2 &= ~orientation_inv(orientation);

            semsignal(sem_labyrinth);
        }
    }
    return EXIT_SUCCESS;
}
예제 #5
0
LABYRINTH gen_labyrinth(PARAL_STATS *stats)
{
    // Crée une sémaphore qui sera utilisée comme mutex pour empêcher plusieurs
    // processus générateurs de supprimer en même temps une bordure entre deux
    // groupes de cellules qui sont partagés par plusieurs processus.
    // Tous les accès aux cellules partagées (limitrophes) ainsi qu'à l'ensemble
    // de leurs groupes respectifs devront se faire en ayant acquis cette mutex.
    int sem_labyrinth = semget(IPC_PRIVATE, 1, 0600);
    assert (sem_labyrinth != -1);
    semsignal(sem_labyrinth); // Initialise à 1 la sémaphore.

    // Ouvre une mémoire partagée pour stocker les statistiques de l'exécution
    // parallèle.
    int shm_stats = shmget(IPC_PRIVATE, sizeof (PARAL_STATS), 0600);
    assert (shm_stats != -1);
    PARAL_STATS *sh_stats = (PARAL_STATS *) shmat(shm_stats, NULL, 0);
    assert (sh_stats != (PARAL_STATS *) -1);
    sh_stats->hits = 0;
    sh_stats->misses = 0;

    // Crée une mémoire partagée pour stocker le labyrinthe.
    int shm_labyrinth = shmget(
        IPC_PRIVATE, sizeof (CELL) * LABYRINTH_SIZE * LABYRINTH_SIZE, 0600
    );
    assert (shm_labyrinth != -1);
    LABYRINTH labyrinth = (LABYRINTH) shmat(shm_labyrinth, NULL, 0);
    assert (labyrinth != (LABYRINTH) -1);

    init_labyrinth(labyrinth);

    // Démarre les quatre processus de génération (ne démarre que 3 processus
    // supplémentaires).
    int m = LABYRINTH_SIZE / 2;
    fork_generator(sem_labyrinth, shm_stats, shm_labyrinth, 0, 1, 1, 0);
    fork_generator(sem_labyrinth, shm_stats, shm_labyrinth, m, 1, m, 0);
    fork_generator(sem_labyrinth, shm_stats, shm_labyrinth, 0, m, 1, m);
    generator     (sem_labyrinth, shm_stats, shm_labyrinth, m, m, m, m);

    // Attend que toutes les cases des trois enfants soient toutes de la
    // même couleur.
    for (int i = 0; i < 3; i++) {
        int child_status;
        wait(&child_status);
        assert (child_status == EXIT_SUCCESS);
    }

    // Copie le résultat hors de la mémoire partagée.
    LABYRINTH ret_labyrinth = (LABYRINTH) malloc(
        sizeof (CELL) * LABYRINTH_SIZE * LABYRINTH_SIZE
    );
    memcpy(
        ret_labyrinth, labyrinth,
        sizeof (CELL) * LABYRINTH_SIZE * LABYRINTH_SIZE
    );

    // Récupère les statistiques.
    if (stats != NULL)
        *stats = *sh_stats;

    // Ferme les IPCs.
    assert (semctl(sem_labyrinth, 0, IPC_RMID) != -1);
    assert (shmctl(shm_stats, IPC_RMID, NULL) != -1);
    assert (shmctl(shm_labyrinth, IPC_RMID, NULL) != -1);

    return ret_labyrinth;
}
예제 #6
0
int main(int argc, char** argv)
{
  printf("bus %s started\n", argv[1]);
  fflush(stdout);

  int semid, shmid;
  struct Common* shared;

  semid = semget(getSemKey(), NUM_SEMS, 0777);
  shmid = shmget(getSemKey(), 0, 0);
  shared = (struct Common *)shmat(shmid, 0, 0);

  semwait(semid, SEM_GATE_EMPTY);
  printf("Bus %s has arrived\n", argv[1]);
  fflush(stdout);

  semsignal(semid, SEM_BUS_BOARDABLE);

  semwait(semid, SEM_MUTEX);
  time_t sleep_time = shared->departure_time - time(NULL);
  semsignal(semid, SEM_MUTEX);

  printf("Bus %s Sleeping until departure\n", argv[1]);
  fflush(stdout);
  sleep(sleep_time);

  semwait(semid, SEM_MUTEX);
  printf("Bus %s: last call for boarding\n", argv[1]);
  fflush(stdout);
  while(1)
  {
	  semwait(semid, SEM_CAN_BOARD);
	  if(shared->tickets_sold == shared->boarded)
	  {
		  semsignal(semid, SEM_CAN_BOARD);
		  break;
	  }
	  semsignal(semid, SEM_CAN_BOARD);
	  // wait another second to give customer
	  // threads a chance to finish boarding
	  sleep(1);
  }

  semwait(semid, SEM_BUS_BOARDABLE);

  // release passengers to the gate that were waiting for the next bus
  printf("Bus %s releasing next bus queue\n", argv[1]);
  fflush(stdout);
  int i;
  for(i=0; i<shared->next_bus_tickets; i++)
  {
	  semsignal(semid, SEM_NEXT_BUS_QUEUE);
  }

  // reset the ticket variables for the next bus
  printf("Bus %s preparing shared variables for next bus\n", argv[1]);
  fflush(stdout);
  // if there were customers waiting for the next, next bus or beyond
  // release some of them
  for(i=0; i<shared->tickets_sold; i++)
  {
	  semsignal(semid, SEM_MAX_CUSTOMERS);
  }
  shared->tickets_sold = shared->next_bus_tickets;
  shared->next_bus_tickets = 0;
  shared->departure_time += BUS_PERIOD;
  shared->boarded = 0;
  semsignal(semid, SEM_MUTEX);

  semsignal(semid, SEM_GATE_EMPTY);

  printf("Bus %s is departing\n", argv[1]);
  fflush(stdout);
  return 0;
}