From: thf@zelator.in-berlin.de (Thomas Funke)
Subject: Shared Memory (SYS5) Sources !
Organization: Puplic-Access-Xenix-System
Date: Tue, 14 Apr 92 15:53:00 GMT


This is my first version of Shared-Memory-system-5 Calls for NeXT !!
Read the README-File for details and have fun !!


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	ipc.h
#	shm.c
#	shm.h
# This archive created: Mon Apr 13 21:38:42 1992
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X
XShared Memory for NeXT !
X------------------------
X
XThis is a quick & dirty hack to realize the standard System-V shared-memory
Xcalls on a NeXT.
X
XIf you don't understand this SW, or don't know how to use it, you should
X
X	read Stevens W.R, Unix Network programming, Prentice Hall
X
Xand NOT
X
X	ask me !
X
XI don't have time to give individual support for this SW. Of course, you
Xcan still hire me.
X
XHowever, if you know how to use this SW and find bugs or improvements, 
Xyou're invited to inform me under the following address:
X
X	Thomas Funke
X	Gasteinerstr. 29
X	1000 Berlin 31
X	Germany
X	
X	E-mail: thf@zelator.in-berlin.de
X
XI'd like to hear from you also if you could get some system-v-pd-sw to
Xrun successfully with these calls. How about POSTGRES-Database ?!
X
X
XHow it works
X------------
X
XThe nice folks at NeXT gave me a hint: there is an undocumented system
Xcall mmap(), which maps some memory to a file. mmap() can be found on
Xother systems, such as sun. So get a man-page for mmap() from you local
Xsun-guru.
X
XThe file can be a zero-length file, thus it just identifies the 
Xshared-memory block.
X
XSo for every shared-mem-block I create a file under the directory
X/tmp/.sharedmem. That file has the name
X
X	key.shmid.size
X
Xto identify the key, the shmid and the size. The shmid is always dependant
Xon the pid of the process which does the shmget() call.	
X
XThe actual attachement will be done with the shmat() call. Usually
Xwe allocate the memory with vm_allocate() and then do a mmap() on
Xthis block and the corresponding file. 
X
XThe shmdt() call will free the allocated block and close the file
Xfor which we did the mmap().
X
XFinally, the shmctl() with a command IPC_RMID will remove the
Xfile. You should always use this call to cleanup the .sharedmem-directory.
XTill now, we don't allow any other command for this call, someone is
Xgoing to fix that ?
X
XLook at the sources, I hope they are understandable.
X
X
XHow to install
X--------------
X
XCopy shm.h and ipc.h to /usr/include/sys.
XTranslate shm.c and link it together with you application. 
X
XIf you want a demo, run 'cc -DDEBUG shm.c' and run two copies of a.out.
X
XWarning
X-------
X
XThe mmap() system call might be abolished in later versions of NeXT-OS.
XSo programs will not run. I'm not sure about OS3.0, probably it'll still
Xbe ok.
X
XWhat to do next ?
X-----------------
X
XShared memory is very useful only with semaphores. So perhabs someone
Xcan realize the System-V semaphore-calls ? My idea is: Allocate a
Xshared-memory block and then use mach-mutex calls on this. I'm not sure
Xif this would work.
X
XI'll not do this in the near future, so you have to do it yourself!
X
XHave fun.
X	
X
X	
X	
SHAR_EOF
fi # end of overwriting check
if test -f 'ipc.h'
then
	echo shar: will not over-write existing file "'ipc.h'"
