-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathwait.c
More file actions
executable file
·135 lines (112 loc) · 4.54 KB
/
wait.c
File metadata and controls
executable file
·135 lines (112 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
; Copyright (C) 2003-2004 A.R.Karthick
; <a_r_karthic@users.sourceforge.net>
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
;
;
*/
/*
Wait queue implementation routines for the thread.
Works in the same way as the Linux Kernel.
*/
#include<stdio.h>
#include "wait.h"
#include "task.h"
#include "sched.h"
#include "util.h"
void init_waitqueue_entry(struct wait_queue *wait_queue,struct task_struct *task){
wait_queue->task = task; //add the task to the wait queue
wait_queue->wait_queue_head.next = wait_queue->wait_queue_head.prev = NULL;
}
/*Add an entry to the wait queue head*/
void add_waitqueue(struct wait_queue *wait_queue,struct wait_queue_head *wait_queue_head) {
struct list_head *element = &wait_queue->wait_queue_head;
struct list_head *head = &wait_queue_head->wait_queue_head;
list_add_tail(element,head);
return ;
}
void remove_waitqueue(struct wait_queue *wait_queue) {
struct list_head *element = &wait_queue->wait_queue_head;
list_del(element); //remove the element from the list
return ;
}
void init_waitqueue_head(struct wait_queue_head *wait_queue_head) {
struct list_head *head = &wait_queue_head->wait_queue_head;
INIT_LIST_HEAD(head); //initialise the list head
}
static __inline__ void remove_from_run_queue(struct list_head *run_queue) {
if(run_queue->next && run_queue->prev) {
list_del(run_queue);
run_queue->next = run_queue->prev = NULL;
}
}
static __inline__ void add_to_run_queue(struct list_head *run_queue) {
//add the thread to the run queue
list_add(run_queue,&init_run_queue);
}
/*Adds the current process to the wait queue */
static __inline__ void __sleep_on(struct wait_queue *wait_queue,struct wait_queue_head *wait_queue_head) {
add_waitqueue(wait_queue,wait_queue_head); //add to the waitqueue
remove_from_run_queue(¤t->run_queue); //remove from run queue
#ifdef DEBUG
fprintf(stderr,"Sleep On: Scheduling out Thread %d\n",current->pid);
#endif
schedule(); //schedule out the task
remove_waitqueue(wait_queue);
#ifdef DEBUG
fprintf(stderr,"Sleep On: Bringing in Thread %d\n",current->pid);
#endif
}
void sleep_on(struct wait_queue *wait_queue,struct wait_queue_head *wait_queue_head) {
current->state = TASK_UNINTERRUPTIBLE; //sets it to uninterruptible
//setup the wait_queue entry
init_waitqueue_entry(wait_queue,current);
__sleep_on(wait_queue,wait_queue_head);
//we are here when the scheduled out thread starts running
}
void interruptible_sleep_on(struct wait_queue *wait_queue,struct wait_queue_head *wait_queue_head) {
current->state = TASK_INTERRUPTIBLE;
init_waitqueue_entry(wait_queue,current); //initialise a waitqueue entry with the current task
__sleep_on(wait_queue,wait_queue_head); //go for an interruptible sleep
//we are here when the scheduled out thread starts running
return ;
}
/*Uninterruptible version of wake_up*/
static __inline__ void __wake_up(struct wait_queue_head *wait_queue_head) {
//loop through the threads in the wait queue and wake them up
struct list_head *head = &wait_queue_head->wait_queue_head;
struct list_head *traverse;
//go through the threads in the wait queue and add them to the run queue
list_for_each(traverse,head) {
struct wait_queue *wait_queue = list_entry(traverse,struct wait_queue,wait_queue_head); //get the wait_queue element
struct task_struct *task = wait_queue->task; //get the thread
if(task) {
task->state = TASK_RUNNING;//change the state of the TASK
fprintf(stderr,"Adding Thread(%d) to the run queue:\n",task->pid);
add_to_run_queue(&task->run_queue); //add the thread to the run queue
}
}
return ;
}
/*Wake up guys in the wait queue*/
void wake_up(struct wait_queue_head *wait_queue_head) {
__wake_up(wait_queue_head);
return;
}
void wake_up_interruptible(struct wait_queue_head *wait_queue_head) {
wake_up(wait_queue_head); //just call wake up
return ;
}