Пример #1
0
/*
 * Yield, so that another thread can run.  This is easy:
 * just call the scheduler, and it will pick a new thread to
 * run.
 */
void sthread_yield() {
    /* This is an entry point to the scheduler. We need the lock to stop
     * multiple contexts from being saved and restored.
     */
    __sthread_lock();
    __sthread_schedule();
}
Пример #2
0
/*
 * This function is called automatically when a thread's function returns,
 * so that the thread can be marked as "finished" and can then be reclaimed.
 * The scheduler will call __sthread_delete() on the thread before scheduling
 * a new thread for execution.
 *
 * This function is global because it needs to be referenced from assembly.
 */
void __sthread_finish(void) {
    /* This was already in the assignment. */
    __sthread_lock();
    printf("Thread 0x%08x has finished executing.\n", (unsigned int) current);
    current->state = ThreadFinished;
    __sthread_schedule();
}
Пример #3
0
/*
 * Add an integer to the buffer.  Yield control to another
 * thread if the buffer is full.
 */
void bounded_buffer_add(BoundedBuffer *bufp, const BufferElem *elem) {
    // We only want one thread modifying the buffer at a time
    __sthread_lock();
    // Decrement the count of available space (we're adding)
    // Blocks when available count = 0 (buffer is full)
    semaphore_wait(bufp->avail);
    bufp->buffer[(bufp->first + bufp->count) % bufp->length] = *elem;
    bufp->count++;
    // Increment the count of used space
    semaphore_signal(bufp->used);
    __sthread_unlock();
}
Пример #4
0
/*
 * Get an integer from the buffer.  Yield control to another
 * thread if the buffer is empty.
 */
void bounded_buffer_take(BoundedBuffer *bufp, BufferElem *elem) {
    // We only want one thread modifying the buffer at a time
    __sthread_lock();
    // Decrement count of used space (we're freeing)
    // Blocks when there are no used elements (buffer is empty)
    semaphore_wait(bufp->used);
    /* Copy the element from the buffer, and clear the record */
    *elem = bufp->buffer[bufp->first];
    bufp->buffer[bufp->first] = empty;
    bufp->count--;
    bufp->first = (bufp->first + 1) % bufp->length;
    // Increment count of available space
    semaphore_signal(bufp->avail);
    __sthread_unlock();
}
Пример #5
0
/*
 * Decrement the semaphore.
 * This operation must be atomic, and it blocks iff the semaphore is zero.
 */
void semaphore_wait(Semaphore *semp) {
    /* This must be atomic, so make sure no other threads interfere. */
    __sthread_lock();

    while (semp->i == 0) {
        /* Semaphore cannot handle another thread, so block current one. */

        /* Add to queue of blocked threads. */
        struct thread_node * current =
            (struct thread_node *) malloc(sizeof(struct thread_node));

        /* The thread to be held is the currently executing one. */
        current->thread = sthread_current();

        /* Will be at the end of queue so next is NULL. */
        current->next = NULL;

        /* Add to queue. */
        if (semp->head == NULL) {
            /* Empty queue, head and tail are the new thread_node. */
            semp->head = current;
            semp->tail = semp->head;
        }
        else {
            /* This will be the next of tail, and new tail. */
            semp->tail->next = current;
            semp->tail = semp->tail->next;
        }

        /* Block it. */
        sthread_block();
    }

    /* Decrement semaphore count, should still be non-negative. */
    semp->i--;
    assert(semp->i >= 0);

    /* Can unlock now that operations are done. */
    __sthread_unlock();
}
Пример #6
0
/*
 * Increment the semaphore.
 * This operation must be atomic.
 */
void semaphore_signal(Semaphore *semp) {
    /* This must be atomic, so make sure no other threads interfere. */
    __sthread_lock();

    /* Incrememnt semaphore count. */
    semp->i++;

    /* Get next in queue to run. */
    if (semp->head == NULL) {
        /* Queue empty! Do nothing. */
    }
    else {
        /* Save the current head to free it later. */
        struct thread_node * old_head = semp->head;

        /* Unblock the head. */
        sthread_unblock(semp->head->thread);

        /* Remove from queue and free. */
        if (semp->head->next == NULL) {
            /* If this has no next them queue is empty now. */
            semp->head = NULL;
            semp->tail = NULL;
        }
        else {
            /* Move head to the next. */
            semp->head = semp->head->next;
        }

        /* Free it. */
        free(old_head);
    }

    /* Can unlock now that operations are done. */
    __sthread_unlock();
}
Пример #7
0
/*
 * Block the current thread.  Set the state of the current thread
 * to Blocked, and call the scheduler.
 */
void sthread_block() {
    /* This is an entry point to the scheduler. */
    __sthread_lock();
    current->state = ThreadBlocked;
    __sthread_schedule();
}