Implement message send and receive functions.

This commit is contained in:
Enrico Fraccaroli (Galfurian)
2023-06-08 16:38:42 -04:00
parent 8f6ff5a59a
commit f515c44eb3
6 changed files with 234 additions and 31 deletions
+18 -10
View File
@@ -16,6 +16,12 @@
/// The default maximum size in bytes of a message queue.
#define MSGMNB 16384
/// Specify that we should not treat as an error if the message we are trying to
/// return to the user, is too big. That message will be truncated to fit the
/// user-defined reading buffer. If not specified, the message is kept in the
/// queue, and an error is returned.
#define MSG_NOERROR 010000
/// @brief Buffer to use with the message queue IPC.
struct msgbuf {
/// Type of the message.
@@ -70,7 +76,7 @@ int msq_init();
/// @param msgflg controls the behaviour of the function.
/// @return the message queue identifier, -1 on failure, and errno is set to
/// indicate the error.
long sys_msgget(key_t key, int msgflg);
int sys_msgget(key_t key, int msgflg);
/// @brief Used to send messages.
/// @param msqid the message queue identifier.
@@ -78,7 +84,7 @@ long sys_msgget(key_t key, int msgflg);
/// @param msgsz specifies the size in bytes of mtext.
/// @param msgflg specifies the action to be taken in case of specific events.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
/// @brief Used to receive messages.
/// @param msqid the message queue identifier.
@@ -90,15 +96,16 @@ int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
/// - msgtyp < 0: the first message of the lowest type that is less than or
/// equal to the absolute value of msgtyp is received.
/// @param msgflg specifies the action to be taken in case of specific events.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
ssize_t sys_msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
/// @return the number of bytes actually copied on success, -1 on failure and
/// errno is set to indicate the error.
ssize_t sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
/// @brief Message queue control operations.
/// @param msqid the message queue identifier.
/// @param cmd The command to perform.
/// @param buf used with IPC_STAT and IPC_SET.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
long sys_msgctl(int msqid, int cmd, struct msqid_ds *buf);
int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf);
#else
@@ -108,7 +115,7 @@ long sys_msgctl(int msqid, int cmd, struct msqid_ds *buf);
/// @param msgflg controls the behaviour of the function.
/// @return the message queue identifier, -1 on failure, and errno is set to
/// indicate the error.
long msgget(key_t key, int msgflg);
int msgget(key_t key, int msgflg);
/// @brief Used to send messages.
/// @param msqid the message queue identifier.
@@ -116,7 +123,7 @@ long msgget(key_t key, int msgflg);
/// @param msgsz specifies the size in bytes of mtext.
/// @param msgflg specifies the action to be taken in case of specific events.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
long msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
/// @brief Used to receive messages.
/// @param msqid the message queue identifier.
@@ -128,14 +135,15 @@ long msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
/// - msgtyp < 0: the first message of the lowest type that is less than or
/// equal to the absolute value of msgtyp is received.
/// @param msgflg specifies the action to be taken in case of specific events.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
long msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
/// @return the number of bytes actually copied on success, -1 on failure and
/// errno is set to indicate the error.
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
/// @brief Message queue control operations.
/// @param msqid the message queue identifier.
/// @param cmd The command to perform.
/// @param buf used with IPC_STAT and IPC_SET.
/// @return 0 on success, -1 on failure and errno is set to indicate the error.
long msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
#endif
+10 -10
View File
@@ -21,25 +21,25 @@
_syscall3(void *, shmat, int, shmid, const void *, shmaddr, int, shmflg)
_syscall3(long, shmget, key_t, key, size_t, size, int, flag)
_syscall3(long, shmget, key_t, key, size_t, size, int, flag)
_syscall1(long, shmdt, const void *, shmaddr)
_syscall1(long, shmdt, const void *, shmaddr)
_syscall3(long, shmctl, int, shmid, int, cmd, struct shmid_ds *, buf)
_syscall3(long, shmctl, int, shmid, int, cmd, struct shmid_ds *, buf)
_syscall3(long, semget, key_t, key, int, nsems, int, semflg)
_syscall3(long, semget, key_t, key, int, nsems, int, semflg)
_syscall4(long, semctl, int, semid, int, semnum, int, cmd, union semun *, arg)
_syscall4(long, semctl, int, semid, int, semnum, int, cmd, union semun *, arg)
_syscall2(long, msgget, key_t, key, int, msgflg)
_syscall2(int, msgget, key_t, key, int, msgflg)
_syscall4(long, msgsnd, int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg)
_syscall4(int, msgsnd, int, msqid, const void *, msgp, size_t, msgsz, int, msgflg)
_syscall5(long, msgrcv, int, msqid, struct msgbuf *, msgp, size_t, msgsz, long, msgtyp, int, msgflg)
_syscall5(ssize_t, msgrcv, int, msqid, void *, msgp, size_t, msgsz, long, msgtyp, int, msgflg)
_syscall3(long, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
_syscall3(int, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
long semop(int semid, struct sembuf *sops, unsigned nsops)
long semop(int semid, struct sembuf *sops, unsigned nsops)
{
struct sembuf *op;
long __res;
+116 -11
View File
@@ -6,13 +6,14 @@
// ============================================================================
// Setup the logging for this file (do this before any other include).
#include "klib/list_head.h"
#include "limits.h"
#include "mem/slab.h"
#include "stddef.h"
#include "sys/kernel_levels.h" // Include kernel log levels.
#include "system/syscall.h"
#define __DEBUG_HEADER__ "[IPCmsg]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#define __DEBUG_HEADER__ "[IPCmsg]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level.
#include "io/debug.h" // Include debugging functions.
// ============================================================================
#include "process/process.h"
@@ -170,6 +171,26 @@ static inline void __msq_info_push_message(msq_info_t *msq_info, struct msg *mes
msq_info->msg_last->msg_next = message;
}
static inline void __msq_info_remove_message(msq_info_t *msq_info, struct msg *message)
{
assert(msq_info && "Received a NULL pointer.");
assert(message && "Received a NULL pointer.");
if (msq_info->msg_first == message) {
msq_info->msg_first = message->msg_next;
} else {
for (struct msg *it = msq_info->msg_first; it; it = it->msg_next) {
if (it->msg_next == message) {
it->msg_next = message->msg_next;
break;
}
}
}
if (msq_info->msg_last == message)
msq_info->msg_last = NULL;
// Clear the pointer in message.
message->msg_next = NULL;
}
// ============================================================================
// SYSTEM FUNCTIONS
// ============================================================================
@@ -180,7 +201,7 @@ int msq_init()
return 0;
}
long sys_msgget(key_t key, int msgflg)
int sys_msgget(key_t key, int msgflg)
{
msq_info_t *msq_info = NULL;
// Need to find a unique key.
@@ -232,9 +253,10 @@ long sys_msgget(key_t key, int msgflg)
return msq_info->id;
}
int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
{
msq_info_t *msq_info = NULL;
struct msgbuf *_msgp = NULL;
// The msqid is less than zero.
if (msqid < 0) {
pr_err("The msqid is less than zero.\n");
@@ -245,6 +267,8 @@ int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
pr_err("The pointer to the caller-defined structure is NULL.\n");
return -EINVAL;
}
// Use the template to acess the message.
_msgp = (struct msgbuf *)msgp;
// The value of msgsz is negative.
if (msgsz <= 0) {
pr_err("The value of msgsz is negative.\n");
@@ -282,7 +306,7 @@ int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
// Initialize the pointer to the next.
message->msg_next = NULL;
// Copy the type of message.
message->msg_type = msgp->mtype;
message->msg_type = _msgp->mtype;
// Allocate the memory for the content of the message.
message->msg_ptr = (char *)kmalloc(msgsz);
if (message->msg_ptr == NULL) {
@@ -291,7 +315,7 @@ int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
return -ENOMEM;
}
// Copy the content of the message.
memcpy(message->msg_ptr, msgp->mtext, msgsz);
memcpy(message->msg_ptr, _msgp->mtext, msgsz);
// The length of the message.
message->msg_size = msgsz;
// Add the message to the queue.
@@ -306,12 +330,20 @@ int sys_msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
// Increment the number of messages in the message queue.
msq_info->msqid.msg_qnum += 1;
pr_debug("[%2d] msg_lspid: %2d, msg_lrpid: %2d, msg_qnum: %2d, msg_cbytes: %4d (%s)\n",
msq_info->id,
msq_info->msqid.msg_lspid,
msq_info->msqid.msg_lrpid,
msq_info->msqid.msg_qnum,
msq_info->msqid.msg_cbytes,
message->msg_ptr);
return 0;
}
ssize_t sys_msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
ssize_t sys_msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
{
msq_info_t *msq_info = NULL;
struct msgbuf *_msgp = NULL;
// The msqid is less than zero.
if (msqid < 0) {
pr_err("The msqid is less than zero.\n");
@@ -322,6 +354,8 @@ ssize_t sys_msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, in
pr_err("The pointer to the caller-defined structure is NULL.\n");
return -EINVAL;
}
// Use the template to acess the message.
_msgp = (struct msgbuf *)msgp;
// The value of msgsz is negative.
if (msgsz <= 0) {
pr_err("The value of msgsz is negative.\n");
@@ -346,17 +380,88 @@ ssize_t sys_msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, in
"calling process does not have read permission to access the set.\n");
return -EACCES;
}
// Prepare a structure for the message.
struct msg *message = NULL;
// If msgtyp is 0, then the first message in the queue is read.
if (msgtyp == 0) {
// Get the first message.
message = msq_info->msg_first;
}
// If msgtyp is greater than 0, then the first message in the queue of type
// msgtyp is read.
else if (msgtyp > 0) {
for (struct msg *it = msq_info->msg_first; it; it = it->msg_next) {
if (it->msg_type == msgtyp) {
message = it;
break;
}
}
}
// If msgtyp is less than 0, then the first message in the queue with the
// lowest type less than or equal to the absolute value of msgtyp will be
// read.
else {
long lowest_type = LONG_MAX;
for (struct msg *it = msq_info->msg_first; it; it = it->msg_next) {
if ((it->msg_type < abs(msgtyp)) && (it->msg_type < lowest_type)) {
lowest_type = it->msg_type;
}
}
for (struct msg *it = msq_info->msg_first; it; it = it->msg_next) {
if (it->msg_type == lowest_type) {
message = it;
break;
}
}
}
if (message == NULL) {
pr_err("There are no messages to read.\n");
return -ENOMSG;
}
// Check if the message is longer than msgsz.
if (message->msg_size > msgsz) {
// If we have the MSG_NOERROR flag, we return E2BIG and leave the
// message on the queue.
if (!(msgflg & MSG_NOERROR)) {
pr_err("The message we are trying to retrieve is too big.\n");
return -E2BIG;
}
// Otherwise, we truncate the message to msgsz.
}
// The number of bytes actually copied.
ssize_t actual_size = min(message->msg_size, msgsz);
// Copy the content of the message (we might truncate).
memcpy(_msgp->mtext, message->msg_ptr, actual_size);
// Update last receive time.
msq_info->msqid.msg_rtime = sys_time(NULL);
// Update pid of last process who issued a receive.
msq_info->msqid.msg_lrpid = sys_getpid();
// Update the total consumed space of the message queue.
msq_info->msqid.msg_cbytes -= message->msg_size;
// Decrement the number of messages in the message queue.
msq_info->msqid.msg_qnum -= 1;
TODO("Not implemented");
pr_debug("[%2d] msg_lspid: %2d, msg_lrpid: %2d, msg_qnum: %2d, msg_cbytes: %4d (%s)\n",
msq_info->id,
msq_info->msqid.msg_lspid,
msq_info->msqid.msg_lrpid,
msq_info->msqid.msg_qnum,
msq_info->msqid.msg_cbytes,
message->msg_ptr);
return 0;
// Remove the message to the queue.
__msq_info_remove_message(msq_info, message);
// Free the memory of the message.
kfree(message->msg_ptr);
// Free the memory of the data structure.
kfree(message);
return actual_size;
}
long sys_msgctl(int msqid, int cmd, struct msqid_ds *buf)
int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf)
{
TODO("Not implemented");
return 0;
+7
View File
@@ -12,6 +12,13 @@ int main(int argc, char *argv[], char *envp[])
{
char *_argv[] = { "login", NULL };
if (fork() == 0) {
execv("/bin/tests/t_msgget", _argv);
printf("This is bad, I should not be here! EXEC NOT WORKING\n");
}
while (1) {}
if (fork() == 0) {
execv("/bin/login", _argv);
printf("This is bad, I should not be here! EXEC NOT WORKING\n");
+2
View File
@@ -88,6 +88,8 @@ set(TESTS
t_semget.c
t_semflg.c
t_semop.c
# Test message queues.
t_msgget.c
# Test scheduling feedback tests.
t_schedfb.c
)
+81
View File
@@ -0,0 +1,81 @@
/// @file t_msgget.c
/// @brief This program creates a message queue.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "string.h"
#include "sys/unistd.h"
#include "sys/errno.h"
#include "sys/msg.h"
#include "sys/ipc.h"
#include "stdlib.h"
#include "fcntl.h"
#include "stdio.h"
#define MESSAGE_LEN 100
// structure for message queue
typedef struct {
long mesg_type;
char mesg_text[MESSAGE_LEN];
} message_t;
int main(int argc, char *argv[])
{
message_t message;
long ret, msqid;
key_t key;
// ========================================================================
// Generating a key using ftok
key = ftok("/home/user/test7.txt", 5);
if (key < 0) {
perror("Failed to generate key using ftok");
return 1;
}
printf("Generated key using ftok (key = %d)\n", key);
// ========================================================================
// Create the first message queue.
msqid = msgget(key, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (msqid < 0) {
perror("Failed to create message queue");
return 1;
}
printf("Created message queue (id : %d)\n", msqid);
// Set the type.
message.mesg_type = 1;
// Set the content.
strcpy(message.mesg_text, "Hello there!");
// Send the message.
if (msgsnd(msqid, &message, sizeof(message), 0) < 0) {
perror("Failed to send the message");
return 1;
}
// Display the message.
printf("We sent the message `%s`\n", message.mesg_text);
// Clear the user-defined message.
memset(message.mesg_text, 0, sizeof(char) * MESSAGE_LEN);
// Receive the message.
if (msgrcv(msqid, &message, sizeof(message), 1, 0) < 0) {
perror("Failed to receive the message");
return 1;
}
// Display the message.
printf("We received the message `%s`\n", message.mesg_text);
// Clear the user-defined message.
memset(message.mesg_text, 0, sizeof(char) * MESSAGE_LEN);
// Receive the message.
if (msgrcv(msqid, &message, sizeof(message), 1, 0) < 0) {
perror("Failed to receive the message");
return 1;
}
// Display the message.
printf("We received the message `%s`\n", message.mesg_text);
return 0;
}