1/* 2 * Copyright (c) 2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <sys/shm.h> 12#include <assert.h> 13#include <stdbool.h> 14#include <errno.h> 15#include <stdio.h> 16#include <barrelfish/barrelfish.h> 17#include <octopus/init.h> 18#include <octopus/capability_storage.h> 19#include <vfs/fdtab.h> 20#include "posixcompat.h" 21 22struct _shm { 23 struct shmid_ds ds; 24 bool used; 25 key_t key; 26 struct capref frame; 27}; 28 29struct _shmap { 30 bool used; 31 void *mem; 32 int id; 33}; 34 35#define MAX_SHMS 32 36 37struct _shm shms[MAX_SHMS]; 38struct _shmap shmaps[MAX_SHMS]; 39 40void *shmat(int shmid, const void *shmaddr, int shmflg) 41{ 42 assert(shmid >= 0 && shmid < MAX_SHMS); 43 struct _shm *s = &shms[shmid]; 44 errval_t err; 45 46 printf("%s:%s:%d: shmid = %d, shmaddr= %p, shmflg = %d\n", 47 __FILE__, __FUNCTION__, __LINE__, shmid, shmaddr, shmflg); 48 49 struct frame_identity id; 50 vregion_flags_t attr; 51 52 int i; 53 54 for(i = 0; i < MAX_SHMS; i++) { 55 if(!shmaps[i].used) { 56 break; 57 } 58 } 59 60 if(i == MAX_SHMS) { 61 // Out of space for mappings 62 errno = ENOSPC; 63 return NULL; 64 } 65 66 struct _shmap *m = &shmaps[i]; 67 68 err = frame_identify(s->frame, &id); 69 if(err_is_fail(err)) { 70 USER_PANIC_ERR(err, "frame_identify"); 71 } 72 73 if(shmflg & SHM_RDONLY) { 74 attr = VREGION_FLAGS_READ; 75 } else { 76 attr = VREGION_FLAGS_READ_WRITE; 77 } 78 79 if(shmaddr != NULL) { 80 err = vspace_map_one_frame_fixed_attr((lvaddr_t)shmaddr, id.bytes, 81 s->frame, attr, NULL, NULL); 82 m->mem = (void *)shmaddr; 83 } else { 84 err = vspace_map_one_frame_attr(&m->mem, id.bytes, s->frame, 85 attr, NULL, NULL); 86 } 87 88 if(err_is_fail(err)) { 89 DEBUG_ERR(err, "vspace_map_one_frame_(fixed_)attr"); 90 // XXX: Probably cause it didn't fit the virtual address space 91 m->mem = NULL; 92 errno = ENOMEM; 93 return NULL; 94 } 95 96 s->ds.shm_nattch++; 97 m->used = true; 98 m->id = shmid; 99 100 POSIXCOMPAT_DEBUG("shmat(%d, %p, %d) = %p\n", 101 shmid, shmaddr, shmflg, m->mem); 102 return m->mem; 103} 104 105int shmget(key_t key, size_t size, int shmflg) 106{ 107 int i; 108 bool newkey = true; 109 110 // XXX: Private key not supported yet 111 assert(key != IPC_PRIVATE); 112 113 POSIXCOMPAT_DEBUG("key is not ipc_private\n"); 114 for(i = 0; i < MAX_SHMS; i++) { 115 if(shms[i].used && shms[i].key == key) { 116 newkey = false; 117 break; 118 } 119 } 120 121 if(i == MAX_SHMS) { 122 // Allocate an SHM descriptor 123 for(i = 0; i < MAX_SHMS; i++) { 124 if(!shms[i].used && shms[i].ds.shm_nattch == 0) { 125 break; 126 } 127 } 128 } 129 130 if(i == MAX_SHMS) { 131 // Out of descriptors 132 errno = ENOSPC; 133 return -1; 134 } 135 136 if (newkey) { 137 struct _shm *s = &shms[i]; 138 char skey[128]; 139 snprintf(skey, 128, "%lu", key); 140 141 POSIXCOMPAT_DEBUG("get capability %s\n", skey); 142 oct_init(); // XXX: do some posixcompat initialization 143 // XXX: Not multi-processing safe! 144 errval_t err = oct_get_capability(skey, &s->frame); 145 if(err_is_fail(err) && err_no(err) != OCT_ERR_CAP_NAME_UNKNOWN) { 146 USER_PANIC_ERR(err, "oct_get_capability"); 147 } 148 if(err == OCT_ERR_CAP_NAME_UNKNOWN) { 149 if(!(shmflg & IPC_CREAT)) { 150 errno = ENOENT; 151 return -1; 152 } 153 154 // Allocate frame (don't map it yet) 155 err = frame_alloc(&s->frame, size, NULL); 156 if(err_is_fail(err)) { 157 DEBUG_ERR(err, "frame_alloc"); 158 if(err_no(err) == LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS) { 159 errno = ENOMEM; 160 } 161 return -1; 162 } 163 164 char buffer[1024]; 165 debug_print_cap_at_capref(buffer, 1024, s->frame); 166 POSIXCOMPAT_DEBUG("%s:%d: store cap skey=%s capability=%s\n", 167 __FILE__, __LINE__, skey, buffer); 168 // XXX: This can fail if someone else won the race 169 err = oct_put_capability(skey, s->frame); 170 if(err_is_fail(err)) { 171 USER_PANIC_ERR(err, "oct_put_capability"); 172 } 173 174 s->ds.shm_nattch = 0; 175 } 176 177 // Assign to local cache 178 s->used = true; 179 s->key = key; 180 } 181 182 POSIXCOMPAT_DEBUG("shmget(%ld, %zu, %d) = %d\n", 183 key, size, shmflg, i); 184 185 return i; 186} 187 188int shmctl(int shmid, int cmd, struct shmid_ds *buf) 189{ 190 char skey[128]; 191 192 if(shmid < 0 || shmid >= MAX_SHMS) { 193 return -1; 194 } 195 196 struct _shm *s = &shms[shmid]; 197 198 if(!s->used) { 199 return -1; 200 } 201 202 POSIXCOMPAT_DEBUG("shmctl(%d, %d, %p)\n", shmid, cmd, buf); 203 204 switch(cmd) { 205 case IPC_STAT: 206 assert(!"NYI"); 207 break; 208 209 case IPC_SET: 210 assert(!"NYI"); 211 break; 212 213 case IPC_RMID: 214 snprintf(skey, 128, "%lu", s->key); 215 216 // This can fail if someone else won the race, but 217 // we don't really care, the key has been removed anyway 218 oct_init(); 219 oct_remove_capability(skey); 220 s->used = false; 221 break; 222 223 default: 224 return -1; 225 } 226 227 return 0; 228} 229 230int shmdt(const void *shmaddr) 231{ 232 struct _shm *s = NULL; 233 struct _shmap *m = NULL; 234 errval_t err; 235 236 int i; 237 for(i = 0; i < MAX_SHMS; i++) { 238 if(shmaps[i].used && shmaps[i].mem == shmaddr) { 239 m = &shmaps[i]; 240 break; 241 } 242 } 243 244 if(m == NULL) { 245 errno = EINVAL; 246 return -1; 247 } 248 249 POSIXCOMPAT_DEBUG("shmdt(%p)\n", shmaddr); 250 s = &shms[i]; 251 252 assert(s->ds.shm_nattch > 0); 253 254 err = vspace_unmap(shmaddr); 255 if(err_is_fail(err)) { 256 DEBUG_ERR(err, "vspace_unmap"); 257 return -1; 258 } 259 260 s->ds.shm_nattch--; 261 m->used = false; 262 263 if(s->ds.shm_nattch==0) 264 s->used = false; 265 266 return 0; 267} 268