Пример #1
0
/*
 * The scheduler is called with the context of the current thread,
 * or NULL when the scheduler is first started.
 *
 * The general operation of this function is:
 *   1.  Save the context argument into the current thread.
 *   2.  Either queue up or deallocate the current thread,
 *       based on its state.
 *   3.  Select a new "ready" thread to run, and set the "current"
 *       variable to that thread.
 *        - If no "ready" thread is available, examine the system
 *          state to handle this situation properly.
 *   4.  Return the context of the thread to run, so that a context-
 *       switch will be performed to start running the next thread.
 *
 * This function is global because it needs to be called from the assembly.
 */
ThreadContext *__sthread_scheduler(ThreadContext *context) {
    /* If this is not the first call to scheduler (= no current thread),
     * 1. Save the context argument into the current thread.
     */
    if (context != NULL) {
        current->context = context;

        /* 2. Queue up or deallocate the current thread. */
        if (current->state == ThreadRunning) {
            current->state = ThreadReady;
            queue_add(current);
        }
        else if (current->state == ThreadBlocked) {
            queue_add(current);
        }
        else if (current->state == ThreadFinished) {
            __sthread_delete(current);
        }
    }
    
    /* 3. Select a new 'ready' thread to run. */
    current = queue_take(&ready_queue);
    
    /* No Ready threads. */
    if (current == NULL && queue_take(&blocked_queue) == NULL) {
        fprintf(stderr, "All threads finished successfully.\n");
        exit(0);
    }
    else if (current == NULL) {
        fprintf(stderr, "Program deadlocked!\n");
        exit(1);
    }
    
    current->state = ThreadRunning;

    /* 4. Return the next thread to resume executing. */
    return current->context;
}
Пример #2
0
/*
 * The scheduler is called with the context of the current thread,
 * or NULL when the scheduler is first started.
 *
 * The general operation of this function is:
 *   1.  Save the context argument into the current thread.
 *   2.  Either queue up or deallocate the current thread,
 *       based on its state.
 *   3.  Select a new "ready" thread to run, and set the "current"
 *       variable to that thread.
 *        - If no "ready" thread is available, examine the system
 *          state to handle this situation properly.
 *   4.  Return the context of the thread to run, so that a context-
 *       switch will be performed to start running the next thread.
 *
 * This function is global because it needs to be called from the assembly.
 */
ThreadContext *__sthread_scheduler(ThreadContext *context) {
    // Check if we actually have a context to work with
    if (context != NULL) {
        // 1. Save the context argument into the current thread
        current->context = context;
        // 2. Either queue up or deallocate the current thread, based on its state
        switch (current->state) {
            case ThreadFinished:
                // Delete the thread
                __sthread_delete(current);
                break;
            case ThreadRunning:
                // Change state of thread, and queue it
                current->state = ThreadReady;
                queue_add(current);
                break;
            case ThreadBlocked:
                // Queue thread
                queue_add(current);
                break;
            case ThreadReady:
                // Should not be switching from a ready thread
                printf("ERROR: Switching from a ready thread\n");
                assert(0);
                break;
        }
    }

    // 3. Select a new "ready" thread to run, and set the "current" variable
    // to that thread. If there are no ready threads and there are no blocked
    // threads, all threads in the program have successfully completed. However,
    // if there are one more more blocked threads in the blocked queue, the
    // program has become deadblocked.
    current = queue_take(&ready_queue);
    if (current == NULL && queue_empty(&blocked_queue)) {
        printf("All threads in the program have successfully completed, exiting\n");
        exit(0);
    } else if (current == NULL && !queue_empty(&blocked_queue)) {
        printf("Program has become deadlocked, exiting\n");
        exit(1);
    }
    current->state = ThreadRunning;

    // 4. Return the next thread to resume executing.
    return current->context;
}
Пример #3
0
/*
 * The scheduler is called with the context of the current thread,
 * or NULL when the scheduler is first started.
 *
 * The general operation of this function is:
 *   1.  Save the context argument into the current thread.
 *   2.  Either queue up or deallocate the current thread,
 *       based on its state.
 *   3.  Select a new "ready" thread to run, and set the "current"
 *       variable to that thread.
 *        - If no "ready" thread is available, examine the system
 *          state to handle this situation properly.
 *   4.  Return the context of the thread to run, so that a context-
 *       switch will be performed to start running the next thread.
 *
 * This function is global because it needs to be called from the assembly.
 */
