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