nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
semaphore.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdint.h>
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stddef.h>
6 #include <time.h>
7 #include <semaphore.h>
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <pthread.h>
11 
12 #include <interrupt.h>
13 
14 #include <list.h>
15 #include <object.h>
16 #include <thread.h>
17 #include <semaphore0.h>
18 
22 struct sem {
23  struct list_head list; /* 세마포어 락에 걸린 쓰레드들 목록 */
24  int pshared;
25  volatile int value;
26 };
27 
28 struct sem_list_info {
29  struct list_head head;
30  struct thread *tcb;
31 };
32 
33 int sem_init(sem_t *_sem, int pshared, unsigned int value)
34 {
35  struct sem *sem;
36  assert(_sem && "Invalid argument");
37 
38  sem = malloc(sizeof(*sem));
39  if (!sem) {
40  return -ENOMEM;
41  }
42 
43  sem->pshared = pshared;
44  sem->value = value;
45 
46  INIT_LIST_HEAD(&sem->list);
47 
48  *_sem = sem;
49  return 0;
50 }
51 
52 int sem_destroy(sem_t *_sem)
53 {
54  struct sem *sem;
55  struct list_head *pos;
56  struct list_head *n;
57  struct sem_list_info *info;
58  assert(_sem && "Invalid argument");
59 
60  sem = *_sem;
61  if (!sem) {
62  return -EINVAL;
63  }
64 
65  list_for_each_safe(pos, n, &sem->list) {
66  list_del(pos);
67  info = list_entry(pos, struct sem_list_info, head);
68 
69  assert(info->tcb && "TCB is not valid");
70  assert(info->tcb->sem == sem && "Invalid semaphore");
71  info->tcb->sem = NULL;
72  free(info);
73  }
74 
75  free(sem);
76  *_sem = NULL;
77  return 0;
78 }
79 
80 int sem_post(sem_t *_sem)
81 {
82  struct sem *sem;
83  unsigned long flags;
84  assert(_sem && "Invalid argument");
85 
86  sem = *_sem;
87  if (!sem) {
88  return -EINVAL;
89  }
90 
91  irq_local_save(&flags);
92  if (++sem->value >= 0) {
93  struct list_head *pos;
94  struct sem_list_info *info;
95 
96  pos = LIST_NEXT(&sem->list);
97  if (pos == &sem->list) {
98  goto out;
99  }
100 
101  list_del(pos);
102  info = list_entry(pos, struct sem_list_info, head);
103  assert(info->tcb && "TCB is not valid");
104  assert((sem == info->tcb->sem) && "Sempahore is not matched");
105 
106  info->tcb->sem = NULL;
107  free(info);
108  }
109 out:
110  irq_local_restore(flags);
111  return 0;
112 }
113 
114 int sem_wait(sem_t *_sem)
115 {
116  struct sem *sem;
117  unsigned long flags;
118  assert(_sem && "Invalid argument");
119 
120  sem = *_sem;
121  if (!sem) {
122  return -EINVAL;
123  }
124 
125  irq_local_save(&flags);
126  if (--sem->value < 0) {
127  struct sem_list_info *info;
128 
129  info = malloc(sizeof(*info));
130  if (!info) {
131  sem->value++;
132  irq_local_restore(flags);
133  return -ENOMEM;
134  }
135 
136  info->tcb = pthread_self();
137  assert(info->tcb && "TCB is not valid");
138  assert(!info->tcb->sem && "TCB's sem is not cleared");
139 
140  info->tcb->sem = sem;
141  list_add_tail(&info->head, &sem->list);
142  irq_local_restore(flags);
143  while (sem->value < 0) {
144  }
145  irq_local_save(&flags);
146  }
147 
148  irq_local_restore(flags);
149  return 0;
150 }
151 
152 int sem_trywait(sem_t *_sem)
153 {
154  struct sem *sem;
155  unsigned long flags;
156  assert(_sem && "Invalid argument");
157 
158  sem = *_sem;
159  if (!sem) {
160  return -EINVAL;
161  }
162 
163  irq_local_save(&flags);
164  if ((sem->value - 1) < 0) {
165  irq_local_restore(flags);
166  return -EBUSY;
167  }
168  sem->value--;
169  irq_local_restore(flags);
170  return 0;
171 }
172 
173 int sem_timedwait(sem_t *_sem, const struct timespec *abs_timeout)
174 {
175  struct sem *sem;
176  assert(_sem && "Invalid argument");
177 
178  sem = *_sem;
179  if (!sem) {
180  return -EINVAL;
181  }
182 
183  return -ENOSYS;
184 }
185 
186 int sem_getvalue(sem_t *_sem, int *val)
187 {
188  struct sem *sem;
189  assert(val && _sem && "Invalid argument");
190 
191  sem = *_sem;
192  if (!sem) {
193  return -EINVAL;
194  }
195 
196  *val = sem->value;
197  return 0;
198 }
199 
204 void sem_clear(struct thread *tcb)
205 {
206  struct sem *sem;
207  struct sem_list_info *info;
208  struct list_head *pos;
209  struct list_head *n;
210 
211  if (!tcb->sem) {
212  return;
213  }
214 
215  sem = tcb->sem;
216  list_for_each_safe(pos, n, &sem->list) {
217  info = list_entry(pos, struct sem_list_info, head);
218  if (info->tcb == tcb) {
219  list_del(pos);
220  free(info);
221  break;
222  }
223  }
224 
225  return;
226 }
227 
228 /* End of a file */