memoria compartida - La web de Sistemas Operativos (SOPA)

Anuncio
Memoria Compartida
LECCIÓN 24: MEMORIA COMPARTIDA
24.1 Conceptos ...................................................................................................... 1
24.2 Llamadas al sistema ....................................................................................... 2
24.3 Código de las funciones ................................................................................. 6
Memoria Compartida
LECCIÓN 24: MEMORIA COMPARTIDA
24.1 Conceptos
La forma mas rápida de comunicar dos procesos es hacer que compartan una zona
de memoria. Para enviar datos de un proceso a otro, solo hay que escribir en
memoria y automáticamente esos datos están disponibles para que los lea cualquier
otro proceso.
Una innovación importante aportada por los IPC es la gestión de memoria
compartida (Shared Memory). En un programa estándar, una zona de memoria
asignada es propia del proceso que la ejecuta. Ningún otro proceso puede acceder a
ella. El principio de la memoria compartida es permitir a los procesos compartir una
parte de su espacio de direccionamiento.
Las memorias compartidas proporcionan un sistema muy potente para compartir
zonas de memoria, pero obligan implementar un mecanismo de sincronización de
accesos. En efecto, no es posible que dos procesos intenten escribir al mismo
tiempo y en el mismo punto de la memoria compartida: es más que probable que la
coherencia de los datos se pierda. Una solución para resolver este problema es
utilizar los semáforos.
La manipulacion de una memoria compartida sólo puede efectuarse por medio de
dos estructuras particulares.
Estructuras Básicas:
Estas estructuras se definen en el archivo cabecera<linux/shm.h> en el laboratorio
/usr/src/linux/include/linux/* pero basta con poner <sys/shm.h>.
Estructura shmid_ds: Corresponde a una entrada en la tabla de memorias
compartidas. Estructura de control asociada a cada una de las regiones de memoria
compartida existentes en el sistema. Se crea como consecuencia de una llamada al
sistema shmget.
Universidad de Las Palmas de Gran Canaria
24-1
Memoria Compartida
TIPO
Struct ipc_perm
int
Time_t
Time_t
Time_t
Unsinged short
Unsinged short
Short
Unsigned short
Unsigned long *
Struct
Vm_area_struct *
CAMPO
Shm_perm
Shm_segsz
Shm_atime
Shm_dtime
Shm_ctime
Shm_cpid
Shm_lpid
DESCRIPCIÓN
Permisos
Tamaño del segmento (bytes)
Fecha de la última vinculación
Fecha de la última desvinculación
Fecha de la última modificación
Número del proceso creador
Número del proceso que ha efectuado la
última operación
Shm_nattch Número de vinculaciones
Shm_npages Tamaño de los segmentos(número de
páginas de memoria)
Shm_pages Tabla de punteros a las ventanas de memoria
Attaches
Descriptores para las vinculaciones
Los tres últimos campos son privados: son utilizados por el núcleo para organizar las
memorias compartidas.
Estructura shminfo: Se utiliza en una llamada a shmctl con IPC_INFO como
argumento. Esta estructura es utilizada por ejemplo por el programa ipcs. Se usa
raramente, excepto en programas de sistema de estadísticas o de observación de la
máquina.
TIPO
Int
Int
Int
Int
Int
CAMPO
Shmax
Shmmin
Shmmni
Shmseg
Shmall
DESCRIPCIÓN
Tamaño máximo del segmento(bytes)
Tamaño mínimo del segmento(bytes)
Número máximo de segmentos
Número máximo de segmentos por proceso
Número máximo de segmentos en número de páginas de memoria
24.2 Llamadas al sistema
•
shmget: Creación y búsqueda de una zona de memoria compartida.
•
shmctl: Control de las zonas de memorias compartidas.
•
shmat: Vinculación de una zona de memoria.
•
shmdt: Desvincular una zona de memoria.
Universidad de Las Palmas de Gran Canaria
24-2
Memoria Compartida
Shmget (creación y búsqueda de una zona de memoria compartida)
La llamada al sistema shmget crea una nueva zona de memoria compartida o bien
permite obtener un acceso a una memoria compartida ya existente. El prototipo de
esta llamada es el siguiente.
#include <sys/ipc.h>
#include<sys/shm.h>
int shmget (key_t, in size, int option);
key: identificador.
size: Tamaño del segmento de memoria compartida.
Option: parámetros estándar de creación de un IPC.
CAMPO I:
IPC_CREAT
IPC_EXCL
CAMPO II:
00X00 usuario
000X0 grupo
0000x otro
El núcleo busca dentro de la tabla alguna entrada que se ajuste a la llave
suministrada. Si la llave suministrada toma el valor IPC_PRIVATE, el núcleo ocupa
la primera entrada que se encuentra libre y ninguna otra llamada “shmget” podrá
devolver esta entrada hasta que la liberemos.
Si dentro de la máscara de indicadores está activo el bit IPC_CREAT, el núcleo crea
una nueva entrada en caso de que no haya ninguna que responda a la llave
suministrada. Si IPC_CREAT y IPC_EXL error si ya existe la clave suministrada.
Descripción: Retorna un descriptor de región de memoria compartida. Si no existe
descriptor y se especifica IPC_CREAT creará uno.
Resulta útil precisar que si esta llamada al sistema se utiliza para obtener una
referencia una zona de memoria compartida ya existente, el tamaño especificado
debe ser inferior o igual al de la memoria existente.
Universidad de Las Palmas de Gran Canaria
24-3
Memoria Compartida
En caso contrario, el tamaño asignado debe ser múltiplo de PAGE_SIZE, que
corresponde al tamaño de una página de memoria (4 KB en la arquitectura x86).
Error: Retornará un -1 y errno tendrá el código de error. La variable errno puede
tomar uno de los valores siguientes:
ERROR
ENOMEN
EINVAL
SIGNIFICADO
Memoria insuficiente
Parámetros no válidos (SHMMIN > size o tamaño >
SHMMAX)
ENOENT
No existe ningún segmento de memoria compartida para la
clave dada
EEXIST
Se ha dado el valor IPC_CREAT – IPC_EXCL y el segmento
de memoria compartida ya existe
EIDRM
El segmento de memoria se ha marcado como destruido
EACCES, EPERM Permisos de acceso insuficientes
EFAULT
Parámetros incorrectos
ENOSPC
Todos los identificadores de memorias compartidas en uso,
o bien la asignación de una memoria compartida del tamaño
especificado sería mayor que SHMALL
Shmat (vincular de una zona de memoria)
La llamada al sistema shmat permite vincular una memoria compartida a un
proceso. Esta operación consiste en realidad en vincular una zona de memoria al
espacio de direccionamiento virtual del proceso que llama. El prototipo de esta
llamada es el siguiente.
#include <sys/ipc.h>
#include<sys/shm.h>
void *shmat (int shmid, const void *shmaddr, int option);
shmid: Identificador válido.
shmaddr: Puntero a área de usuario, permite especificar la dirección de la memoria
compartida.
Si shmaddr vale NULL, el sistema operativo intenta encontrar una zona de memoria
libre(es el método más seguro).
Universidad de Las Palmas de Gran Canaria
24-4
Memoria Compartida
Si no, el sistema operativo intenta vincular la memoria compartida a la dirección
especificada. Si se especifica la opción SHM_RND, el sistema intenta vincular la
zona de memoria a una dirección múltiplo de SHMLBA lo más próxima posible a la
especificada.
Hay que precisar que esta llamada permite al sistema el uso de una opción
especial: SHM_RDONLY. Esta opción permite especificar que el proceso sólo puede
acceder al segmento de memoria en lectura. Si no es así, el segmento se vincula en
lectura y escritura. No existe un medio para realizar una vinculación en escritura
exclusiva.
Esta llamada al sistema actualiza los parámetros siguientes de la estructura
shmid_ds:
shm_atime recibe la fecha actual;
shm_lpid recibe el pid del proceso que llama;
shm_nattch se incrementa en una unidad.
Ejecución correcta: conectará una región de memoria compartida a la memoria de
usuario.
Error: Retornará un -1 y errno tendrá el código de error. La variable errno puede
tomar uno de los valores siguientes:
ERROR
EACCES
EINVAL
ENOMEN
EIDRM
SIGNIFICADO
Permisos de acceso insuficientes
Clave o dirección no válida
Memoria insuficiente
Segmento marcado como destruido
Shmdt (desvincular una zona de una zona de memoria)
La llamada al sistema shmdt le permite a un proceso desvincular una zona de
memoria compartida de su espacio de direccionamiento. El prototipo de esta llamada
es el siguiente:
#include<sys.types.h>
#include <sys/ipc.h>
#include<sys/shm.h>
int shmdt (const void *shmaddr);
Esta llamada al sistema actualiza los campos siguientes de las estructura
shmid_ds:
shm_dtime recibe la fecha actual;
shm_lpid recibe el pid del proceso que llama;
shm_nattch se decrementa en una unidad.
Universidad de Las Palmas de Gran Canaria
24-5
Memoria Compartida
Shmct (Control de las zonas de memoria compartidas)
La llamada shmctl permite controlar la gestión de un segmento de memoria
compartida. El prototipo de esta llamada es el siguiente:
#include <sys/ipc.h>
#include<sys/shm.h>
int shmct (int shmid, int cmd, struct shmid_ds *buf);
Veamos los diferentes mandatos posibles, que corresponden a usos distintos:
IPC_STAT: permite obtener informaciones respecto al segmento de memoria
compartida. Estas informaciones se copian en la zona de memoria apuntada por buf.
IPC_SET: permite aplicar cambios que el usuario ha efectuado en los campos uid,
gid o mode del campo shm_perms. Sólo se utilizan los 9 bits de menor peso. El
campo shm_ctime también se modificará. Sólo el propietario, el creador y el
superusuario tienen derecho a efectuar esta operación.
IPC_RMID: permite marcar un segmento de memoria compartida como destruido.
Este segmento se destruirá efectivamente cuando se suprima la última vinculación.
Hay que añadir a estos mandatos dos opciones específicas de Linux. Estas dos
opciones sólo pueden ser usadas por el superusuario, y permiten o, por el contrario,
impiden el swap de un segmento de memoria compartida:
SHM_LOCK: impide al swap de un segmento de memoria compartida;
SHM_UNLOCK: permite el swap de un segmento de memoria compartida;
24.3 Código de las funciones
/*fichero de memoria compartida*/
#include <linux/malloc.h>
#include <linux/shm.h>
#include <linux/swap.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
extern unsigned long get_swap_page (void);
static int findkey (key_t key);
static int newseg (key_t key, int shmflg, int size);
static int shm_map (struct vm_area_struct *shmd);
Universidad de Las Palmas de Gran Canaria
24-6
Memoria Compartida
static void killseg (int id);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
static unsigned long shm_nopage(struct vm_area_struct *, unsigned long, int);
static int shm_swapout(struct vm_area_struct *, struct page *);
static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */
static int shm_swp = 0; /* number of shared memory pages that are in swap */
static int max_shmid = 0; /* every used id is <= max_shmid */
static struct wait_queue *shm_lock = NULL; /* calling findkey() may need to wait */
/*Numero maximo de segmentos*/
static struct shmid_kernel *shm_segs[SHMMNI];
static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
/* some statistics */
static ulong swap_attempts = 0;
static ulong swap_successes = 0;
static ulong used_segs = 0;
/*Esta funcion inicializa las memorias compartidas*/
void __init shm_init (void)
{
int id;
for (id = 0; id < SHMMNI; id++)
/ *valor especial para shm_segs[id] que nos indica que el segmento no esta
* siendo usado*/
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
shm_lock = NULL;
return;
}
/*Esta funcion mira si la clave esta siendo usada devuelve el identificador si esta
usada*/
static int findkey (key_t key)
{
int id;
struct shmid_kernel *shp;
for (id = 0; id <= max_shmid; id++) {
/*esta siendo destruido el segmento*/
while ((shp = shm_segs[id]) == IPC_NOID)
Universidad de Las Palmas de Gran Canaria
24-7
Memoria Compartida
sleep_on (&shm_lock);
if (shp == IPC_UNUSED) /*el segmento no esta siendo usado*/
continue;
/*Si coincide con la clave retornamos su posicion*/
if (key == shp->u.shm_perm.key)
return id;
}
return -1;
}
/*Creacion de un nuevo identificador sujeto a la disponibilidad de entradas libres
* en la tabla que gestiona el nucleo para la memoria esta funcion es llamada
* por sys_shmget*/
static int newseg (key_t key, int shmflg, int size)
/*tamano del segmento de memoria compartida*/
{
struct shmid_kernel *shp;
/*calcula el tamaño en paginas*/
int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
int id, i;
if (size < SHMMIN)
return -EINVAL;
/*tamano minimo del segmento*/
/*numero maximo de segmentos en numero de paginas de memoria*/
if (shm_tot + numpages >= SHMALL)
return -ENOSPC;
/*localizamos el primer segmento que este libre*/
for (id = 0; id < SHMMNI; id++)
if (shm_segs[id] == IPC_UNUSED) {
shm_segs[id] = (struct shmid_kernel *) IPC_NOID;
goto found;
}
/*se utiliza tambien para indicar que no se puede crear un segmento nuevo*/
return -ENOSPC;
found:
shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
/*reserva la memoria que necesita con el kmalloc*/
if (!shp) {
/*mal asunto no hay memoria*/
Universidad de Las Palmas de Gran Canaria
24-8
Memoria Compartida
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
wake_up (&shm_lock);
/* la memoria podria crearse pero no tiene mas memoria para almacenar la
* estructura*/
return -ENOMEM;
}
/*reserva memoria para la tabla de punteros a las ventanas de memoria*/
shp->shm_pages = (ulong *) vmalloc (numpages*sizeof(ulong));
if (!shp->shm_pages) {
/*mal asunto y deshace los cambios*/
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
wake_up (&shm_lock);
kfree(shp);
return -ENOMEM;
}
for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
shm_tot += numpages;
shp->u.shm_perm.key = key;
shp->u.shm_perm.mode = (shmflg & S_IRWXUGO);
shp->u.shm_perm.cuid = shp->u.shm_perm.uid = current->euid;
shp->u.shm_perm.cgid = shp->u.shm_perm.gid = current->egid;
shp->u.shm_perm.seq = shm_seq;
shp->u.shm_segsz = size;
shp->u.shm_cpid = current->pid;
shp->attaches = NULL;
shp->u.shm_lpid = shp->u.shm_nattch = 0;
shp->u.shm_atime = shp->u.shm_dtime = 0;
shp->u.shm_ctime = CURRENT_TIME;
shp->shm_npages = numpages;
if (id > max_shmid)
max_shmid = id;
shm_segs[id] = shp;
used_segs++;
wake_up (&shm_lock);
return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id;
}
int shmmax = SHMMAX;
/*funcion shmget*/
asmlinkage int sys_shmget (key_t key, int size, int shmflg)
{
Universidad de Las Palmas de Gran Canaria
24-9
Memoria Compartida
struct shmid_kernel *shp;
int err, id = 0;
down(&current->mm->mmap_sem);
lock_kernel();
/*para que se realice de manera atomica*/
if (size < 0 || size > shmmax) { /*tamano maximo del segmento*/
err = -EINVAL;
/*se crea un nuevo identificador sujeto a la disponibilidad de entradas
* libres en la tabla que gestiona el núcleo para los segmentos, se
* ocupa la primera*/
} else if (key == IPC_PRIVATE) {
err = newseg(key, shmflg, size);
} else if ((id = findkey (key)) == -1) {
/*key not used*/
/*IPC_CREAT la facilidad IPC se creara si otro proceso no la ha creado ya*/
if (!(shmflg & IPC_CREAT))
/*el segmento de memoria no existe y no esta marcada la opción*/
err = -ENOENT;
else
/*llamamos a la funcion que nos creara una entrada en la tabla*/
err = newseg(key, shmflg, size);
/*la llamada falla porque el grupo de semaforos ya creado*/
} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
err = -EEXIST;
} else {
/*se coge el que devolvio find*/
shp = shm_segs[id];
/*se hacen unas comprobaciones*/
if (shp->u.shm_perm.mode & SHM_DEST)
err = -EIDRM;
else if (size > shp->u.shm_segsz)
err = -EINVAL;
else if (ipcperms (&shp->u.shm_perm, shmflg))
err = -EACCES;
else
err = (int) shp->u.shm_perm.seq * SHMMNI + id;
}
unlock_kernel();
up(&current->mm->mmap_sem);
return err;
}
/*funcion shmctl*/
asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
Universidad de Las Palmas de Gran Canaria
24-10
Memoria Compartida
{
struct shmid_ds tbuf;
struct shmid_kernel *shp;
struct ipc_perm *ipcp;
int id, err = -EINVAL;
lock_kernel();
if (cmd < 0 || shmid < 0)
goto out;
if (cmd == IPC_SET) {
err = -EFAULT;
if(copy_from_user (&tbuf, buf, sizeof (*buf)))
goto out;
}
switch (cmd) { /* replace with proc interface ? */
case IPC_INFO: /*información actual del segmento*/
{
struct shminfo shminfo;
err = -EFAULT;
if (!buf)
goto out;
shminfo.shmmni = SHMMNI;
shminfo.shmmax = shmmax;
shminfo.shmmin = SHMMIN;
shminfo.shmall = SHMALL;
shminfo.shmseg = SHMSEG;
if(copy_to_user (buf, &shminfo, sizeof(struct shminfo)))
goto out;
err = max_shmid;
goto out;
}
case SHM_INFO: /*asociada a los procesos*/
{
struct shm_info shm_info;
err = -EFAULT;
shm_info.used_ids = used_segs;
shm_info.shm_rss = shm_rss;
shm_info.shm_tot = shm_tot; /*memoria asignada*/
shm_info.shm_swp = shm_swp;
shm_info.swap_attempts = swap_attempts;
shm_info.swap_successes = swap_successes;
if(copy_to_user (buf, &shm_info, sizeof(shm_info)))
goto out;
err = max_shmid;
goto out;
}
case SHM_STAT:
err = -EINVAL;
if (shmid > max_shmid)
Universidad de Las Palmas de Gran Canaria
24-11
Memoria Compartida
goto out;
shp = shm_segs[shmid];
if (shp == IPC_UNUSED || shp == IPC_NOID)
goto out;
if (ipcperms (&shp->u.shm_perm, S_IRUGO))
goto out;
id = (unsigned int) shp->u.shm_perm.seq * SHMMNI + shmid;
err = -EFAULT;
if(copy_to_user (buf, &shp->u, sizeof(*buf)))
goto out;
err = id;
goto out;
}
shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
err = -EINVAL;
if (shp == IPC_UNUSED || shp == IPC_NOID)
goto out;
err = -EIDRM;
if (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)
goto out;
ipcp = &shp->u.shm_perm;
switch (cmd) {
case SHM_UNLOCK:/permite/
err = -EPERM;
if (!capable(CAP_IPC_LOCK))
goto out;
err = -EINVAL;
if (!(ipcp->mode & SHM_LOCKED))
goto out;
ipcp->mode &= ~SHM_LOCKED;
break;
case SHM_LOCK: /impide/
/* Allow superuser to lock segment in memory */
/* Should the pages be faulted in here or leave it to user? */
/* need to determine interaction with current->swappable */
err = -EPERM;
if (!capable(CAP_IPC_LOCK))
goto out;
err = -EINVAL;
if (ipcp->mode & SHM_LOCKED)
goto out;
ipcp->mode |= SHM_LOCKED;
break;
case IPC_STAT:/inf. Segmento memoria compartida*/
err = -EACCES;
if (ipcperms (ipcp, S_IRUGO))
goto out;
err = -EFAULT;
Universidad de Las Palmas de Gran Canaria
24-12
Memoria Compartida
if(copy_to_user (buf, &shp->u, sizeof(shp->u)))
goto out;
break;
case IPC_SET: /*cambios en un segmento*/
if (current->euid == shp->u.shm_perm.uid ||
current->euid == shp->u.shm_perm.cuid ||
capable(CAP_SYS_ADMIN)) {
ipcp->uid = tbuf.shm_perm.uid;
ipcp->gid = tbuf.shm_perm.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
| (tbuf.shm_perm.mode & S_IRWXUGO);
shp->u.shm_ctime = CURRENT_TIME;
break;
}
err = -EPERM;
goto out;
case IPC_RMID:/*marcar un segmento de memoria como destruido*/
if (current->euid == shp->u.shm_perm.uid ||
current->euid == shp->u.shm_perm.cuid ||
capable(CAP_SYS_ADMIN)) {
shp->u.shm_perm.mode |= SHM_DEST;
if (shp->u.shm_nattch <= 0)
killseg (id);
break;
}
err = -EPERM;
goto out;
default:
err = -EINVAL;
goto out;
}
err = 0;
out:
unlock_kernel();
return err;
}
/*funcion que permite vincular una zona de memoria compartida a un proceso*/
asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
{
struct shmid_kernel *shp;
struct vm_area_struct *shmd;
int err = -EINVAL;
unsigned int id;
Universidad de Las Palmas de Gran Canaria
24-13
Memoria Compartida
unsigned long addr;
unsigned long len;
down(&current->mm->mmap_sem);
lock_kernel();
if (shmid < 0) {
goto out;
}
shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
if (shp == IPC_UNUSED || shp == IPC_NOID) {
goto out;
}
if (!(addr = (ulong) shmaddr)) {
if (shmflg & SHM_REMAP)
goto out;
err = -ENOMEM;
addr = 0;
again:
if (!(addr = get_unmapped_area(addr, shp->u.shm_segsz)))
goto out;
if(addr & (SHMLBA - 1)) {
addr = (addr + (SHMLBA - 1)) & ~(SHMLBA - 1);
goto again;
}
} else if (addr & (SHMLBA-1)) {
if (shmflg & SHM_RND)
addr &= ~(SHMLBA-1);
/* round down */
else
goto out;
}
/*
* Check if addr exceeds TASK_SIZE (from do_mmap)
*/
len = PAGE_SIZE*shp->shm_npages;
err = -EINVAL;
if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len)
goto out;
/*
* If shm segment goes below stack, make sure there is some
* space left for the stack to grow (presently 4 pages).
*/
if (addr < current->mm->start_stack &&
addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
{
/* printk("shmat() -> EINVAL because segment intersects stack\n"); */
goto out;
}
if (!(shmflg & SHM_REMAP))
Universidad de Las Palmas de Gran Canaria
24-14
Memoria Compartida
if ((shmd = find_vma_intersection(current->mm, addr, addr + shp>u.shm_segsz))) {
/* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx)
intersects an already mapped interval [0x%lx,0x%lx).\n",
addr, addr + shp->shm_segsz, shmd->vm_start, shmd>vm_end); */
goto out;
}
err = -EACCES;
if (ipcperms(&shp->u.shm_perm, shmflg & SHM_RDONLY ? S_IRUGO :
S_IRUGO|S_IWUGO))
goto out;
err = -EIDRM;
if (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)
goto out;
err = -ENOMEM;
shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
if (!shmd)
goto out;
if ((shp != shm_segs[id]) || (shp->u.shm_perm.seq != (unsigned int) shmid /
SHMMNI)) {
kmem_cache_free(vm_area_cachep, shmd);
err = -EIDRM;
goto out;
}
shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id);
shmd->vm_start = addr;
shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
shmd->vm_mm = current->mm;
shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY :
PAGE_SHARED;
shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
| VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
| ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE |
VM_WRITE);
shmd->vm_file = NULL;
shmd->vm_offset = 0;
shmd->vm_ops = &shm_vm_ops;
shp->u.shm_nattch++;
/* prevent destruction */
if ((err = shm_map (shmd))) {
if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode
SHM_DEST)
killseg(id);
kmem_cache_free(vm_area_cachep, shmd);
goto out;
}
Universidad de Las Palmas de Gran Canaria
24-15
&
Memoria Compartida
insert_attach(shp,shmd); /* insert shmd into shp->attaches */
shp->u.shm_lpid = current->pid;
shp->u.shm_atime = CURRENT_TIME;
*raddr = addr;
err = 0;
out:
unlock_kernel();
up(&current->mm->mmap_sem);
return err;
}
asmlinkage int sys_shmdt (char *shmaddr)
{
struct vm_area_struct *shmd, *shmdnext;
down(&current->mm->mmap_sem);
lock_kernel();
for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
shmdnext = shmd->vm_next;
if (shmd->vm_ops == &shm_vm_ops
&& shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
do_munmap(shmd->vm_start,
shmd->vm_end
>vm_start);
}
unlock_kernel();
up(&current->mm->mmap_sem);
return 0;
}
Universidad de Las Palmas de Gran Canaria
24-16
shmd-
Memoria Compartida
Universidad de Las Palmas de Gran Canaria
24-1
Descargar