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
- Lines: 184
- Date:
Tue Nov 9 10:02:36 1999
- Orig file:
v2.3.26/linux/ipc/util.c
- Orig date:
Sun Nov 7 16:37:34 1999
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)