diff --git a/libc/src/sys/ipc.c b/libc/src/sys/ipc.c index acd2582..861f849 100644 --- a/libc/src/sys/ipc.c +++ b/libc/src/sys/ipc.c @@ -3,6 +3,7 @@ /// @copyright (c) 2014-2023 This file is distributed under the MIT License. /// See LICENSE.md for details. +#include "sys/ipc.h" #include "sys/unistd.h" #include "sys/errno.h" #include "sys/stat.h" @@ -33,12 +34,32 @@ _syscall4(long, semctl, int, semid, int, semnum, int, cmd, union semun *, arg) _syscall2(int, msgget, key_t, key, int, msgflg) -_syscall4(int, msgsnd, int, msqid, const void *, msgp, size_t, msgsz, int, msgflg) - -_syscall5(ssize_t, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long, msgtyp, int, msgflg) - _syscall3(int, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf) +int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) +{ + long __res; + do { + __inline_syscall4(__res, msgsnd, msqid, msgp, msgsz, msgflg); + if (!(msgflg & IPC_NOWAIT) && (__res == -EAGAIN)) + continue; + break; + } while (1); + __syscall_return(int, __res); +} + +ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) +{ + long __res; + do { + __inline_syscall5(__res, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg); + if (!(msgflg & IPC_NOWAIT) && ((__res == -EAGAIN) || (__res == -ENOMSG))) + continue; + break; + } while (1); + __syscall_return(int, __res); +} + long semop(int semid, struct sembuf *sops, unsigned nsops) { struct sembuf *op; diff --git a/mentos/src/ipc/msg.c b/mentos/src/ipc/msg.c index 7e93b87..377a91d 100644 --- a/mentos/src/ipc/msg.c +++ b/mentos/src/ipc/msg.c @@ -16,6 +16,7 @@ #include "io/debug.h" // Include debugging functions. // ============================================================================ +#include "process/scheduler.h" #include "process/process.h" #include "system/panic.h" #include "sys/errno.h" @@ -284,7 +285,7 @@ int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) // The message queue doesn't exist. if (!msq_info) { pr_err("The message queue does not exist.\n"); - return -EINVAL; + return -EIDRM; } // Check if the message queue exists for the given key, but the calling // process does not have permission to access the set. @@ -293,9 +294,10 @@ int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) "calling process does not have permission to access the set.\n"); return -EACCES; } + // Check if the message can't be sent due to the msg_qbytes limit for the + // queue. if (((msq_info->msqid.msg_cbytes + msgsz) >= msq_info->msqid.msg_qbytes)) { - pr_err("The message can't be sent due to the message queue limit.\n"); - return -EFAULT; + return -EAGAIN; } // Allocate the memory for the message. struct msg *message = (struct msg *)kmalloc(sizeof(struct msg)); @@ -371,7 +373,7 @@ ssize_t sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) // The message queue doesn't exist. if (!msq_info) { pr_err("The message queue does not exist.\n"); - return -EINVAL; + return -EIDRM; } // Check if the message queue exists for the given key, but the calling // process does not have permission to access the set. @@ -415,7 +417,7 @@ ssize_t sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) } } if (message == NULL) { - pr_err("There are no messages to read.\n"); + // pr_err("There are no messages to read.\n"); return -ENOMSG; } // Check if the message is longer than msgsz. @@ -463,7 +465,52 @@ ssize_t sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf) { - TODO("Not implemented"); + msq_info_t *msq_info = NULL; + task_struct *task = NULL; + // The msqid is less than zero. + if (msqid < 0) { + pr_err("The msqid is less than zero.\n"); + return -EINVAL; + } + // Search for the message queue. + msq_info = __list_find_msq_info_by_id(msqid); + // The message queue doesn't exist. + if (!msq_info) { + pr_err("The message queue does not exist.\n"); + return -EIDRM; + } + // Get the calling task. + task = scheduler_get_current_process(); + assert(task && "Failed to get the current running process."); + + if (cmd == IPC_RMID) { + // Remove the message queue; any processes blocked is awakened (errno set to + // EIDRM); no argument required. + + if ((msq_info->msqid.msg_perm.uid != task->uid) && (msq_info->msqid.msg_perm.cuid != task->uid)) { + pr_err("The calling process is not the creator or the owner of the queue.\n"); + return -EPERM; + } + // Remove the info from the list. + __list_remove_msq_info(msq_info); + // Delete the info. + __msq_info_dealloc(msq_info); + } else if (cmd == IPC_STAT) { + // Place a copy of the msqid_ds data structure in the buffer pointed to + // by buf. + // Check if the buffer is a null pointer. + if (!buf) { + pr_err("The buffer is NULL.\n"); + return -EINVAL; + } + // Check permissions. + if (!ipc_valid_permissions(O_RDONLY, &msq_info->msqid.msg_perm)) { + pr_err("The calling process does not have read permission to access the queue.\n"); + return -EACCES; + } + // Copying all the data. + memcpy(buf, &msq_info->msqid, sizeof(struct msqid_ds)); + } return 0; } diff --git a/programs/tests/t_msgget.c b/programs/tests/t_msgget.c index fb188d1..f25d640 100644 --- a/programs/tests/t_msgget.c +++ b/programs/tests/t_msgget.c @@ -67,6 +67,25 @@ int main(int argc, char *argv[]) // Display the message. printf("We received the message `%s`\n", message.mesg_text); + // ======================================================================== + // Create child process. + if (!fork()) { + sleep(3); + + // Set the content. + strcpy(message.mesg_text, "Hello there, i'm the child!"); + + // Display the message. + printf("I, the child, I'm sending the message `%s`\n", message.mesg_text); + + // Send the message. + if (msgsnd(msqid, &message, sizeof(message), 0) < 0) { + perror("Failed to send the message"); + return 1; + } + return 0; + } + // Clear the user-defined message. memset(message.mesg_text, 0, sizeof(char) * MESSAGE_LEN); // Receive the message. @@ -77,5 +96,11 @@ int main(int argc, char *argv[]) // Display the message. printf("We received the message `%s`\n", message.mesg_text); + // Delete the message queue. + ret = msgctl(msqid, IPC_RMID, NULL); + if (ret < 0) { + perror("Failed to remove message queue."); + } + printf("Correctly removed message queue.\n"); return 0; }