+waitpid()
[meinos.git] / kernel2 / shm.c
blob08ab2f7758992da324e2d55ea405d56a611a470b
1 /*
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>
20 #include <ipc/shm.h>
21 #include <ipc.h>
22 #include <memuser.h>
23 #include <paging.h>
24 #include <errno.h>
25 #include <memphys.h>
26 #include <procm.h>
27 #include <stdint.h>
28 #include <malloc.h>
29 #include <syscall.h>
30 #include <perm.h>
31 #include <string.h>
32 #include <memmap.h>
33 #include <debug.h>
35 #define ipc_shm_permcheck(shm,op) (perm_check((shm)->ipc.owner->pid,(shm)->ipc.owner->gid,proc_current->uid,proc_current->gid,(shm)->ipc.mode,op) || proc_current->uid==(shm)->ipc.creator->uid)
36 #define ipc_shm_find(key,id) ipc_find(key,id,IPC_SHM)
38 /**
39 * Intitializes Shared Memory
40 * @return Success?
42 int ipc_shm_init() {
43 if (syscall_create(SYSCALL_IPC_SHM_GET,ipc_shm_get,1)==-1) return -1;
44 if (syscall_create(SYSCALL_IPC_SHM_CREATE,ipc_shm_create,4)==-1) return -1;
45 if (syscall_create(SYSCALL_IPC_SHM_ATTACH,ipc_shm_attach,4)==-1) return -1;
46 if (syscall_create(SYSCALL_IPC_SHM_DETACH,ipc_shm_detach,2)==-1) return -1;
47 if (syscall_create(SYSCALL_IPC_SHM_STAT,ipc_shm_stat,13)==-1) return -1;
48 if (syscall_create(SYSCALL_IPC_SHM_SET,ipc_shm_set,7)==-1) return -1;
49 if (syscall_create(SYSCALL_IPC_SHM_DESTROY,ipc_shm_destroy,1)==-1) return -1;
50 return 0;
53 /**
54 * Gets a shared memory object (Syscall)
55 * @param key IPC Key
56 * @return SHMID
58 id_t ipc_shm_get(key_t key) {
59 ipc_shm_t *shm = ipc_shm_find(key,-1);
60 if (shm==NULL) return -EINVAL;
61 else return shm->ipc.id;
64 /**
65 * Creates a shared memory object (Syscall)
66 * @param key IPC Key
67 * @param size Size
68 * @param flags Flags
69 * @param time Current time
70 * @return SHMID
72 id_t ipc_shm_create(key_t key,size_t size,int flags,time_t time) {
73 ipc_shm_t *shm = key!=IPC_PRIVATE?ipc_shm_find(key,-1):NULL;
74 if (shm==NULL) {
75 ipc_shm_t *new = malloc(sizeof(ipc_shm_t));
76 if (new!=NULL) {
77 size_t i;
78 memset(new,0,sizeof(ipc_shm_t));
79 new->ipc.type = IPC_SHM;
80 new->ipc.id = ipc_lastid++;
81 new->ipc.key = key;
82 new->ipc.owner = proc_current;
83 new->ipc.creator = proc_current;
84 new->ipc.mode = flags&0777;
85 new->size = size;
86 new->num_pages = ADDR2PAGE(PAGEUP(new->size));
87 new->phys = malloc(sizeof(void*)*new->num_pages);
88 for (i=0;i<new->num_pages;i++) new->phys[i] = memphys_alloc();
89 new->atts = llist_create();
90 new->lopid = proc_current->pid;
91 llist_push(ipc_objects,new);
92 return new->ipc.id;
94 else return -ENOSPC;
96 else return -EEXIST;
99 /**
100 * Attaches process to shared memory object (Syscall)
101 * @param id SHMID
102 * @param virt Virtual address to attatch to
103 * @param flags Flags
104 * @return Success?
106 int ipc_shm_attach(id_t id,const void **addr,int flags,time_t time) {
107 void *virt = (void*)*addr;
108 if (virt>=(void*)USERDATA_ADDRESS || virt==NULL) {
109 ipc_shm_t *shm = ipc_shm_find(-1,id);
110 if (shm!=NULL) {
111 ipc_shm_att_t *new = malloc(sizeof(ipc_shm_att_t));
112 if (new!=NULL) {
113 size_t i;
114 new->shm = shm;
115 new->proc = proc_current;
116 new->virt = virt==NULL?memuser_findvirt(proc_current->addrspace,shm->num_pages):(void*)virt;
117 new->readonly = flags&SHM_RDONLY;
118 if (virt==NULL) virt = memuser_findvirt(proc_current->addrspace,shm->num_pages);
119 for (i=0;i<shm->num_pages;i++) paging_map(new->virt+i*PAGE_SIZE,shm->phys[i],1,!new->readonly);
120 llist_push(shm->atts,new);
121 shm->atime = time;
122 shm->lopid = proc_current->pid;
123 *addr = virt;
124 return 0;
126 else return -ENOSPC;
129 return -EINVAL;
133 * Detaches process form shared memory object (Syscall)
134 * @param virt Virtual address to detach from
135 * @return Success?
137 int ipc_shm_detach(const void *virt,time_t time) {
138 size_t i,j,k;
139 ipc_shm_t *shm;
140 ipc_shm_att_t *att;
141 if (virt<(void*)USERDATA_ADDRESS) return -1;
142 for (i=0;(shm = llist_get(ipc_objects,i));i++) {
143 if (shm->ipc.type==IPC_SHM) {
144 for (j=0;(att = llist_get(shm->atts,j));j++) {
145 if (att->proc==proc_current && att->virt==virt) {
146 for (k=0;k<shm->num_pages;k++) paging_unmap(att->virt+k*PAGE_SIZE);
147 llist_remove(shm->atts,j);
148 free(att);
149 shm->atime = time;
150 shm->lopid = proc_current->pid;
151 return 0;
156 return -EINVAL;
159 int ipc_shm_stat(id_t id,uid_t *uid,gid_t *gid,uid_t *cuid,gid_t *cgid,mode_t *mode,size_t *segsz,pid_t *lpid,pid_t *cpid,size_t *nattch,time_t *atime,time_t *dtime,time_t *ctime) {
160 ipc_shm_t *shm = ipc_shm_find(-1,id);
161 if (shm!=NULL) {
162 if (ipc_shm_permcheck(shm,PERM_R)) {
163 *uid = shm->ipc.owner->uid;
164 *gid = shm->ipc.owner->gid;
165 *cuid = shm->ipc.creator->uid;
166 *cgid = shm->ipc.creator->gid;
167 *cpid = shm->ipc.creator->pid;
168 *mode = shm->ipc.mode;
169 *segsz = shm->size;
170 *lpid = shm->lopid;
171 *nattch = llist_size(shm->atts);
172 *atime = shm->atime;
173 *dtime = shm->dtime;
174 *ctime = shm->ctime;
175 return 0;
177 else return -EACCES;
179 return -EINVAL;
182 int ipc_shm_set(id_t id,uid_t uid,gid_t gid,mode_t mode,time_t time) {
183 ipc_shm_t *shm = ipc_shm_find(-1,id);
184 if (shm!=NULL) {
185 if (ipc_shm_permcheck(shm,PERM_W)) {
186 shm->ipc.mode = mode;
187 shm->ctime = time;
188 return 0;
190 else return -EACCES;
192 return -EINVAL;
196 * Destroys a shared memory object
197 * @param id SHMID
198 * @return Success
200 int ipc_shm_destroy(id_t id) {
201 ipc_shm_t *shm = ipc_shm_find(-1,id);
202 if (shm!=NULL) {
203 ipc_shm_att_t *att;
204 size_t i;
205 while ((att = llist_pop(shm->atts))) {
206 for (i=0;i<shm->num_pages;i++) paging_unmap(att->virt+i*PAGE_SIZE);
207 free(att);
209 for (i=0;i<shm->num_pages;i++) memphys_free(shm->phys[i]);
210 free(shm->phys);
211 free(shm);
212 llist_remove(ipc_objects,llist_find(ipc_objects,shm));
213 return 0;
215 return -1;