3 #define MAX_SHM_NR 1024
8 struct shmid_ds shmid_ds
;
12 static struct shm_struct shm_list
[MAX_SHM_NR
];
13 static int shm_list_nr
= 0;
15 static struct shm_struct
*shm_find_key(key_t key
)
18 if (key
== IPC_PRIVATE
)
20 for (i
= 0; i
< shm_list_nr
; i
++)
21 if (shm_list
[i
].key
== key
)
26 static struct shm_struct
*shm_find_id(int id
)
29 for (i
= 0; i
< shm_list_nr
; i
++)
30 if (shm_list
[i
].id
== id
)
35 /*===========================================================================*
37 *===========================================================================*/
38 int do_shmget(message
*m
)
40 struct shm_struct
*shm
;
41 long key
, size
, old_size
;
46 old_size
= size
= m
->SHMGET_SIZE
;
47 flag
= m
->SHMGET_FLAG
;
49 if ((shm
= shm_find_key(key
))) {
50 if (!check_perm(&shm
->shmid_ds
.shm_perm
, who_e
, flag
))
52 if ((flag
& IPC_CREAT
) && (flag
& IPC_EXCL
))
54 if (size
&& shm
->shmid_ds
.shm_segsz
< size
)
57 } else { /* no key found */
58 if (!(flag
& IPC_CREAT
))
62 /* round up to a multiple of PAGE_SIZE */
63 if (size
% I386_PAGE_SIZE
)
64 size
+= I386_PAGE_SIZE
- size
% I386_PAGE_SIZE
;
68 if (shm_list_nr
== MAX_SHM_NR
)
70 /* TODO: shmmni should be changed... */
71 if (identifier
== SHMMNI
)
73 shm
= &shm_list
[shm_list_nr
];
74 memset(shm
, 0, sizeof(struct shm_struct
));
75 shm
->page
= (vir_bytes
) minix_mmap(0, size
,
77 MAP_CONTIG
|MAP_PREALLOC
|MAP_ANON
|MAP_IPC_SHARED
,
79 if (shm
->page
== (vir_bytes
) MAP_FAILED
)
81 shm
->phys
= vm_getphys(SELF_E
, (void *) shm
->page
);
82 memset((void *)shm
->page
, 0, size
);
84 shm
->shmid_ds
.shm_perm
.cuid
=
85 shm
->shmid_ds
.shm_perm
.uid
= getnuid(who_e
);
86 shm
->shmid_ds
.shm_perm
.cgid
=
87 shm
->shmid_ds
.shm_perm
.gid
= getngid(who_e
);
88 shm
->shmid_ds
.shm_perm
.mode
= flag
& 0777;
89 shm
->shmid_ds
.shm_segsz
= old_size
;
90 shm
->shmid_ds
.shm_atime
= 0;
91 shm
->shmid_ds
.shm_dtime
= 0;
92 shm
->shmid_ds
.shm_ctime
= time(NULL
);
93 shm
->shmid_ds
.shm_cpid
= getnpid(who_e
);
94 shm
->shmid_ds
.shm_lpid
= 0;
95 shm
->shmid_ds
.shm_nattch
= 0;
96 shm
->id
= id
= identifier
++;
102 m
->SHMGET_RETID
= id
;
106 /*===========================================================================*
108 *===========================================================================*/
109 int do_shmat(message
*m
)
114 struct shm_struct
*shm
;
117 addr
= (vir_bytes
) m
->SHMAT_ADDR
;
118 flag
= m
->SHMAT_FLAG
;
120 if (addr
&& (addr
% I386_PAGE_SIZE
)) {
122 addr
-= (addr
% I386_PAGE_SIZE
);
127 if (!(shm
= shm_find_id(id
)))
130 if (flag
& SHM_RDONLY
)
134 if (!check_perm(&shm
->shmid_ds
.shm_perm
, who_e
, flag
))
137 ret
= vm_remap(who_e
, SELF_E
, (void *)addr
, (void *)shm
->page
,
138 shm
->shmid_ds
.shm_segsz
);
139 if (ret
== MAP_FAILED
)
142 shm
->shmid_ds
.shm_atime
= time(NULL
);
143 shm
->shmid_ds
.shm_lpid
= getnpid(who_e
);
144 /* nattach is updated lazily */
146 m
->SHMAT_RETADDR
= (long) ret
;
150 /*===========================================================================*
151 * update_refcount_and_destroy *
152 *===========================================================================*/
153 void update_refcount_and_destroy(void)
157 for (i
= 0, j
= 0; i
< shm_list_nr
; i
++) {
160 rc
= vm_getrefcount(SELF_E
, (void *) shm_list
[i
].page
);
161 if (rc
== (u8_t
) -1) {
162 printf("IPC: can't find physical region.\n");
165 shm_list
[i
].shmid_ds
.shm_nattch
= rc
- 1;
167 if (shm_list
[i
].shmid_ds
.shm_nattch
||
168 !(shm_list
[i
].shmid_ds
.shm_perm
.mode
& SHM_DEST
)) {
170 shm_list
[j
] = shm_list
[i
];
173 int size
= shm_list
[i
].shmid_ds
.shm_segsz
;
174 if (size
% I386_PAGE_SIZE
)
175 size
+= I386_PAGE_SIZE
- size
% I386_PAGE_SIZE
;
176 minix_munmap((void *)shm_list
[i
].page
, size
);
182 /*===========================================================================*
184 *===========================================================================*/
185 int do_shmdt(message
*m
)
191 addr
= m
->SHMDT_ADDR
;
193 if ((paddr
= vm_getphys(who_e
, (void *) addr
)) == 0)
196 for (i
= 0; i
< shm_list_nr
; i
++) {
197 if (shm_list
[i
].phys
== paddr
) {
198 struct shm_struct
*shm
= &shm_list
[i
];
200 shm
->shmid_ds
.shm_atime
= time(NULL
);
201 shm
->shmid_ds
.shm_lpid
= getnpid(who_e
);
202 /* nattch is updated lazily */
204 vm_unmap(who_e
, (void *) addr
);
208 if (i
== shm_list_nr
)
209 fprintf(stderr
, "IPC: do_shmdt impossible error!\n");
211 update_refcount_and_destroy();
216 /*===========================================================================*
218 *===========================================================================*/
219 int do_shmctl(message
*m
)
221 int id
= m
->SHMCTL_ID
;
222 int cmd
= m
->SHMCTL_CMD
;
223 struct shmid_ds
*ds
= (struct shmid_ds
*)m
->SHMCTL_BUF
;
224 struct shmid_ds tmp_ds
;
225 struct shm_struct
*shm
= NULL
;
226 struct shminfo sinfo
;
227 struct shm_info s_info
;
232 update_refcount_and_destroy();
234 if ((cmd
== IPC_STAT
||
237 !(shm
= shm_find_id(id
)))
244 /* check whether it has read permission */
245 if (!check_perm(&shm
->shmid_ds
.shm_perm
, who_e
, 0444))
247 r
= sys_datacopy(SELF_E
, (vir_bytes
)&shm
->shmid_ds
,
248 who_e
, (vir_bytes
)ds
, sizeof(struct shmid_ds
));
253 uid
= getnuid(who_e
);
254 if (uid
!= shm
->shmid_ds
.shm_perm
.cuid
&&
255 uid
!= shm
->shmid_ds
.shm_perm
.uid
&&
258 r
= sys_datacopy(who_e
, (vir_bytes
)ds
,
259 SELF_E
, (vir_bytes
)&tmp_ds
, sizeof(struct shmid_ds
));
262 shm
->shmid_ds
.shm_perm
.uid
= tmp_ds
.shm_perm
.uid
;
263 shm
->shmid_ds
.shm_perm
.gid
= tmp_ds
.shm_perm
.gid
;
264 shm
->shmid_ds
.shm_perm
.mode
&= ~0777;
265 shm
->shmid_ds
.shm_perm
.mode
|= tmp_ds
.shm_perm
.mode
& 0666;
266 shm
->shmid_ds
.shm_ctime
= time(NULL
);
269 uid
= getnuid(who_e
);
270 if (uid
!= shm
->shmid_ds
.shm_perm
.cuid
&&
271 uid
!= shm
->shmid_ds
.shm_perm
.uid
&&
274 shm
->shmid_ds
.shm_perm
.mode
|= SHM_DEST
;
275 /* destroy if possible */
276 update_refcount_and_destroy();
281 sinfo
.shmmax
= (unsigned long) -1;
283 sinfo
.shmmni
= MAX_SHM_NR
;
284 sinfo
.shmseg
= (unsigned long) -1;
285 sinfo
.shmall
= (unsigned long) -1;
286 r
= sys_datacopy(SELF_E
, (vir_bytes
)&sinfo
,
287 who_e
, (vir_bytes
)ds
, sizeof(struct shminfo
));
290 m
->SHMCTL_RET
= shm_list_nr
- 1;
291 if (m
->SHMCTL_RET
< 0)
297 s_info
.used_ids
= shm_list_nr
;
299 for (i
= 0; i
< shm_list_nr
; i
++)
301 shm_list
[i
].shmid_ds
.shm_segsz
/I386_PAGE_SIZE
;
302 s_info
.shm_rss
= s_info
.shm_tot
;
304 s_info
.swap_attempts
= 0;
305 s_info
.swap_successes
= 0;
306 r
= sys_datacopy(SELF_E
, (vir_bytes
)&s_info
,
307 who_e
, (vir_bytes
)ds
, sizeof(struct shm_info
));
310 m
->SHMCTL_RET
= shm_list_nr
- 1;
311 if (m
->SHMCTL_RET
< 0)
315 if (id
< 0 || id
>= shm_list_nr
)
318 r
= sys_datacopy(SELF_E
, (vir_bytes
)&shm
->shmid_ds
,
319 who_e
, (vir_bytes
)ds
, sizeof(struct shmid_ds
));
322 m
->SHMCTL_RET
= shm
->id
;
331 static void list_shm_ds(void)
334 printf("key\tid\tpage\n");
335 for (i
= 0; i
< shm_list_nr
; i
++)
336 printf("%ld\t%d\t%lx\n",
343 /*===========================================================================*
345 *===========================================================================*/
348 return (shm_list_nr
== 0);