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
;
45 key
= m
->m_lc_ipc_shmget
.key
;
46 old_size
= size
= m
->m_lc_ipc_shmget
.size
;
47 flag
= m
->m_lc_ipc_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 */
64 size
+= PAGE_SIZE
- size
% 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
) mmap(0, size
,
76 PROT_READ
|PROT_WRITE
, MAP_ANON
, -1, 0);
77 if (shm
->page
== (vir_bytes
) MAP_FAILED
)
79 shm
->vm_id
= vm_getphys(sef_self(), (void *) shm
->page
);
80 memset((void *)shm
->page
, 0, size
);
82 shm
->shmid_ds
.shm_perm
.cuid
=
83 shm
->shmid_ds
.shm_perm
.uid
= getnuid(who_e
);
84 shm
->shmid_ds
.shm_perm
.cgid
=
85 shm
->shmid_ds
.shm_perm
.gid
= getngid(who_e
);
86 shm
->shmid_ds
.shm_perm
.mode
= flag
& 0777;
87 shm
->shmid_ds
.shm_segsz
= old_size
;
88 shm
->shmid_ds
.shm_atime
= 0;
89 shm
->shmid_ds
.shm_dtime
= 0;
90 shm
->shmid_ds
.shm_ctime
= time(NULL
);
91 shm
->shmid_ds
.shm_cpid
= getnpid(who_e
);
92 shm
->shmid_ds
.shm_lpid
= 0;
93 shm
->shmid_ds
.shm_nattch
= 0;
94 shm
->id
= id
= identifier
++;
100 m
->m_lc_ipc_shmget
.retid
= id
;
104 /*===========================================================================*
106 *===========================================================================*/
107 int do_shmat(message
*m
)
112 struct shm_struct
*shm
;
115 addr
= (vir_bytes
) m
->SHMAT_ADDR
;
116 flag
= m
->SHMAT_FLAG
;
118 if (addr
&& (addr
% PAGE_SIZE
)) {
120 addr
-= (addr
% PAGE_SIZE
);
125 if (!(shm
= shm_find_id(id
)))
128 if (flag
& SHM_RDONLY
)
132 if (!check_perm(&shm
->shmid_ds
.shm_perm
, who_e
, flag
))
135 ret
= vm_remap(who_e
, sef_self(), (void *)addr
, (void *)shm
->page
,
136 shm
->shmid_ds
.shm_segsz
);
137 if (ret
== MAP_FAILED
)
140 shm
->shmid_ds
.shm_atime
= time(NULL
);
141 shm
->shmid_ds
.shm_lpid
= getnpid(who_e
);
142 /* nattach is updated lazily */
144 m
->SHMAT_RETADDR
= (long) ret
;
148 /*===========================================================================*
149 * update_refcount_and_destroy *
150 *===========================================================================*/
151 void update_refcount_and_destroy(void)
155 for (i
= 0, j
= 0; i
< shm_list_nr
; i
++) {
158 rc
= vm_getrefcount(sef_self(), (void *) shm_list
[i
].page
);
159 if (rc
== (u8_t
) -1) {
160 printf("IPC: can't find physical region.\n");
163 shm_list
[i
].shmid_ds
.shm_nattch
= rc
- 1;
165 if (shm_list
[i
].shmid_ds
.shm_nattch
||
166 !(shm_list
[i
].shmid_ds
.shm_perm
.mode
& SHM_DEST
)) {
168 shm_list
[j
] = shm_list
[i
];
171 int size
= shm_list
[i
].shmid_ds
.shm_segsz
;
172 if (size
% PAGE_SIZE
)
173 size
+= PAGE_SIZE
- size
% PAGE_SIZE
;
174 munmap((void *)shm_list
[i
].page
, size
);
180 /*===========================================================================*
182 *===========================================================================*/
183 int do_shmdt(message
*m
)
189 addr
= m
->SHMDT_ADDR
;
191 if ((vm_id
= vm_getphys(who_e
, (void *) addr
)) == 0)
194 for (i
= 0; i
< shm_list_nr
; i
++) {
195 if (shm_list
[i
].vm_id
== vm_id
) {
196 struct shm_struct
*shm
= &shm_list
[i
];
198 shm
->shmid_ds
.shm_atime
= time(NULL
);
199 shm
->shmid_ds
.shm_lpid
= getnpid(who_e
);
200 /* nattch is updated lazily */
202 vm_unmap(who_e
, (void *) addr
);
206 if (i
== shm_list_nr
)
207 printf("IPC: do_shmdt impossible error! could not find id %lu to unmap\n",
210 update_refcount_and_destroy();
215 /*===========================================================================*
217 *===========================================================================*/
218 int do_shmctl(message
*m
)
220 int id
= m
->SHMCTL_ID
;
221 int cmd
= m
->SHMCTL_CMD
;
222 struct shmid_ds
*ds
= (struct shmid_ds
*)m
->SHMCTL_BUF
;
223 struct shmid_ds tmp_ds
;
224 struct shm_struct
*shm
= NULL
;
225 struct shminfo sinfo
;
226 struct shm_info s_info
;
231 update_refcount_and_destroy();
233 if ((cmd
== IPC_STAT
||
236 !(shm
= shm_find_id(id
)))
243 /* check whether it has read permission */
244 if (!check_perm(&shm
->shmid_ds
.shm_perm
, who_e
, 0444))
246 r
= sys_datacopy(SELF
, (vir_bytes
)&shm
->shmid_ds
,
247 who_e
, (vir_bytes
)ds
, sizeof(struct shmid_ds
));
252 uid
= getnuid(who_e
);
253 if (uid
!= shm
->shmid_ds
.shm_perm
.cuid
&&
254 uid
!= shm
->shmid_ds
.shm_perm
.uid
&&
257 r
= sys_datacopy(who_e
, (vir_bytes
)ds
,
258 SELF
, (vir_bytes
)&tmp_ds
, sizeof(struct shmid_ds
));
261 shm
->shmid_ds
.shm_perm
.uid
= tmp_ds
.shm_perm
.uid
;
262 shm
->shmid_ds
.shm_perm
.gid
= tmp_ds
.shm_perm
.gid
;
263 shm
->shmid_ds
.shm_perm
.mode
&= ~0777;
264 shm
->shmid_ds
.shm_perm
.mode
|= tmp_ds
.shm_perm
.mode
& 0666;
265 shm
->shmid_ds
.shm_ctime
= time(NULL
);
268 uid
= getnuid(who_e
);
269 if (uid
!= shm
->shmid_ds
.shm_perm
.cuid
&&
270 uid
!= shm
->shmid_ds
.shm_perm
.uid
&&
273 shm
->shmid_ds
.shm_perm
.mode
|= SHM_DEST
;
274 /* destroy if possible */
275 update_refcount_and_destroy();
280 sinfo
.shmmax
= (unsigned long) -1;
282 sinfo
.shmmni
= MAX_SHM_NR
;
283 sinfo
.shmseg
= (unsigned long) -1;
284 sinfo
.shmall
= (unsigned long) -1;
285 r
= sys_datacopy(SELF
, (vir_bytes
)&sinfo
,
286 who_e
, (vir_bytes
)ds
, sizeof(struct shminfo
));
289 m
->SHMCTL_RET
= shm_list_nr
- 1;
290 if (m
->SHMCTL_RET
< 0)
296 s_info
.used_ids
= shm_list_nr
;
298 for (i
= 0; i
< shm_list_nr
; i
++)
300 shm_list
[i
].shmid_ds
.shm_segsz
/PAGE_SIZE
;
301 s_info
.shm_rss
= s_info
.shm_tot
;
303 s_info
.swap_attempts
= 0;
304 s_info
.swap_successes
= 0;
305 r
= sys_datacopy(SELF
, (vir_bytes
)&s_info
,
306 who_e
, (vir_bytes
)ds
, sizeof(struct shm_info
));
309 m
->SHMCTL_RET
= shm_list_nr
- 1;
310 if (m
->SHMCTL_RET
< 0)
314 if (id
< 0 || id
>= shm_list_nr
)
317 r
= sys_datacopy(SELF
, (vir_bytes
)&shm
->shmid_ds
,
318 who_e
, (vir_bytes
)ds
, sizeof(struct shmid_ds
));
321 m
->SHMCTL_RET
= shm
->id
;
330 static void list_shm_ds(void)
333 printf("key\tid\tpage\n");
334 for (i
= 0; i
< shm_list_nr
; i
++)
335 printf("%ld\t%d\t%lx\n",
342 /*===========================================================================*
344 *===========================================================================*/
347 return (shm_list_nr
== 0);