/*
    OS Scheduler Simulator

** 連絡先: 琉球大学情報工学科 河野 真治  
** (E-Mail Address: kono@ie.u-ryukyu.ac.jp)
**
**    このソースのいかなる複写,改変,修正も許諾します。ただし、
**    その際には、誰が貢献したを示すこの部分を残すこと。
**    再配布や雑誌の付録などの問い合わせも必要ありません。
**    営利利用も上記に反しない範囲で許可します。
**    バイナリの配布の際にはversion messageを保存することを条件とします。
**    このプログラムについては特に何の保証もしない、悪しからず。
**
**    Everyone is permitted to do anything on this program 
**    including copying, modifying, improving,
**    as long as you don't try to pretend that you wrote it.
**    i.e., the above copyright notice has to appear in all copies.  
**    Binary distribution requires original version messages.
**    You don't have to ask before copying, redistribution or publishing.
**    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.

  Task Queue Manager

 */

#include <stdio.h>
#include <stdlib.h>
#include "queue.h"

int queue_errno; 

static QueuePtr freeQueue;   /* Free Pool of Queue */
static QueuePtr queuePool;   /* List of malloced free Queue */

static int extend_queue_pool(int num);

const int QUEUE_MALLOC_ERROR =   10;
const int POOL_SIZE_OVER_ERROR = 11;
const int MAX_POOL_SIZE = 65536*100;

int errno_queue;
static int pool_size;

//
// Initialize Queue Pool
//    return NULL on error
//

int
init_queue(int num)
{
    if (! queuePool) {
    return extend_queue_pool(num);
    }
    return 1;
}

static int
extend_queue_pool(int num)
{
    QueuePtr q;
    // Keep malloc history in QueuePool
    pool_size = num;
    q =  (QueuePtr) malloc(sizeof(Queue) * (num+1));
    if (!q) {
    queue_errno = QUEUE_MALLOC_ERROR;
    return NULL;
    }
    q->next = queuePool;
    queuePool = q;
    // Connect all free queue in the pool
    q = queuePool + 1;
    for(q = queuePool+1; num-->0;  q++) q->next = q+1;
    q->next = freeQueue;
    freeQueue = queuePool+1;
    return 1;
}

void
destory_queue()
{
    QueuePtr q;
    for(q = queuePool ;q; q = q->next) {
    free(q);
    }
    freeQueue = queuePool = NULL;
}

QueuePtr
new_queue(char *name, int length, int priority)
{
    QueuePtr q;
    if (!freeQueue) {
    pool_size *= 2;
    if (pool_size > MAX_POOL_SIZE) {
        queue_errno = POOL_SIZE_OVER_ERROR;
        return NULL;
    }
    if (!extend_queue_pool(pool_size)) {
        return NULL;
    }
    }
    q = freeQueue;
    freeQueue = freeQueue->next;

    q->next = NULL;
    q->priority = priority;
    q->name = name;
    q->length = length;
    q->invoke = 0;
    q->waiting = q->start = q->end = q->prev_end = 0;
    return q;
}

void
free_queue(QueuePtr q)
{
    q->next = freeQueue;
    freeQueue = q;
}


QueuePtr
insert_queue(QueuePtr list,QueuePtr q)
{
    q->next = list;
    return q;
}

QueuePtr
append_queue(QueuePtr list,QueuePtr q)
{
    QueuePtr p = list;
    if (!p) {
    return q;
    } else {
    while(p->next) p = p->next;
    p->next = q;
    return list;
    }
}

QueuePtr
dequeue(QueuePtr list,QueuePtr *q)
{
    QueuePtr p = list;
    if (p) {
    *q = list;
    return list->next;
    }
    return p;
}

QueuePtr
remove_queue(QueuePtr list,QueuePtr q)
{
    QueuePtr p = list;
    QueuePtr p1;

    if (!p) return p;
    p1 = p->next;
    while(p1 && p1 != q) { p1 = p1->next; p = p->next; }
    if (p1) {
    p->next = p1->next;
    }
    return list;
}

QueuePtr
sort_queue(QueuePtr q,int (*comp)(QueuePtr,QueuePtr))
{
    QueuePtr top,high,low,r,r1;

    if (q == NULL) return q;
    if (q->next == NULL) return q;

    /* split list into high part and low part */
    high = low = NULL;
    for(r = q->next; r ; ) {
    r1 = r->next;
    if (comp(q,r)) {
        r->next=high; high = r; 
    } else {
        r->next=low; low = r; 
    }
    r = r1;
    }

    /* sort each parts */
    high = sort_queue(high,comp);
    low = sort_queue(low,comp);

    /* append sorted parts */
    q->next = low;
    if (high) {
    top = high;
    while(high->next) high = high->next;
    high->next = q;
    } else {
    return q;
    }

    return top;
}


/* end */