哈工大 操作系统 lab4 信号量的实现和应用解答
所需数据结构(定义在头文件中,用户也需要知道):
#define SEM_FAILED (void*) 0
#define SEM_NAME_MAX_LEN 16
#define SEM_QUEUE_LEN 16
struct semaphore_queue {
int front;
int rear;
struct task_struct* wait_tasks[SEM_QUEUE_LEN];
};
typedef struct semaphore_queue sem_queue;
struct semaphore_t {
int val;
int open_flag;
char name[SEM_NAME_MAX_LEN];
sem_queue wait_queue;
};
typedef struct semaphore_t sem_t;
对上述数据结构的一些基本操作(实现了一个循环队列):
#define __LIBRARY__
#include <unistd.h> /* type def */
#include <linux/sched.h> /* schedule */
#include <linux/kernel.h> /* printk */
#include <asm/segment.h> /* get_fs_byte */
#include <asm/system.h> /* sti cli */
#define SEM_COUNT 32
sem_t semaphores[SEM_COUNT];
void init_queue(sem_queue* q) {
q->front = q->rear = 0;
}
int empty(sem_queue* q) {
return q->front == q->rear ? 1 : 0;
}
int full(sem_queue* q) {
return (q->rear + 1) % SEM_QUEUE_LEN == q->front ? 1 : 0;
}
struct task_struct* front(sem_queue* q) {
if(empty(q)) {
printk("front fail! no task in queue\n");
return NULL;
}
struct task_struct *tmp = q->wait_tasks[q->front];
return tmp;
}
void pop(sem_queue* q) {
if (empty(q)) {
printk("pop fail! no task in queue!\n");
return;
}
q->front = (q->front + 1) % SEM_QUEUE_LEN;
}
void push(sem_queue* q, struct task_struct* p) {
if (full(q)) {
printk("push fail! queue is full!\n");
return;
}
q->wait_tasks[q->rear] = p;
q->rear = (q->rear + 1) % SEM_QUEUE_LEN;
}
int sem_exit(const char* name) {
int i = 0;
for (i = 0; i < SEM_COUNT; ++i) {
if (semaphores[i].open_flag == 1 && strcmp(name, semaphores[i].name) == 0) {
return i;
}
}
return -1;
}
sem_open
实现:
sem_t* sys_sem_open(const char* name, unsigned int value) {
char buffer[SEM_NAME_MAX_LEN];
int i = 0;
for (i = 0; i < SEM_NAME_MAX_LEN; ++i) {
buffer[i] = get_fs_byte(name + i);
if (buffer[i] == '\0') {
break;
}
}
if (i >= SEM_NAME_MAX_LEN) {
printk("name too long!\n");
return NULL;
}
int idx = sem_exit(buffer);
if (idx != -1) { // exits
return &semaphores[idx];
}
// not exits
for (i = 0; i < SEM_COUNT; ++i) {
if (semaphores[i].open_flag == 0) {
strcpy(semaphores[i].name, buffer);
semaphores[i].open_flag = 1;
semaphores[i].val = value;
init_queue(&(semaphores[i].wait_queue));
return &semaphores[i];
}
}
// can't find a slot
printk("MAX SEMAPHORE's NUMBER IS %d, NOW FULL!\n", SEM_COUNT);
return NULL;
}
sem_unlink
实现:
int sys_sem_unlink(const char *name) {
char buffer[SEM_NAME_MAX_LEN];
int i = 0;
for (i = 0; i < SEM_NAME_MAX_LEN; ++i) {
buffer[i] = get_fs_byte(name + i);
if (buffer[i] == '\0') {
break;
}
}
if (i >= SEM_NAME_MAX_LEN) {
printk("name too long!\n");
return -1;
}
int idx = sem_exit(buffer);
if (idx == -1) { // not exits
printk("SEM %s NOT EXIT\n", buffer);
return -1;
}
semaphores[idx].val = 0;
semaphores[idx].open_flag = 0;
strcpy(semaphores[idx].name, "\0");
return 0;
}
sem_wait
实现:
int sys_sem_wait(sem_t* sem) {
if (sem == NULL) {
return -1;
}
cli();
if (--sem->val < 0) {
current->state = TASK_UNINTERRUPTIBLE;
push(&(sem->wait_queue), current);
schedule();
}
sti();
return 0;
}
sem_wait
实现:
int sys_sem_post(sem_t* sem) {
if (sem == NULL) {
return -1;
}
cli();
if (++sem->val <= 0) {
struct task_struct* p = front(&(sem->wait_queue));
if (p != NULL) {
pop(&(sem->wait_queue));
p->state = TASK_RUNNING;
}
}
sti();
return 0;
}
然后按添加系统调用的流程添加上系统调用即可。
有一个比较坑的地方是,添加的系统调用可能没用,编译不过去(拷贝个unistd.h
到linux0.11即可)。