else
sed 's/^X//' << \SHAR_EOF > 'ipc.h'
X
X/* ipc.h for NeXT
X *
X * Copyright (c) 1992 Thomas Funke
X *                    thf@zelator.in-berlin.de
X */
X
X/*
XThis program is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation (any version).
X
XThis program is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with this program; see the file COPYING.  If not, write to
Xthe Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X#ifndef _IPC_H
X#define _IPC_H
X
X
Xtypedef long key_t; /* We don't have it on NeXT */
X
Xstruct ipc_perm {
X	uid_t		uid;		/* owner's user id	*/
X	gid_t		gid;		/* owner's group id	*/
X	uid_t		cuid;		/* creator's user id	*/
X	gid_t		cgid;		/* creator's group id	*/
X	unsigned short	mode;		/* access modes		*/
X	unsigned short	seq;		/* slot usage sequence number */
X	key_t		key;		/* key			*/
X}; /* Not used yet */
X
X/* IPC operation flag definitions */
X#define	IPC_CREAT	0001000		/* create entry if key doesn't exist */
X#define	IPC_EXCL	0002000		/* fail if key exists */
X#define	IPC_NOWAIT	0004000		/* error if request must wait */
X
X/* Keys. */
X#define	IPC_PRIVATE	(key_t)0	/* private key */
X
X/* Control Commands. */
X#define	IPC_RMID	0	/* remove identifier */
X#define	IPC_SET		1	/* set options */
X#define	IPC_STAT	2	/* get options */
X
X/* Common ipc_perm mode Definitions. */
X#define	IPC_R		0000400		/* read or receive permission       */
X#define	IPC_W		0000200		/* write or send permission	    */
X
X#endif 
X
X
X
X
X
SHAR_EOF
fi # end of overwriting check
if test -f 'shm.c'
then
	echo shar: will not over-write existing file "'shm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shm.c'