ThreadContext *__sthread_scheduler(ThreadContext *context) {
    if (context != NULL) {
        /* Save the context argument into the current thread. */
        current->context = context;
        /* Either queue up or deallocate current thread, based on its state. */
        if (current->state == ThreadFinished) {
            /* Deallocatate because finished. */
            __sthread_delete(current);
        }
        else if (current->state == ThreadBlocked) {
            /* Queue up because blocked. */
            queue_add(current);
        }
        else if (current->state == ThreadRunning) {
            /* Queue up because yielding and make it ready. */
            current->state = ThreadReady;
            queue_add(current);
        }
    }

    if (queue_empty(&ready_queue)) {
        if (queue_empty(&blocked_queue)) {
            /* Nothing ready and nothing blocked, so done! */
            printf("Done.\n");
            exit(0);
        }
        else {
            /* Nothing ready but still blocked threads, so deadlock. */
            printf("Deadlock.\n");
            /* Exit with error. */
            exit(1);
        }
    }
    else {
        /* Select a new "ready" thread to run, and set the "current" variable to
         * that thread. */
        current = queue_take(&ready_queue);
        current->state = ThreadRunning;
    }

    return current->context;
}
Пример #4
0
/*
 * The scheduler is called with the context of the current thread,
 * or NULL when the scheduler is first started.
 *
 * The general operation of this function is:
 *   1.  Save the context argument into the current thread.
 *   2.  Either queue up or deallocate the current thread,
 *       based on its state.
 *   3.  Select a new "ready" thread to run, and set the "current"
 *       variable to that thread.
 *        - If no "ready" thread is available, examine the system
 *          state to handle this situation properly.
 *   4.  Return the context of the thread to run, so that a context-
 *       switch will be performed to start running the next thread.
 *
 * This function is global because it needs to be called from the assembly.
 */
ThreadContext *__sthread_scheduler(ThreadContext *context) {

    /* Add the current thread to the ready queue */
    if (context != NULL) {
        assert(current != NULL);

        if (current->state == ThreadRunning)
            current->state = ThreadReady;

        if (current->state != ThreadFinished) {
            current->context = context;
            queue_add(current);
        }
        else {
            __sthread_delete(current);
        }
    }

    /*
     * Choose a new process from the ready queue.
     * Abort if the queue is empty.
     */
    current = queue_take(&ready_queue);
    if (current == NULL) {
        if (queue_empty(&blocked_queue)) {
            fprintf(stderr, "All threads completed, exiting.\n");
            exit(0);
        }
        else {
            fprintf(stderr, "The system is deadlocked!\n");
            exit(1);
        }
    }

    current->state = ThreadRunning;

    /* Return the next thread to resume executing. */
    return current->context;
}
Пример #5
0
/**
 * Reads a file and appends it to the search list
 */
int search_queue_add(char* file, struct queue_head* free_iovec_queue, struct queue_head* search_queue) {
  int bytes_read = 0;
  int fd = open(file, O_RDONLY);
  if(fd < 0){
    fprintf(stderr,"Couldn't open file [%s] \n", file);
    return -1;
  }
  struct stat file_info;

  int ret = fstat(fd,&file_info);
  if(ret){
    fprintf(stderr,"Couldnt stat file %s %d \n",file,ret);
    return -1;
  }

  posix_fadvise(fd,0,0,POSIX_FADV_SEQUENTIAL|POSIX_FADV_NOREUSE);

  int total_bytes = file_info.st_size;  
  if(total_bytes == 0) {
    close(fd);
    return total_bytes;
  }

  int iovecs_to_read = (int)ceil((double)total_bytes/(1.0*cfg.iovec_block_size));

  struct queue*  assignable_nodes =  queue_take(free_iovec_queue, iovecs_to_read);

  struct search_queue_node*  sqn[iovecs_to_read];
  struct queue* cur = assignable_nodes;

  long long  i = 0;
  while(cur!=NULL){
    sqn[i] = assignable_nodes->data;
    strncpy(sqn[i]->file_name,file,MAX_FILE_NAME);
    sqn[i]->file_name_len = strlen(file);
    sqn[i]->iovec_num = i;

    cur = cur->next;
    i++;
  }
    
  if(sqn == NULL){    
    return 0;
  }  

  struct iovec buffers[iovecs_to_read];
  
  // Assign base address from nodes gotten from free list
  for(i = 0;i < iovecs_to_read; i++){
    // also populate list
    buffers[i].iov_base = sqn[i]->vec->iov_base;
    buffers[i].iov_len = sqn[i]->vec->iov_len;
  }
  
  // gather all files blocks that can be read into buffers
  bytes_read = readv(fd, buffers , iovecs_to_read);

  queue_prepend_all_list(search_queue, assignable_nodes);    

  fprintf(stderr,"Read file [%s] \n%d bytes num iovecs %d \n",file,bytes_read,iovecs_to_read);


  close(fd);

  return bytes_read;
}