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