xref: /minix3/minix/lib/libmthread/queue.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1  #include <minix/mthread.h>
2  #include "global.h"
3  #include "proto.h"
4  
5  /*===========================================================================*
6   *				mthread_queue_add			     *
7   *===========================================================================*/
mthread_queue_add(queue,thread)8  void mthread_queue_add(queue, thread)
9  mthread_queue_t *queue;		/* Queue we want thread to append to */
10  mthread_thread_t thread;
11  {
12  /* Append a thread to the tail of the queue. As a process can be present on
13   * only one queue at the same time, we can use the threads array's 'next'
14   * pointer to point to the next thread on the queue.
15   */
16    mthread_tcb_t *last;
17  
18    if (!isokthreadid(thread))
19    	mthread_panic("Can't append invalid thread ID to a queue");
20  
21    last = mthread_find_tcb(thread);
22  
23    if (mthread_queue_isempty(queue)) {
24    	queue->mq_head = queue->mq_tail = last;
25    } else  {
26  	queue->mq_tail->m_next = last;
27  	queue->mq_tail = last;	/* 'last' is the new last in line */
28    }
29  }
30  
31  
32  /*===========================================================================*
33   *				mthread_queue_init			     *
34   *===========================================================================*/
mthread_queue_init(queue)35  void mthread_queue_init(queue)
36  mthread_queue_t *queue;		/* Queue that has to be initialized */
37  {
38  /* Initialize queue to a known state */
39  
40    queue->mq_head = queue->mq_tail = NULL;
41  }
42  
43  
44  /*===========================================================================*
45   *				mthread_queue_isempty			     *
46   *===========================================================================*/
mthread_queue_isempty(queue)47  int mthread_queue_isempty(queue)
48  mthread_queue_t *queue;
49  {
50    return(queue->mq_head == NULL);
51  }
52  
53  
54  /*===========================================================================*
55   *				mthread_dump_queue			     *
56   *===========================================================================*/
57  #ifdef MDEBUG
mthread_dump_queue(queue)58  void mthread_dump_queue(queue)
59  mthread_queue_t *queue;
60  {
61    int threshold, count = 0;
62    mthread_tcb_t *t;
63    mthread_thread_t tid;
64    threshold = no_threads;
65    printf("Dumping queue: ");
66  
67    if(queue->mq_head != NULL) {
68    	t = queue->mq_head;
69  	if (t == &mainthread) tid = MAIN_THREAD;
70  	else tid = t->m_tid;
71  	printf("%d ", tid);
72  	count++;
73  	t = t->m_next;
74  	while (t != NULL) {
75  		if (t == &mainthread) tid = MAIN_THREAD;
76  		else tid = t->m_tid;
77  		printf("%d ", tid);
78  		t = t->m_next;
79  		count++;
80  		if (count > threshold) break;
81  	}
82    } else {
83    	printf("[empty]");
84    }
85  
86    printf("\n");
87  }
88  #endif
89  
90  /*===========================================================================*
91   *				mthread_queue_remove			     *
92   *===========================================================================*/
mthread_queue_remove(queue)93  mthread_thread_t mthread_queue_remove(queue)
94  mthread_queue_t *queue;		/* Queue we want a thread from */
95  {
96  /* Get the first thread in this queue, if there is one. */
97    mthread_thread_t thread;
98    mthread_tcb_t *tcb, *random_tcb, *prev;
99    int count = 0, offset_id = 0, picked_random = 0;
100  
101    tcb = queue->mq_head;
102  
103    if (MTHREAD_RND_SCHED) {
104  	/* Count items on queue */
105  	random_tcb = queue->mq_head;
106  	if (random_tcb != NULL) {
107  		do {
108  			count++;
109  			random_tcb = random_tcb->m_next;
110  		} while (random_tcb != NULL);
111  	}
112  
113  	if (count > 1) {
114  		picked_random = 1;
115  
116  		/* Get random offset */
117  		offset_id = random() % count;
118  
119  		/* Find offset in queue */
120  		random_tcb = queue->mq_head;
121  		prev = random_tcb;
122  		while (--offset_id > 0) {
123  			prev = random_tcb;
124  			random_tcb = random_tcb->m_next;
125  		}
126  
127  		/* Stitch head and tail together */
128  		prev->m_next = random_tcb->m_next;
129  
130  		/* Fix head and tail */
131  		if (queue->mq_head == random_tcb)
132  			queue->mq_head = random_tcb->m_next;
133  		if (queue->mq_tail == random_tcb)
134  			queue->mq_tail = prev;
135  
136  		tcb = random_tcb;
137  	}
138    }
139  
140    /* Retrieve thread id from tcb */
141    if (tcb == NULL) thread = NO_THREAD;
142    else if (tcb == &mainthread) thread = MAIN_THREAD;
143    else thread = (tcb->m_tid);
144  
145    /* If we didn't pick a random thread and queue is not empty... */
146    if (!picked_random && thread != NO_THREAD) {
147    	tcb = queue->mq_head;
148  	if (queue->mq_head == queue->mq_tail) {
149  		/* Queue holds only one thread */
150  		queue->mq_head = queue->mq_tail = NULL; /* So mark thread empty */
151  	} else {
152  		/* Second thread in line is the new first */
153  		queue->mq_head = queue->mq_head->m_next;
154  	}
155    }
156  
157    if (tcb != NULL)
158  	tcb->m_next = NULL; /* This thread is no longer part of a queue */
159  
160    return(thread);
161  }
162  
163