X
X/* shm.c
X * Realizes  Shared-Memory for NeXT
X * Copyright (c) 1992 Thomas Funke
X *                    thf@zelator.in-berlin.de
X */
X
X/*
XThis program is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation (any version).
X
XThis program is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with this program; see the file COPYING.  If not, write to
Xthe Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <string.h>
X#include <stdio.h>
X#include <sys/param.h>
X#include <libc.h>
X#include <sys/errno.h>
X#include <sys/mman.h>
X#include <mach.h>
X
X#include "ipc.h"
X#include "shm.h"
X
Xtypedef char String [80];
X
X/* Undocumented mmap function gives us true shared memory */
Xextern char *mmap(caddr_t addr, size_t len, int prot, int flags, 
X    int fd, off_t off);
X
X/* Max count of shared memory areas for each prozess */
X#define MAX_SHMEM 20
X
X/* Create all Files for mmap in the SHMDIR */
X#define SHMDIR "/tmp/.sharedmem"
X
X/* On error release memory for directory
X * and set errno
X */
X#define RETURN_ERROR(err) { errno = err; freeDir(nlsize); return -1; }
X#define RETURN(val)   { freeDir(nlsize); return val; }
X
X/* Store the shared-mem directory */
Xstatic struct direct **namelist;
Xstatic int nlsize;
X
X/* Remember what we have attached */
X
Xstatic struct {
X    int shmid;  /* Shared memory ID */
X    int fd;     /* Filedescr. */
X    char *mem;  /* start of shared memory area */
X    int size;   /* Size of Block */
X} attached [ MAX_SHMEM] = {0}; 
X
X/* Remember how many shmget's we did */
Xstatic int getcount = 0;
X
Xstatic int getAttachedEntry (void)
X/* Find a free entry in the attached-Table */
X{
X    int i;
X    
X    for (i=0; i < MAX_SHMEM; i++) {
X	if (attached [i].shmid == 0)
X	    return i;
X    }
X    
X    return -1; /* Not found */
X}
X
Xstatic int openDir(void)
X/* read the SHMDIR and create it if notexistant 
X * returns number of entries or -1 if error
X */
X{    
X    umask (0);
X    mkdir (SHMDIR, 0777);
X    
X    nlsize = scandir (SHMDIR, &namelist, NULL, NULL);
X    
X    return nlsize;
X}
X
Xstatic freeDir (int nlsize)
X/* Release the Memory for openDir -- don't forget to call ! */
X{
X    int i;
X    
X    for (i=0; i < nlsize; i++) {
X	free (namelist[i]);
X    }
X    
X    free (namelist);
X
X}
X
Xstatic int getShmID (int key, int size)
X/* Search in SHMDIR for key 
X * if size > actual size return -1 !
X */
X{
X    int i;
X    struct direct *dp;
X    int k = -1, shmid = -1, s = -1;
X    
X    for (i = 0; i < nlsize; i++) {
X	dp = namelist[i];
X	
X	if (dp->d_name[0] == '.') continue; /* ignore ., .. */
X
X	k = -1;
X	sscanf (dp->d_name, "%d.%d.%d", &k, &shmid, &s);
X	if (k == key) return shmid;
X    }	
X    return -1;
X}
X
Xstatic int newEntry (int key, int size, int shmflag)
X/* create new entry in filesystem, return shmid */
X{
X
X	int pid = getpid (), fd;
X	String s;
X	int shmid = pid * MAX_SHMEM + getcount;
X	
X	if (getcount > MAX_SHMEM) { /* Too many shmget's */
X	    errno = ENOMEM;
X	    return -1;
X	}
X	
X	/* Create new entry */
X	sprintf (s, "%s/%d.%d.%d", SHMDIR, key, shmid, size); /* Filename */
X	fd = creat (s, shmflag & 0666);
X	if (fd < 0) return -1;
X	
X	close (fd);
X	getcount++;
X	return shmid; /* shmid is pid * 100 + getcount */
X}
X
Xint shmget (key_t key, int size, int shmflag)
X{
X    int fd, shmid;
X    String s;
X    
X    nlsize = openDir ();
X    if (nlsize < 0) return -1; /* No success */
X            
X    if (key == IPC_PRIVATE) {
X	RETURN (newEntry (key, size, shmflag));	
X    }
X    
X    /* Not a private key */
X    
X    /* Does key exist ? */
X    
X    if ((shmid= getShmID (key, size)) < 0) { /* Key does NOT exist */
X	if ((shmflag & IPC_CREAT) == 0)
X	    RETURN_ERROR (ENOENT);
X	
X	RETURN (newEntry (key, size, shmflag))
X    }
X    
X    if ( (shmflag & IPC_CREAT) && (shmflag & IPC_EXCL)) 
X	RETURN_ERROR (EEXIST);
X    
X    RETURN(shmid);
X}
X
Xchar *shmat (int shmid, char *addr, int shmflag)
X/* Attach to the shared memory given by shmid */
X{
X    int i, fd, mapflag, entry;
X    struct direct *dp;
X    int k = -1, sid = -1, size = -1;
X    char *mapaddr;
X    String s;
X    
X    entry = getAttachedEntry();
X    if (entry < 0) { /* Too many shared memory areas */
X	errno = ENOMEM;
X	return -1;
X    };
X    
X    nlsize = openDir ();
X    if (nlsize < 0) return -1; /* No success */
X    
X    for (i = 0; i < nlsize; i++) {
X	dp = namelist[i];
X	
X	if (dp->d_name[0] == '.') continue; /* ignore ., .. */
X	
X	sscanf (dp->d_name, "%d.%d.%d", &k, &sid, &size);
X	if (shmid == sid) break;
X    }
X    
X    if (shmid != sid) 
X	RETURN_ERROR (EINVAL);
X    
X    sprintf (s, "%s/%s", SHMDIR, dp->d_name);
X    fd = open(s, O_RDWR, 0);
X    if (fd < 0)
X	RETURN_ERROR (errno);
X    
X    if (addr == NULL) { /* Allocate virtual memory */
X    	if (vm_allocate(current_task(), (vm_address_t *)&mapaddr, size, TRUE)
X	    !=  KERN_SUCCESS)
X	    RETURN_ERROR (ENOMEM);
X    }
X    else
X	mapaddr = addr; /* Not sure if this works .... */
X    
X    /* Now do the map */
X    
X    if (shmflag & SHM_RDONLY)
X	mapflag = PROT_READ;
X    else
X	mapflag = PROT_READ | PROT_WRITE;
X        
X    if ((int) mmap(mapaddr, size, mapflag, MAP_SHARED, fd, 0) < 0)
X	RETURN_ERROR (errno);
X    
X    /* Now enter the values into the 'attached'-Table */
X    
X    attached[entry].shmid = shmid;
X    attached[entry].fd = fd;
X    attached[entry].mem = mapaddr;
X    attached[entry].size = size;
X    
X    RETURN (mapaddr);
X}
X
Xint shmdt (char *shmaddr)
X{
X    int i;
X    
X    if (shmaddr == NULL) {
X	errno = EINVAL;
X	return -1;
X    }
X    
X    for (i = 0; i < MAX_SHMEM; i++) {
X	if ((attached[i].shmid != 0) && (attached[i].mem == shmaddr)) {
X	    vm_deallocate
X		(current_task(), (vm_address_t) shmaddr, attached[i].size);
X	    attached[i].shmid = 0;
X	    attached[i].mem = NULL;
X	    close (attached[i].fd);
X	    return 0;
X	}
X    }
X    
X    errno = EINVAL;
X    return -1; /* Not found */
X}
X
Xint shmctl (int shmid, int cmd, struct shmid_ds *buf)
X{
X    int i, fd, mapflag;
X    struct direct *dp;
X    int k = -1, sid = -1, size = -1;
X    char *mapaddr;
X    String s;
X    
X    if (cmd != IPC_RMID) { /* We have only this ! */
X        errno = EINVAL;
X	return -1;
X    }
X	
X    nlsize = openDir ();
X    if (nlsize < 0) return -1; /* No success */
X    
X    for (i = 0; i < nlsize; i++) {
X	dp = namelist[i];
X	
X	if (dp->d_name[0] == '.') continue; /* ignore ., .. */
X	
X	sscanf (dp->d_name, "%d.%d.%d", &k, &sid, &size);
X	if (shmid == sid) break;
X    }
X    
X    if (shmid != sid) 
X	RETURN_ERROR (EINVAL);
X    
X    sprintf (s, "%s/%s", SHMDIR, dp->d_name);
X    if (unlink (s) < 0)
X	RETURN_ERROR (errno);
X    
X    RETURN (0);
X}
X
X#ifdef DEBUG 
Xmain()
X/* Run two copies of this program and look at the output */
X{
X    int shmid, i;
X
X    char * mem;
X    
X    shmid = shmget (2, 2000, 0666 | IPC_CREAT);
X    if (shmid < 0) {
X	perror ("shmget");
X	exit (1);
X    }
X    
X    mem = shmat (shmid, NULL, 0);
X    
X    if ((int) mem == -1) {
X	perror ("shmat");
X	exit (1);
X    }
X    
X    i= 0;
X    while (1) {
X	*mem = i;
X	printf("%d: set to %d\n", getpid(), i);
X	sleep(1);
X	printf("%d: read %d\n", getpid(), *mem);
X	i++;    
X    }
X    
X    exit (0);
X}
X#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'shm.h'
then
	echo shar: will not over-write existing file "'shm.h'"
