1 /* kernel/ckrm_classqueue.c : implements the class queue
3 * Copyright (C) Haoqiang Zheng, IBM Corp. 2003
4 * (C) Hubertus Franke, IBM Corp. 2003
6 * Class queue functionality for CKRM cpu controller
8 * Latest version, more details at http://ckrm.sf.net
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
22 * classqueue now has a fixed size
24 * function/structure names are changed to more intuitive ones
26 #include <linux/sched.h>
27 #include <linux/ckrm_classqueue.h>
29 #define cq_nr_member(cq) (cq->array.nr_active)
30 #define CLASSQUEUE_MASK (CLASSQUEUE_SIZE - 1)
34 * translate the logical priority to the real index in the queue
36 * validate the position
37 * a valid prio is [cq->base,cq->base + size -1]
38 * check whether node is supposed to be enqeued beyond above window and
39 * if so set the need_repos flag
41 static inline unsigned long get_node_index(struct classqueue_struct *cq,
47 if (!cq_nr_member(cq))
50 max_prio = cq->base + (CLASSQUEUE_SIZE - 1);
51 if (unlikely(node->prio > max_prio)) {
52 node->real_prio = node->prio;
53 node->prio = max_prio;
58 if (unlikely(node->prio < cq->base))
59 node->prio = cq->base;
61 index = (cq->base_offset + (node->prio - cq->base)) ;
62 return ( index & CLASSQUEUE_MASK ); // ensure its in limits
66 * initialize a class queue object
68 int classqueue_init(struct classqueue_struct *cq, int enabled)
71 struct cq_prio_array *array;
74 for (i = 0; i < CLASSQUEUE_SIZE; i++) {
75 INIT_LIST_HEAD(array->queue + i);
76 __clear_bit(i, array->bitmap);
78 // delimiter for bitsearch
79 __set_bit(CLASSQUEUE_SIZE, array->bitmap);
84 cq->enabled = enabled;
90 *classqueue_enqueue - add the class to classqueue based on its prio
92 void classqueue_enqueue(struct classqueue_struct *cq,
93 cq_node_t * node, int prio)
98 if (cq_nr_member(cq)) {
99 index = get_node_index(cq, node);
100 } else { //the first one
107 list_add(&(node->list), &cq->array.queue[index]);
108 __set_bit(index, cq->array.bitmap);
109 cq->array.nr_active++;
115 void classqueue_dequeue(struct classqueue_struct *cq, cq_node_t * node)
118 list_del_init(&(node->list));
119 cq->array.nr_active--;
121 //check clear the bitmap
122 if (list_empty(&cq->array.queue[node->index]))
123 __clear_bit(node->index, cq->array.bitmap);
126 void classqueue_update_prio(struct classqueue_struct *cq,
127 cq_node_t * node, int new_pos)
131 if (! cls_in_classqueue(node))
134 node->prio = new_pos;
135 index = get_node_index(cq, node);
137 //remove from the original position
138 list_del_init(&(node->list));
139 if (list_empty(&cq->array.queue[node->index]))
140 __clear_bit(node->index, cq->array.bitmap);
142 //add to new positon, round robin for classes with same priority
143 list_add_tail(&(node->list), &cq->array.queue[index]);
144 __set_bit(index, cq->array.bitmap);
149 static inline void __classqueue_update_base(struct classqueue_struct *cq,
153 if (unlikely(new_base <= cq->base)) // base will never move back
155 if (unlikely(!cq_nr_member(cq))) {
157 cq->base = new_base; // is this necessary ??
161 max_prio = cq->base + (CLASSQUEUE_SIZE - 1);
162 if (unlikely(new_base > max_prio))
165 cq->base_offset = (cq->base_offset + (new_base - cq->base)) & CLASSQUEUE_MASK;
170 *classqueue_get_min_prio: return the priority of the last node in queue
172 * this function can be called without runqueue lock held
173 * return 0 if there's nothing in the queue
175 static inline int classqueue_get_min_prio(struct classqueue_struct *cq)
177 cq_node_t *result = NULL;
181 * search over the bitmap to get the first class in the queue
183 pos = find_next_bit(cq->array.bitmap, CLASSQUEUE_SIZE, cq->base_offset);
184 //do circular search from the beginning
185 if (pos >= CLASSQUEUE_SIZE)
186 pos = find_first_bit(cq->array.bitmap, CLASSQUEUE_SIZE);
188 if (pos < CLASSQUEUE_SIZE) {
189 result = list_entry(cq->array.queue[pos].next, cq_node_t, list);
190 if (list_empty(&cq->array.queue[pos]))
200 * this function must be called with runqueue lock held
202 cq_node_t *classqueue_get_head(struct classqueue_struct *cq)
212 * search over the bitmap to get the first class in the queue
214 pos = find_next_bit(cq->array.bitmap, CLASSQUEUE_SIZE, cq->base_offset);
215 //do circular search from the beginning
216 if (pos >= CLASSQUEUE_SIZE)
217 pos = find_first_bit(cq->array.bitmap, CLASSQUEUE_SIZE);
219 if (pos < CLASSQUEUE_SIZE) {
220 //BUG_ON(list_empty(&cq->array.queue[pos]));
221 node = list_entry(cq->array.queue[pos].next, cq_node_t, list);
224 //check if the node need to be repositioned
225 if (likely(! node || ! node->need_repos))
228 // We need to reposition this node in the class queue
229 // BUG_ON(node->prio == node->real_prio);
231 //remove from the original position
232 list_del_init(&(node->list));
233 if (list_empty(&cq->array.queue[node->index]))
234 __clear_bit(node->index, cq->array.bitmap);
236 new_base = classqueue_get_min_prio(cq);
237 node->prio = node->real_prio;
240 new_base = node->real_prio;
241 else if (node->real_prio < new_base)
242 new_base = node->real_prio;
243 __classqueue_update_base(cq,new_base);
245 index = get_node_index(cq, node);
246 //add to new positon, round robin for classes with same priority
247 list_add_tail(&(node->list), &cq->array.queue[index]);
248 __set_bit(index, cq->array.bitmap);
255 * Moving the end of queue forward
256 * the new_base here is logical, we need to translate to the abosule position
258 void classqueue_update_base(struct classqueue_struct *cq)
262 if (! cq_nr_member(cq)) {
268 new_base = classqueue_get_min_prio(cq);
269 __classqueue_update_base(cq,new_base);