哈工大 操作系统 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即可)。

posted @ 2022-04-19 20:19  zju_cxl  阅读(47)  评论(0编辑  收藏  举报