// // File name: queue.C // By Ting-jen Yen // #include "queue.h" #include #include "sparse_mask.h" #include "sparse_2.h" #include "tcpstream.h" #include "GLOBAL_VARIABLE.h" // ----------------------------------------------------------- // Class: Queue_item // Description: It is an element of request queue which // waiting to be sent to the server. // // Constructor, with no options set. // Queue_item::Queue_item() { next = NULL; depend = 0; } // // Real constructor of "Queue_item". // Set the value of request level, start and end of the rows // requested, start and end of the columns request. // Queue_item::Queue_item(int lvl, int st_r, int en_r, int st_c, int en_c) { level = lvl; st_col = st_c; en_col = en_c; st_row = st_r; en_row = en_r; depend = 0; next = NULL; } Queue_item::Queue_item(int lvl, int st_r, int en_r, int st_c, int en_c, int i) { level = lvl; st_col = st_c; en_col = en_c; st_row = st_r; en_row = en_r; depend = i; next = NULL; } // ----------------------------------------------------- // Class: Queue // Description: It is a queue to keep requests before // those requests been sent. It is in // link list structure. // This structure is the only way display // thread talk to network thread. // And because both threads access this // class, I use a mutual exclusive lock // to make sure only one thread can access // it at the same time. // There is also a semaphore used to block // the network thread to read from queue // when the queue is empty. // // Constructor. To initiate a empty Queue structure, and set // all pointers to NULL. Queue::Queue() { Length = 0; head = tail = NULL; } // To destroy a Queue structure, we have to remove // everything from the queue. Queue::~Queue() { Queue_item *ptr, *ptr_next; for (ptr = head; ptr != NULL;) { ptr_next = ptr->next; delete ptr; Length --; ptr = ptr_next; } } // In the startup function, we put a first request // in the queue, which is supposed to retrive the // whole image in the lowest resolution. void Queue::startup() { Queue_item *new_item; new_item = new Queue_item; new_item -> request_type = GET_LIST; // new_item -> request_type = VIEW_NEW_IMAGE; // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); if (head == NULL) head = tail = new_item; else { tail -> next = new_item; tail = new_item; } Length ++; // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); sem_post(&QUEUE_EMPTY); } // In this function, we will send a request to // stop the network connection. It would assume // highest priority and been put in the head of // queue instead of tail. void Queue::stop() { Queue_item *new_item; new_item = new Queue_item(0,0,0,0,0); new_item -> request_type = CLOSE_CONNECTION; // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); if (head == NULL) head = tail = new_item; else { new_item -> next = head; head = new_item; } Length ++; // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); sem_post(&QUEUE_EMPTY); } // Remove an item from head of queue and return it // Queue_item *Queue::dequeue() { Queue_item *return_value; sem_wait(&QUEUE_EMPTY); // If queue is empty, it will stop here waiting. // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); return_value = head; if (head) head = head->next; if (!head) tail = NULL; if (Length > 0) --Length; // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); return return_value; } // Remove every request in the queue void Queue::clean() { // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); while (!sem_trywait(&QUEUE_EMPTY)) { if (head) { Queue_item *tmp; tmp = head; head = head->next; delete tmp; } else tail = NULL; if (Length > 0) --Length; } pthread_mutex_unlock(&USE_QUEUE); } int Queue::enqueue(int id) { Queue_item *new_item; new_item = new Queue_item(); new_item->request_type = VIEW_NEW_IMAGE; new_item->level = id; // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); if (head == NULL) // Queue is empty head = tail = new_item; else { tail->next = new_item; tail = new_item; } // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); Length ++; sem_post(&QUEUE_EMPTY); return Length; } // // Get the data about a request, pack tham into a Queue_item // structure and put the item in the tail of the queue. // int Queue::enqueue(int lvl, int st_c, int en_c, int st_r, int en_r, int dep) { Queue_item *new_item; new_item = new Queue_item(lvl, st_c, en_c, st_r, en_r, dep); new_item ->request_type = GET_MORE_DATA; // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); if (head == NULL) // Queue is empty head = tail = new_item; else { tail->next = new_item; tail = new_item; } Length ++; // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); sem_post(&QUEUE_EMPTY); return Length; } // Return the length of the queue. // Note: The return value might NOT be totally correct. // Because it didn't use mutual exclusive lock, // Also, in the enqueue() function, the variable // Length modified AFTER the mutual exclusive lock. // It isn't a good way. But in this program, exactly // length of the queue is not necessary, so I didn't // add mutual exclusive lock in it. int Queue::length() { return Length; } // // reduce() is a function to examine the contents in // the queue, and remove some of them which is no // longer necessary. // // x, y, w, h is the coordinates and size of view window, // level is the current resolution level. void Queue::reduce(int x, int y, int w, int h, int level) { Queue_item **prev_item, *current_item, *last_item; int x_min, x_max, y_min, y_max; int free_one = 0; x_min = x << level; y_min = y << level; x_max = (x+w) << level; y_max = (y+w) << level; last_item = NULL; // Beginning mutual exclusive session pthread_mutex_lock(&USE_QUEUE); for (prev_item = &head, current_item = head; current_item != NULL && Length > 0;) { int x1_min, x1_max, y1_min, y1_max, level1; // if a request in queue isn't asking for data, // we should skip it. We only deal with the // request asking for data. if (current_item ->request_type != GET_MORE_DATA) { last_item = current_item; prev_item = &(current_item->next); current_item = current_item -> next; continue; } level1 = current_item->level; level1 ++; x1_min = current_item->st_row << level1; x1_max = current_item->en_row << level1; y1_min = current_item->st_col << level1; y1_max = current_item->en_col << level1; // if the requested area did cover part of // our view window, we will leave it alone. if (((x1_min <= x_min && x1_max >= x_min) || (x1_min <= x_max && x1_max >= x_max)) && ((y1_min <= y_min && y1_max >= y_min) || (y1_min <= y_max && y1_max >= y_max))) { last_item = current_item; prev_item = &(current_item->next); current_item = current_item -> next; continue; } // Otherwise, we can remove it, because the user // input has made the view window outside the // area after this request is made. for (Queue_item *pt = current_item->next; pt && pt->depend==1;) { current_item->next = pt->next; delete pt; sem_wait(&QUEUE_EMPTY); Length --; pt = current_item->next; } *prev_item = current_item->next; free_one = 1; Length --; if (current_item == tail) tail = last_item; delete current_item; current_item = *prev_item; } if (head == NULL) tail = NULL; // Ending mutual exclusive session pthread_mutex_unlock(&USE_QUEUE); if (free_one == 1) sem_wait(&QUEUE_EMPTY); }