else
sed 's/^X//' << \SHAR_EOF > 'shm.h'
X/*
X * Copyright (c) 1992 Thomas Funke
X *                    thf@zelator.in-berlin.de
X */
X
X/*
XThis program is free software; you can redistribute it and/or modify
Xit under the terms of the GNU General Public License as published by
Xthe Free Software Foundation (any version).
X
XThis program is distributed in the hope that it will be useful,
Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
XGNU General Public License for more details.
X
XYou should have received a copy of the GNU General Public License
Xalong with this program; see the file COPYING.  If not, write to
Xthe Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
X
X
X#ifndef _SHM_H_
X#define _SHM_H_
X
X/*
X *	Operation Flags.
X */
X
X#define	SHM_RDONLY	010000	/* attach read-only (else read-write) */
X#define	SHM_RND		020000	/* round attach address to SHMLBA */
X
Xstruct shmid_ds {
X	struct ipc_perm	shm_perm;	/* operation permission struct */
X	int		shm_segsz;	/* segment size */
X	int		shm_lpid;	/* pid of last shmop */
X	int		shm_cpid;	/* pid of creator */
X	unsigned short	shm_nattch;	/* current # attached */
X	unsigned short	shm_cnattch;	/* in memory # attached */
X	time_t		shm_atime;	/* last shmat time */
X	time_t		shm_dtime;	/* last shmdt time */
X	time_t		shm_ctime;	/* last change time */
X};
X
Xextern int shmget(key_t key, int size, int shmflg);
Xextern char *shmat(int shmid, char *shmaddr, int shmflg);
Xextern int shmdt(char *shmaddr);
Xextern int shmctl(int shmid, int cmd, struct shmid_ds *buf);
X
X/*
X *	ipc_perm Mode Definitions.
X */
X#define	SHM_R		IPC_R	/* read permission */
X#define	SHM_W		IPC_W	/* write permission */
X#define	SHM_DEST	02000	/* destroy segment when # attached = 0 */
X
X#endif /* _SHM_H_ */
X
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
-----------------------------------------------------------------------
Thomas Funke, Gasteinerstr. 29, 1000 Berlin 31, Germany, +49-30-8618224  
** Registered NeXT Developer **
E-mail:  thf@zelator.in-berlin.de
-----------------------------------------------------------------------