1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > linux实现内存共享 Linux共享内存实现

linux实现内存共享 Linux共享内存实现

时间:2024-06-07 09:03:58

相关推荐

linux实现内存共享 Linux共享内存实现

Shm是Unix进程间通信最常见也最重要的方法之一。

它是如何实现的呢?

我们来看下入下内容。

初始化:

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;

}寻找共享内存的ID。

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;

}

获取共享内存:

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;

}

共享内存属性设置:

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;

}

SHM的SWAP:

/*

* Goes through counter = (shm_rss << prio) present shm pages.

*/

static unsigned long swap_id = 0; /* currently being swapped */

static unsigned long swap_idx = 0; /* next to swap */

int shm_swap (int prio)

{

unsigned long page;

struct shmid_ds *shp;

struct shm_desc *shmd;

unsigned int swap_nr;

unsigned long id, idx, invalid = 0;

int counter;

counter = shm_rss >> prio;

if (!counter || !(swap_nr = get_swap_page()))

return 0;

check_id:

shp = shm_segs[swap_id];

if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {

swap_idx = 0;

if (++swap_id > max_shmid)

swap_id = 0;

goto check_id;

}

id = swap_id;

check_table:

idx = swap_idx++;

if (idx >= shp->shm_npages) {

swap_idx = 0;

if (++swap_id > max_shmid)

swap_id = 0;

goto check_id;

}

page = shp->shm_pages[idx];

if (!(page & PAGE_PRESENT))

goto check_table;

swap_attempts++;

if (--counter < 0) { /* failed */

if (invalid)

invalidate();

swap_free (swap_nr);

return 0;

}

for (shmd = shp->attaches; shmd; shmd = shmd->seg_next) {

unsigned long tmp, *pte;

if ((shmd->shm_sgn >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {

printk ("shm_swap: id=%ld does not match shmd\n", id);

continue;

}

tmp = shmd->start + (idx << PAGE_SHIFT);

if (tmp >= shmd->end) {

printk ("shm_swap: too large idx=%ld id=%ld PANIC\n",idx, id);

continue;

}

pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);

if (!(*pte & 1)) {

printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",

id, shmd->start, idx);

*pte = 0;

continue;

}

pte = (ulong *) (PAGE_MASK & *pte);

pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));

tmp = *pte;

if (!(tmp & PAGE_PRESENT))

continue;

if (tmp & PAGE_ACCESSED) {

*pte &= ~PAGE_ACCESSED;

continue;

}

tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;

*pte = tmp;

mem_map[MAP_NR(page)]--;

shmd->task->rss--;

invalid++;

}

if (mem_map[MAP_NR(page)] != 1)

goto check_table;

page &= PAGE_MASK;

shp->shm_pages[idx] = swap_nr;

if (invalid)

invalidate();

write_swap_page (swap_nr, (char *) page);

free_page (page);

swap_successes++;

shm_swp++;

shm_rss--;

return 1;

} 其实,共享内存并非神秘的魔域。它也就仅仅是个资源管理方案而已。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。