patch-2.3.27 linux/ipc/util.c

Next file: linux/ipc/util.h
Previous file: linux/ipc/shm.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.26/linux/ipc/util.c linux/ipc/util.c
@@ -6,6 +6,8 @@
  *            get BSD style process accounting right.
  *            Occurs in several places in the IPC code.
  *            Chris Evans, <chris@ferret.lmh.ox.ac.uk>
+ * Nov 1999 - ipc helper functions, unified SMP locking
+ *	      Manfred Spraul <manfreds@colorfullife.com>
  */
 
 #include <linux/config.h>
@@ -13,12 +15,13 @@
 #include <linux/shm.h>
 #include <linux/init.h>
 #include <linux/msg.h>
-
-#include "util.h"
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
 
 #if defined(CONFIG_SYSVIPC)
 
-extern void sem_init (void), msg_init (void), shm_init (void);
+#include "util.h"
 
 void __init ipc_init (void)
 {
@@ -26,6 +29,157 @@
 	msg_init();
 	shm_init();
 	return;
+}
+
+void __init ipc_init_ids(struct ipc_ids* ids, int size)
+{
+	int i;
+	sema_init(&ids->sem,1);
+	ids->size = size;
+	if(size == 0)
+		return;
+	if(size > IPCMNI)
+		size = IPCMNI;
+
+	ids->in_use = 0;
+	ids->max_id = -1;
+	ids->seq = 0;
+	{
+		int seq_limit = INT_MAX/SEQ_MULTIPLIER;
+		if(seq_limit > USHRT_MAX)
+			ids->seq_max = USHRT_MAX;
+		 else
+		 	ids->seq_max = seq_limit;
+	}
+
+	ids->entries = ipc_alloc(sizeof(struct ipc_id)*size);
+
+	if(ids->entries == NULL) {
+		printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
+		ids->size = 0;
+	}
+	ids->ary = SPIN_LOCK_UNLOCKED;
+	for(i=0;i<size;i++) {
+		ids->entries[i].p = NULL;
+	}
+}
+
+int ipc_findkey(struct ipc_ids* ids, key_t key)
+{
+	int id;
+	struct ipc_perm* p;
+
+	for (id = 0; id <= ids->max_id; id++) {
+		p = ids->entries[id].p;
+		if(p==NULL)
+			continue;
+		if (key == p->key)
+			return id;
+	}
+	return -1;
+}
+
+static int grow_ary(struct ipc_ids* ids, int newsize)
+{
+	struct ipc_id* new;
+	struct ipc_id* old;
+	int i;
+
+	if(newsize > IPCMNI)
+		newsize = IPCMNI;
+	if(newsize <= ids->size)
+		return newsize;
+
+	new = ipc_alloc(sizeof(struct ipc_id)*newsize);
+	if(new == NULL)
+		return ids->size;
+	memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size);
+	for(i=ids->size;i<newsize;i++) {
+		new[i].p = NULL;
+	}
+	spin_lock(&ids->ary);
+
+	old = ids->entries;
+	ids->entries = new;
+	i = ids->size;
+	ids->size = newsize;
+	spin_unlock(&ids->ary);
+	ipc_free(old, sizeof(struct ipc_id)*i);
+	return ids->size;
+}
+
+int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new, int size)
+{
+	int id;
+
+	size = grow_ary(ids,size);
+	for (id = 0; id < size; id++) {
+		if(ids->entries[id].p == NULL)
+			goto found;
+	}
+	return -1;
+found:
+	ids->in_use++;
+	if (id > ids->max_id)
+		ids->max_id = id;
+
+	new->cuid = new->uid = current->euid;
+	new->gid = new->cgid = current->egid;
+
+	new->seq = ids->seq++;
+	if(ids->seq > ids->seq_max)
+		ids->seq = 0;
+
+	ipc_lock(ids,id);
+	ids->entries[id].p = new;
+	return id;
+}
+
+struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
+{
+	struct ipc_perm* p;
+	int lid = id % SEQ_MULTIPLIER;
+	if(lid > ids->size)
+		BUG();
+	p = ids->entries[lid].p;
+	ids->entries[lid].p = NULL;
+	if(p==NULL)
+		BUG();
+	ids->in_use--;
+
+	if (lid == ids->max_id) {
+		do {
+			lid--;
+			if(lid == -1)
+				break;
+		} while (ids->entries[lid].p == NULL);
+		ids->max_id = lid;
+	}
+	return p;
+}
+
+void* ipc_alloc(int size)
+{
+	void* out;
+	if(size > PAGE_SIZE) {
+		lock_kernel();
+		out = vmalloc(size);
+		unlock_kernel();
+	} else {
+		out = kmalloc(size, GFP_KERNEL);
+	}
+	return out;
+}
+
+void ipc_free(void* ptr, int size)
+{
+	if(size > PAGE_SIZE) {
+		lock_kernel();
+		vfree(ptr);
+		unlock_kernel();
+	} else {
+		kfree(ptr);
+	}
 }
 
 /* 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)