⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shm.c

📁 linux1.1源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/ipc/shm.c * Copyright (C) 1992, 1993 Krishna Balasubramanian  *         Many improvements/fixes by Bruno Haible. * assume user segments start at 0x0 */#include <linux/errno.h>#include <asm/segment.h>#include <linux/sched.h>#include <linux/ipc.h> #include <linux/shm.h>#include <linux/stat.h>#include <linux/malloc.h>extern int ipcperms (struct ipc_perm *ipcp, short semflg);extern unsigned int 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 shm_desc *shmd, int remap);static void killseg (int id);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;static struct shmid_ds *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;void shm_init (void){	int id;           	for (id = 0; id < SHMMNI; id++) 		shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;	shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;	shm_lock = NULL;	return;}static int findkey (key_t key)    {	int id;	struct shmid_ds *shp;		for (id=0; id <= max_shmid; id++) {		while ((shp = shm_segs[id]) == IPC_NOID) 			sleep_on (&shm_lock);		if (shp == IPC_UNUSED)			continue;		if (key == shp->shm_perm.key) 			return id;	}	return -1;}/*  * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID. */static int newseg (key_t key, int shmflg, int size){	struct shmid_ds *shp;	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;	int id, i;	if (size < SHMMIN)		return -EINVAL;	if (shm_tot + numpages >= SHMALL)		return -ENOSPC;	for (id=0; id < SHMMNI; id++)		if (shm_segs[id] == IPC_UNUSED) {			shm_segs[id] = (struct shmid_ds *) IPC_NOID;			goto found;		}	return -ENOSPC;found:	shp = (struct shmid_ds *) kmalloc (sizeof (*shp), GFP_KERNEL);	if (!shp) {		shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;		if (shm_lock)			wake_up (&shm_lock);		return -ENOMEM;	}	shp->shm_pages = (ulong *) kmalloc (numpages*sizeof(ulong),GFP_KERNEL);	if (!shp->shm_pages) {		shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;		if (shm_lock)			wake_up (&shm_lock);		kfree_s (shp, sizeof (*shp));		return -ENOMEM;	}	for (i=0; i< numpages; shp->shm_pages[i++] = 0);	shm_tot += numpages;	shp->shm_perm.key = key;	shp->shm_perm.mode = (shmflg & S_IRWXUGO);	shp->shm_perm.cuid = shp->shm_perm.uid = current->euid;	shp->shm_perm.cgid = shp->shm_perm.gid = current->egid;	shp->shm_perm.seq = shm_seq;	shp->shm_segsz = size;	shp->shm_cpid = current->pid;	shp->attaches = NULL;	shp->shm_lpid = shp->shm_nattch = 0;	shp->shm_atime = shp->shm_dtime = 0;	shp->shm_ctime = CURRENT_TIME;	shp->shm_npages = numpages;	if (id > max_shmid)		max_shmid = id;	shm_segs[id] = shp;	used_segs++;	if (shm_lock)		wake_up (&shm_lock);	return id + (int)shm_seq*SHMMNI;}int sys_shmget (key_t key, int size, int shmflg){	struct shmid_ds *shp;	int id = 0;		if (size < 0 || size > SHMMAX)		return -EINVAL;	if (key == IPC_PRIVATE) 		return newseg(key, shmflg, size);	if ((id = findkey (key)) == -1) {		if (!(shmflg & IPC_CREAT))			return -ENOENT;		return newseg(key, shmflg, size);	} 	if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))		return -EEXIST;	shp = shm_segs[id];	if (shp->shm_perm.mode & SHM_DEST)		return -EIDRM;	if (size > shp->shm_segsz)		return -EINVAL;	if (ipcperms (&shp->shm_perm, shmflg))		return -EACCES;	return shp->shm_perm.seq*SHMMNI + id;}/*  * Only called after testing nattch and SHM_DEST. * Here pages, pgtable and shmid_ds are freed. */static void killseg (int id){	struct shmid_ds *shp;	int i, numpages;	ulong page;	shp = shm_segs[id];	if (shp == IPC_NOID || shp == IPC_UNUSED) {		printk ("shm nono: killseg called on unused seg id=%d\n", id);		return;	}	shp->shm_perm.seq++;     /* for shmat */	numpages = shp->shm_npages; 	shm_seq++;	shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;	used_segs--;	if (id == max_shmid) 		while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));	if (!shp->shm_pages) {		printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);		return;	}	for (i=0; i< numpages ; i++) {		if (!(page = shp->shm_pages[i]))			continue;		if (page & 1) {			free_page (page & PAGE_MASK);			shm_rss--;		} else {			swap_free (page);			shm_swp--;		}	}	kfree_s (shp->shm_pages, numpages * sizeof (ulong));	shm_tot -= numpages;	kfree_s (shp, sizeof (*shp));	return;}int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf){	struct shmid_ds *shp, tbuf;	struct ipc_perm *ipcp;	int id, err;		if (cmd < 0 || shmid < 0)		return -EINVAL;	if (cmd == IPC_SET) {		if (!buf)			return -EFAULT;		err = verify_area (VERIFY_READ, buf, sizeof (*buf));		if (err)			return err;		memcpy_fromfs (&tbuf, buf, sizeof (*buf));	}	switch (cmd) { /* replace with proc interface ? */	case IPC_INFO: 	{		struct shminfo shminfo;		if (!buf)			return -EFAULT;		shminfo.shmmni = SHMMNI;		shminfo.shmmax = SHMMAX;		shminfo.shmmin = SHMMIN;		shminfo.shmall = SHMALL;		shminfo.shmseg = SHMSEG;		err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo));		if (err)			return err;		memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));		return max_shmid;	}	case SHM_INFO: 	{ 		struct shm_info shm_info;		if (!buf)			return -EFAULT;		err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));		if (err)			return err;		shm_info.used_ids = used_segs; 		shm_info.shm_rss = shm_rss;		shm_info.shm_tot = shm_tot;		shm_info.shm_swp = shm_swp;		shm_info.swap_attempts = swap_attempts;		shm_info.swap_successes = swap_successes;		memcpy_tofs (buf, &shm_info, sizeof(shm_info));		return max_shmid;	}	case SHM_STAT:		if (!buf)			return -EFAULT;		err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));		if (err)			return err;		if (shmid > max_shmid)			return -EINVAL;		shp = shm_segs[shmid];		if (shp == IPC_UNUSED || shp == IPC_NOID)			return -EINVAL;		if (ipcperms (&shp->shm_perm, S_IRUGO))			return -EACCES;		id = shmid + shp->shm_perm.seq * SHMMNI; 		memcpy_tofs (buf, shp, sizeof(*shp));		return id;	}		shp = shm_segs[id = shmid % SHMMNI];	if (shp == IPC_UNUSED || shp == IPC_NOID)		return -EINVAL;	ipcp = &shp->shm_perm;	if (ipcp->seq != shmid / SHMMNI) 		return -EIDRM;		switch (cmd) {	case SHM_UNLOCK:		if (!suser())			return -EPERM;		if (!(ipcp->mode & SHM_LOCKED))			return -EINVAL;		ipcp->mode &= ~SHM_LOCKED;		break;	case SHM_LOCK:/* 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 */		if (!suser())			return -EPERM;		if (ipcp->mode & SHM_LOCKED)			return -EINVAL;		ipcp->mode |= SHM_LOCKED;		break;	case IPC_STAT:		if (ipcperms (ipcp, S_IRUGO))			return -EACCES;		if (!buf)			return -EFAULT;		err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));		if (err)			return err;		memcpy_tofs (buf, shp, sizeof(*shp));		break;	case IPC_SET:		if (suser() || current->euid == shp->shm_perm.uid ||		    current->euid == shp->shm_perm.cuid) {			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->shm_ctime = CURRENT_TIME;			break;		}		return -EPERM;	case IPC_RMID:		if (suser() || current->euid == shp->shm_perm.uid ||		    current->euid == shp->shm_perm.cuid) {			shp->shm_perm.mode |= SHM_DEST;			if (shp->shm_nattch <= 0) 				killseg (id);			break;		}		return -EPERM;	default:		return -EINVAL;	}	return 0;}/* * check range is unmapped, ensure page tables exist * mark page table entries with shm_sgn. * if remap != 0 the range is remapped. */static int shm_map (struct shm_desc *shmd, int remap){	unsigned long invalid = 0;	unsigned long *page_table;	unsigned long tmp, shm_sgn;	unsigned long page_dir = shmd->task->tss.cr3;		/* check that the range is unmapped and has page_tables */	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);		if (*page_table & PAGE_PRESENT) {			page_table = (ulong *) (PAGE_MASK & *page_table);			page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));			if (*page_table) {				if (!remap)					return -EINVAL;				if (*page_table & PAGE_PRESENT) {					--current->rss;					free_page (*page_table & PAGE_MASK);				}				else					swap_free (*page_table);				invalid++;			}			continue;		}  	      {		unsigned long new_pt;		if(!(new_pt = get_free_page(GFP_KERNEL)))	/* clearing needed?  SRB. */			return -ENOMEM;		*page_table = new_pt | PAGE_TABLE;		tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);	}}	if (invalid)		invalidate();	/* map page range */	shm_sgn = shmd->shm_sgn;	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, 	     shm_sgn += (1 << SHM_IDX_SHIFT)) { 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -