2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
29 #define ipc_msg_find(key,id) ipc_find(key,id,IPC_MSG)
32 if (syscall_create(SYSCALL_IPC_MSG_GET
,ipc_msg_get
,1)==-1) return -1;
33 if (syscall_create(SYSCALL_IPC_MSG_CREATE
,ipc_msg_create
,3)==-1) return -1;
34 if (syscall_create(SYSCALL_IPC_MSG_DESTROY
,ipc_msg_destroy
,2)==-1) return -1;
35 if (syscall_create(SYSCALL_IPC_MSG_SEND
,ipc_msg_send
,6)==-1) return -1;
36 if (syscall_create(SYSCALL_IPC_MSG_RECV
,ipc_msg_recv
,6)==-1) return -1;
41 * Gets MSQID by key (Syscall)
45 id_t
ipc_msg_get(key_t key
) {
46 ipc_msg_t
*msg
= ipc_msg_find(key
,-1);
47 if (msg
==NULL
) return -1;
52 * Creates a Message Queue (Syscall)
55 * @param time Current time
58 id_t
ipc_msg_create(key_t key
,mode_t mode
,time_t time
) {
59 ipc_msg_t
*msg
= key
!=IPC_PRIVATE
?ipc_msg_find(key
,-1):NULL
;
61 ipc_msg_t
*new = malloc(sizeof(ipc_msg_t
));
63 memset(new,0,sizeof(ipc_msg_t
));
64 new->ipc
.type
= IPC_MSG
;
66 new->ipc
.owner
= proc_current
;
67 new->ipc
.creator
= proc_current
;
68 new->ipc
.id
= ipc_lastid
++;
70 new->msgs
= llist_create();
71 new->waiting
= llist_create();
73 llist_push(ipc_objects
,new);
81 * Destroys a message queue (Syscall)
82 * @param id ID of message queue
85 int ipc_msg_destroy(id_t id
) {
86 ipc_msg_t
*msq
= ipc_msg_find(-1,id
);
88 if (perm_check(proc_current
->pid
,proc_current
->gid
,msq
->ipc
.owner
->uid
,msq
->ipc
.owner
->gid
,msq
->mode
,PERM_W
)) {
91 while ((msg
= llist_pop(msq
->msgs
))!=NULL
) {
92 if ((msg
->flags
&IPC_NOWAIT
)!=msg
->flags
) proc_wake(msg
->sender
);
96 while ((waiter
= llist_pop(msq
->waiting
))!=NULL
) proc_wake(waiter
);
97 llist_remove(ipc_objects
,llist_find(ipc_objects
,msq
));
107 * Sends a message (Syscall)
109 * @param msg Message data
110 * @param msgsz Message size
111 * @param type Message type
113 * @param time Current time
116 int ipc_msg_send(id_t id
,void *data
,size_t msgsz
,long type
,int flags
,time_t time
) {
118 ipc_msg_t
*msq
= ipc_msg_find(-1,id
);
120 if (perm_check(proc_current
->pid
,proc_current
->gid
,msq
->ipc
.owner
->uid
,msq
->ipc
.owner
->gid
,msq
->mode
,PERM_W
)) {
121 ipc_msg_msg_t
*new = malloc(sizeof(ipc_msg_msg_t
));
123 new->data
= memcpy(malloc(msgsz
),data
,msgsz
);
127 new->sender
= proc_current
;
128 msq
->lspid
= proc_current
->pid
;
130 llist_push(msq
->msgs
,new);
131 while ((waiter
= llist_pop(msq
->waiting
))!=NULL
) proc_wake(waiter
);
132 if ((flags
&IPC_NOWAIT
)!=flags
) proc_sleep(proc_current
);
141 * Receives a message (Syscall)
143 * @param data Buffer for message data
144 * @param msgsz Size of buffer
145 * @param type Type message must have
147 * @param time Current time
148 * @return Number of bytes received
149 * @todo Get first message with type, not first absolute message
151 ssize_t
ipc_msg_recv(id_t id
,void *data
,size_t msgsz
,long type
,int flags
,time_t time
) {
152 ipc_msg_t
*msq
= ipc_msg_find(-1,id
);
154 if (perm_check(proc_current
->pid
,proc_current
->gid
,msq
->ipc
.owner
->uid
,msq
->ipc
.owner
->gid
,msq
->mode
,PERM_R
)) {
157 for (i
=0;(msg
= llist_get(msq
->msgs
,i
));i
++) {
158 if (msg
->type
==type
|| type
==0 || (type
<0 && msg
->type
<=-type
)) {
159 size_t count
= msgsz
>msg
->size
?msg
->size
:msgsz
;
160 memcpy(data
,msg
->data
,count
);
161 if ((msg
->flags
&IPC_NOWAIT
)==flags
) proc_wake(msg
->sender
);
162 msq
->lrpid
= proc_current
->pid
;
169 if (!(flags
&IPC_NOWAIT
)) {
170 llist_push(msq
->waiting
,proc_current
);
171 proc_sleep(proc_current
);
172 return 0; // try again after sleeping
182 * Gets information about a message queue (Syscall)
184 * @param uid Reference for owner's UID
185 * @param gid Reference for owner's GID
186 * @param cuid Reference for creator's UID
187 * @param cgid Reference for creator's GID
188 * @param mode Reference for mode
189 * @param num Reference for number of messages
190 * @param lspid Reference for last sender's PID
191 * @param lrpid Reference for last receiver's PID
192 * @param stime Reference for last send time
193 * @param rtime Reference for last receive time
194 * @param ctime Reference for last change time
197 int msg_stat(id_t id
,uid_t
*uid
,gid_t
*gid
,uid_t
*cuid
,gid_t
*cgid
,mode_t
*mode
,size_t *num
,pid_t
*lspid
,pid_t
*lrpid
,time_t *stime
,time_t *rtime
,time_t *ctime
) {
198 ipc_msg_t
*msq
= ipc_msg_find(-1,id
);
200 *uid
= msq
->ipc
.owner
->uid
;
201 *gid
= msq
->ipc
.owner
->gid
;
202 *cuid
= msq
->ipc
.creator
->uid
;
203 *cgid
= msq
->ipc
.creator
->gid
;
205 *num
= llist_size(msq
->msgs
);
217 * Changes information of a message queue (Syscall)
219 * @param uid Owner's UID
220 * @param gid Owner's GID
221 * @param mode Permissions
222 * @param time Current time
225 int msg_set(id_t id
,uid_t uid
,gid_t gid
,mode_t mode
,time_t time
) {
226 ipc_msg_t
*msq
= ipc_msg_find(-1,id
);
228 if (perm_check(proc_current
->pid
,proc_current
->gid
,msq
->ipc
.owner
->uid
,msq
->ipc
.owner
->gid
,msq
->mode
,PERM_W
) || proc_current
==msq
->ipc
.creator
) {