Fork me on GitHub

root/kernel/syscalls/shmget.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. shm_get_new_seg
  2. shm_release_seg
  3. free_seg
  4. shm_get_new_attach
  5. shm_release_attach
  6. shm_init
  7. sys_shmget

   1 /*
   2  * fiwix/kernel/syscalls/shmget.c
   3  *
   4  * Copyright 2022, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/kernel.h>
   9 #include <fiwix/types.h>
  10 #include <fiwix/string.h>
  11 #include <fiwix/errno.h>
  12 #include <fiwix/process.h>
  13 #include <fiwix/mm.h>
  14 #include <fiwix/ipc.h>
  15 #include <fiwix/shm.h>
  16 
  17 #ifdef __DEBUG__
  18 #include <fiwix/stdio.h>
  19 #endif /*__DEBUG__ */
  20 
  21 #ifdef CONFIG_SYSVIPC
  22 struct shmid_ds *shmseg[SHMMNI];
  23 unsigned int num_segs;
  24 unsigned int max_segid;
  25 unsigned int shm_seq;
  26 unsigned int shm_tot;
  27 unsigned int shm_rss;
  28 
  29 /* FIXME: this should be allocated dynamically */
  30 static struct shmid_ds shmseg_pool[SHMMNI];
  31 struct shmid_ds *shm_get_new_seg(void)
  32 {
  33         int n;
  34 
  35         for(n = 0; n < SHMMNI; n++) {
  36                 if(shmseg_pool[n].shm_ctime == 0) {
  37                         shmseg_pool[n].shm_ctime = 1;
  38                         if(!(shmseg_pool[n].shm_pages = (unsigned int *)kmalloc())) {
  39                                 return NULL;
  40                         }
  41                         memset_b(shmseg_pool[n].shm_pages, 0, PAGE_SIZE);
  42                         return &shmseg_pool[n];
  43                 }
  44         }
  45         return NULL;
  46 }
  47 
  48 void shm_release_seg(struct shmid_ds *seg)
  49 {
  50         kfree((unsigned int)seg->shm_pages);
  51         if(seg->shm_attaches) {
  52                 kfree((unsigned int)seg->shm_attaches);
  53         }
  54         memset_b(seg, 0, sizeof(struct shmid_ds));
  55 }
  56 
  57 void free_seg(int shmid)
  58 {
  59         struct shmid_ds *seg;
  60         int npages;
  61 
  62         seg = shmseg[shmid % SHMMNI];
  63         npages = (seg->shm_segsz + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  64         num_segs--;
  65         shm_tot -= npages;
  66         shm_seq++;
  67         shmseg[shmid % SHMMNI] = (struct shmid_ds *)IPC_UNUSED;
  68         if((shmid % SHMMNI) == max_segid) {
  69                 while(max_segid) {
  70                         if(shmseg[max_segid] != IPC_UNUSED) {
  71                                 break;
  72                         }
  73                         max_segid--;
  74                 }
  75         }
  76         shm_release_seg(seg);
  77 }
  78 
  79 struct vma *shm_get_new_attach(struct shmid_ds *seg)
  80 {
  81         int n;
  82 
  83         if(!seg->shm_attaches) {
  84                 if(!(seg->shm_attaches = (void *)kmalloc())) {
  85                         return NULL;
  86                 }
  87                 memset_b(seg->shm_attaches, 0, PAGE_SIZE);
  88         }
  89         for(n = 0; n < NUM_ATTACHES_PER_SEG; n++) {
  90                 if(!seg->shm_attaches[n].start && !seg->shm_attaches[n].end) {
  91                         return &seg->shm_attaches[n];
  92                 }
  93         }
  94         return NULL;
  95 }
  96 
  97 void shm_release_attach(struct vma *attach)
  98 {
  99         memset_b(attach, 0, sizeof(struct vma));
 100 }
 101 
 102 void shm_init(void)
 103 {
 104         int n;
 105 
 106         for(n = 0; n < SHMMNI; n++) {
 107                 shmseg[n] = (struct shmid_ds *)IPC_UNUSED;
 108         }
 109         memset_b(shmseg_pool, 0, sizeof(shmseg_pool));
 110         num_segs = max_segid = shm_seq = shm_tot = shm_rss = 0;
 111 }
 112 
 113 int sys_shmget(key_t key, __size_t size, int shmflg)
 114 {
 115         struct shmid_ds *seg;
 116         struct ipc_perm *perm;
 117         int n, npages;
 118 
 119 #ifdef __DEBUG__
 120         printk("(pid %d) sys_shmget(%d, %d, 0x%x)\n", current->pid, (int)key, size, shmflg);
 121 #endif /*__DEBUG__ */
 122 
 123         if(size < 0 || size > SHMMAX) {
 124                 return -EINVAL;
 125         }
 126 
 127         if(key == IPC_PRIVATE) {
 128                 /* create a new segment */
 129                 if(size < SHMMIN) {
 130                         return -EINVAL;
 131                 }
 132                 npages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 133                 if(shm_tot + npages >= SHMALL) {
 134                         return -ENOSPC;
 135                 }
 136                 if(!(seg = shm_get_new_seg())) {
 137                         return -ENOMEM;
 138                 }
 139                 for(n = 0; n < SHMMNI; n++) {
 140                         if(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {
 141                                 goto init;
 142                         }
 143                 }
 144                 shm_release_seg(seg);
 145                 return -ENOSPC;
 146         }
 147 
 148         seg = NULL;
 149 
 150         for(n = 0; n < SHMMNI; n++) {
 151                 if(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {
 152                         continue;
 153                 }
 154                 if(key == shmseg[n]->shm_perm.key) {
 155                         seg = shmseg[n];
 156                         break;
 157                 }
 158         }
 159 
 160         if(!seg) {
 161                 if(!(shmflg & IPC_CREAT)) {
 162                         return -ENOENT;
 163                 }
 164 
 165                 /* create a new segment */
 166                 if(size < SHMMIN) {
 167                         return -EINVAL;
 168                 }
 169                 npages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 170                 if(shm_tot + npages >= SHMALL) {
 171                         return -ENOSPC;
 172                 }
 173                 if(!(seg = shm_get_new_seg())) {
 174                         return -ENOMEM;
 175                 }
 176                 for(n = 0; n < SHMMNI; n++) {
 177                         if(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {
 178                                 goto init;
 179                         }
 180                 }
 181                 shm_release_seg(seg);
 182                 return -ENOSPC;
 183         } else {
 184                 if((shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) {
 185                         return -EEXIST;
 186                 }
 187                 if(!ipc_has_perms(&seg->shm_perm, shmflg)) {
 188                         return -EACCES;
 189                 }
 190                 if(size > seg->shm_segsz) {
 191                         return -EINVAL;
 192                 }
 193                 return (seg->shm_perm.seq * SHMMNI) + n;
 194         }
 195 
 196 init:
 197         perm = &seg->shm_perm;
 198         perm->key = key;
 199         perm->uid = perm->cuid = current->euid;
 200         perm->gid = perm->cgid = current->egid;
 201         perm->mode = shmflg & 0777;
 202         perm->seq = shm_seq;
 203         seg->shm_segsz = size;
 204         seg->shm_atime = seg->shm_dtime = 0;
 205         seg->shm_ctime = CURRENT_TIME;
 206         seg->shm_cpid = current->pid;
 207         seg->shm_lpid = 0;
 208         seg->shm_nattch = 0;
 209         seg->shm_npages = 0;
 210         seg->shm_attaches = 0;
 211         shmseg[n] = seg;
 212         if(n > max_segid) {
 213                 max_segid = n;
 214         }
 215         num_segs++;
 216         shm_tot += npages;
 217         return (seg->shm_perm.seq * SHMMNI) + n;
 218 }
 219 #endif /* CONFIG_SYSVIPC */

/* [previous][next][first][last][top][bottom][index][help] */