pax_global_header00006660000000000000000000000064123265100730014511gustar00rootroot0000000000000052 comment=83e9e1feaf311d7fd96d3eb37f99aa46fef8f85b yp-svipc-0.16/000077500000000000000000000000001232651007300132115ustar00rootroot00000000000000yp-svipc-0.16/.gitignore000066400000000000000000000000721232651007300152000ustar00rootroot00000000000000build dist MANIFEST yorick/*.o yorick/*.so yorick/ywrap.c yp-svipc-0.16/ChangeLog000066400000000000000000000025471232651007300147730ustar00rootroot000000000000000.14 fix typo (m_doc pointer) for python 3.x support redo 'free' fix that was undone in 0.12 update online pydoc 0.13 python 3.x support (Thibaut Paumard) fix fd leak in Y_fork 0.12 fix 'free' bug introduced in 0.11 fix 'snprintf' bug reported by compiler fix 'semtimedop' for osx fix headers fix demos 0.11 numpy array dims as intp* (platform size) 0.10 single dot version match for yorick and python key_t for macs ifdef HACKs 0.9.1 sem_init with nums=0 provides a hacked functionality and reset to 0 all the semaphores in the pool. ids must be int not long, fix the mask used in the demo 0.9 check argument passed to shm_write and msq_snd is an array keyword argument support for python cleanup the demos 0.8 add compatibility layer for semtimedop on FreeBSD/Darwin add (optional) count argument to sem_take/sem_give fix misc compilation warnings add msq support 0.4-2 semaphores var/unvar fix SHM_STAT warning fix 0.4 read(...,subscribe=) >0 interpreted as float timeout, <0 blocking 0.3 publish/subcribe capability. python/yorick common pack 0.2 extend the capabilities of shm_write to allow re-write on an existing segment if the referenced variable has the same type and dimensions as the one used during creation (i.e. first write). 0.1 Initial import, support shared memory. yp-svipc-0.16/INSTALL.python000066400000000000000000000003761232651007300155700ustar00rootroot00000000000000 cd . sudo python setup.py install rpm: python setup.py bdist_rpm sudo yum install dist/xxx.rpm osx: if you get build errors about PPC assembler not found: export ARCHFLAGS='-arch i386 -arch x86_64' sudo -E python setup.py install yp-svipc-0.16/INSTALL.yorick000066400000000000000000000000611232651007300155360ustar00rootroot00000000000000cd yorick yorick -batch make.i sudo gmake installyp-svipc-0.16/MANIFEST.in000066400000000000000000000001441232651007300147460ustar00rootroot00000000000000include MANIFEST.in include setup.py include python/svipc_module.c recursive-include common *.c *.h yp-svipc-0.16/README000066400000000000000000000037451232651007300141020ustar00rootroot00000000000000 System-V plugin for yorick / python. note: MacOSX does not provide semtimedop. The module provides a hacked implementation that emulates the behaviour. TIPS AND TRICKS: - max number of sem -> 1024 sysctl -w kernel.sem="250 32000 32 1024" sysctl -w kernel.sem="500 32000 32 1024" - (linux) the maximum amount of shared memory is a kernel config parameter. You may find what value it's using one of these commands. The value printed is a number of bytes: sysctl kernel.shmmax cat /proc/sys/kernel/shmmax You can change this value 'on the fly' issuing one of these commands as 'root'. Here 3221225472 corresponds to 3 GB sysctl -w kernel.shmmax=3221225472 echo 3221225472 > /proc/sys/kernel/shmmax To change the default value so it is setup everytime the kernel is booted: edit the file: /etc/sysctl.conf add/modify the entry: kernel.shmmax = - osx: sysctl -w kern.sysv.shmmax=33554432 sysctl -w kern.sysv.shmmin=1 sysctl -w kern.sysv.shmmni=256 sysctl -w kern.sysv.shmseg=64 sysctl -w kern.sysv.shmall=8192 kern.sysv.shmmni may no work from the command line, edit /etc/sysctl.conf and reboot. - trace memory usage of your process watch -d ps -C yorick -F watch -d ps -C python -F - "ipcs" provides some handy commands to work from the shell. consult the man page for details linux: ipcs | grep 0xbadca ipcrm -M 0xbadcafe -S 0xbadcafe ipcrm `ipcs | egrep '0x7dc' | awk '{print "-S " $1}'` ipcrm `ipcs | egrep '0x7dc' | awk '{print "-M " $1}'` ipcrm `ipcs | egrep '0x7dc' | awk '{print "-Q " $1}'` ipcrm `ipcs | egrep '0x808|0xdcb|0x101' | awk '{print "-S " $1}'` ipcrm `ipcs | egrep '0x808|0xdcb|0x101' | awk '{print "-M " $1}'` ipcrm `ipcs | egrep '0x808|0xdcb|0x101' | awk '{print "-Q " $1}'` osx: ipcrm `ipcs | egrep '0x808|0xdcb' | awk '{print "-s " $2}'` yp-svipc-0.16/common/000077500000000000000000000000001232651007300145015ustar00rootroot00000000000000yp-svipc-0.16/common/svipc.h000066400000000000000000000015421232651007300160000ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "svipc_misc.h" #include "svipc_shm.h" #include "svipc_sem.h" #include "svipc_msq.h" yp-svipc-0.16/common/svipc_misc.c000066400000000000000000000062341232651007300170110ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "svipc_misc.h" int svipc_debug = 0; #if defined(__gnu_linux__) #if !defined(__USE_GNU) #define __USE_GNU #endif #include //--------------------------------------------------------------- // svipc_setaffinity //--------------------------------------------------------------- int svipc_setaffinity(int cpu) { int status; cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(cpu, &mask); status = sched_setaffinity(0, sizeof(mask), &mask); if (status) perror("setaffinity failed"); return status; } #else int svipc_setaffinity(int cpu) { //perror("setaffinity: platform not supported"); return -1; } #endif //--------------------------------------------------------------- // svipc_ftok //--------------------------------------------------------------- key_t svipc_ftok(char *path, int proj) { key_t key = ftok(path, proj); if (key == -1) perror("ftok failed"); return key; } //--------------------------------------------------------------- // svipc_nprocs //--------------------------------------------------------------- long svipc_nprocs(void) { // These values may not be standard // _SC_NPROCESSORS_CONF - number of processors configured // _SC_NPROCESSORS_ONLN - number of processors online return sysconf(_SC_NPROCESSORS_ONLN); } //--------------------------------------------------------------- // hacks //--------------------------------------------------------------- #if !defined(__gnu_linux__) #include /* nanosleep */ #include /* EAGAIN */ int semtimedop(int semid, struct sembuf *sops, size_t nsops, struct timespec *timeout) { int status; long time_to_live; if (timeout != NULL) time_to_live = timeout->tv_sec * 1e9 + timeout->tv_nsec; else time_to_live = -1; if (time_to_live >= 0) { // poll hack sops->sem_flg |= IPC_NOWAIT; // loop while it fails, because it's unavailable, and we have not // run out of time. anything else, get out. // The order in the next statement matters: // - errno is updated by semop // - we want to semop at least once, even when timeout=0 while ((status = semop(semid, sops, nsops)) && (errno == EAGAIN) && (time_to_live > 0)) { usleep(SVIPC_USLEEP_QUANTUM); time_to_live -= SVIPC_USLEEP_QUANTUM * 1e3; // ns. } } else { // regular semop status = semop(semid, sops, nsops); } return status; } #endif yp-svipc-0.16/common/svipc_misc.h000066400000000000000000000040161232651007300170120ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SVIPC_MISC_H) #define SVIPC_MISC_H #ifdef __cplusplus extern "C" { #endif /******************************************************************* * compat hacks *******************************************************************/ #if !defined(__gnu_linux__) #include // key_t for OSX, BSD #include // quantum of time in microseconds to sleep between timedop tries. #define SVIPC_USLEEP_QUANTUM 1e3 // 1 ms. fine for scripting int semtimedop(int semid, struct sembuf *sops, size_t nsops, struct timespec *timeout); #endif /******************************************************************* * plugin *******************************************************************/ int svipc_setaffinity(int cpu); key_t svipc_ftok(char *path, int proj); long svipc_nprocs(void); /******************************************************************* * debug *******************************************************************/ extern int svipc_debug; #define Debug(level, fmt, ...) { \ if(level<=svipc_debug) { \ fprintf (stderr,"(%02d) %15s:%-4d - %15s: ",level,__FILE__,__LINE__,__PRETTY_FUNCTION__); \ fprintf (stderr, fmt, ## __VA_ARGS__); \ fflush (stderr); \ } \ } #ifdef __cplusplus } #endif #endif yp-svipc-0.16/common/svipc_msq.c000066400000000000000000000111561232651007300166550ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "svipc_misc.h" #include "svipc_msq.h" //--------------------------------------------------------------- // svipc_msq_init //--------------------------------------------------------------- int svipc_msq_init(key_t key) { int msgqid; Debug(5, "svipc_msq_init %x\n", key); msgqid = msgget(key, IPC_CREAT | IPC_PRIVATE | IPC_EXCL | 0666); if (msgqid == -1) { perror("msgget failed"); return -1; } return 0; } //--------------------------------------------------------------- // svipc_msq_cleanup //--------------------------------------------------------------- int svipc_msq_cleanup(key_t key) { int msgqid; Debug(5, "svipc_msq_cleanup\n"); msgqid = msgget(key, 0666); if (msgqid == -1) { perror("msgget failed"); return -1; } int status = msgctl(msgqid, IPC_RMID, NULL); if (status == -1) { perror("msgctl IPC_RMID failed"); return -1; } return 0; } //--------------------------------------------------------------- // svipc_msq_info //--------------------------------------------------------------- int svipc_msq_info(key_t key, int details) { int msgqid, status; Debug(5, "svipc_msq_info %x\n", key); msgqid = msgget(key, 0666); if (msgqid == -1) { perror("msgget failed"); return -1; } struct msqid_ds stat; status = msgctl(msgqid, IPC_STAT, &stat); if (status == -1) { perror("msgctl IPC_STAT failed"); return -1; } if (details) { fprintf(stderr, "MsgQ msqid: 0x%x id: %d\n", key, msgqid); fprintf(stderr, "Last snd time: %s", ctime(&stat.msg_stime)); fprintf(stderr, "Last rcv time: %s", ctime(&stat.msg_rtime)); fprintf(stderr, "Maximum number of bytes allowed in queue: %ld\n", stat.msg_qbytes); fprintf(stderr, "PID of last msgsnd: %d\n", stat.msg_lspid); fprintf(stderr, "PID of last msgrcv: %d\n", stat.msg_lrpid); } fprintf(stderr, "Current number of messages in queue: %ld\n", stat.msg_qnum); return 0; } //--------------------------------------------------------------- // svipc_msq_snd //--------------------------------------------------------------- int svipc_msq_snd(key_t key, struct svipc_msgbuf *sendmsg, size_t msgsz, int nowait) { int msgqid, status; Debug(5, "svipc_msq_snd %x\n", key); msgqid = msgget(key, 0666); if (msgqid == -1) { perror("msgget failed"); return -1; } // look how big is the queue struct msqid_ds stat; status = msgctl(msgqid, IPC_STAT, &stat); if (status == -1) { perror("msgctl IPC_STAT failed"); return -1; } if (msgsz > stat.msg_qbytes) { perror("msg too big for queue!"); return -1; } int msgflg = nowait ? IPC_NOWAIT : 0; status = msgsnd(msgqid, sendmsg, msgsz, msgflg); if (status == -1) { perror("msgget failed"); return -1; } Debug(1, "msgsnd mtype %ld - nbytes %d sent\n", sendmsg->mtype, (int)msgsz); return 0; } //--------------------------------------------------------------- // svipc_msq_rcv //--------------------------------------------------------------- int svipc_msq_rcv(key_t key, long mtype, struct svipc_msgbuf **rcvmsg, int nowait) { int msgqid; Debug(5, "svipc_msq_rcv\n"); msgqid = msgget(key, 0666); if (msgqid == -1) { perror("msgget failed"); return -1; } int msgflg = nowait ? IPC_NOWAIT : 0; // look how big is the queue struct msqid_ds stat; int status = msgctl(msgqid, IPC_STAT, &stat); if (status == -1) { perror("msgctl IPC_STAT failed"); return -1; } // all rounder - one message can be as big as the queue itself *rcvmsg = malloc(sizeof(struct svipc_msgbuf) + stat.msg_qbytes); ssize_t nbytes = msgrcv(msgqid, *rcvmsg, stat.msg_qbytes, mtype, msgflg); if (nbytes == -1) { perror("msgrcv failed"); return -1; } Debug(5, "msgrcv mtype %ld - nbytes %d\n", mtype, (int)nbytes); return 0; } yp-svipc-0.16/common/svipc_msq.h000066400000000000000000000024661232651007300166660ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SVIPC_MSQ_H) #define SVIPC_MSQ_H #ifdef __cplusplus extern "C" { #endif typedef struct svipc_msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* pointer to message data */ } svipc_msgbuf; int svipc_msq_init(key_t key); int svipc_msq_cleanup(key_t key); int svipc_msq_info(key_t key, int details); int svipc_msq_snd(key_t key, struct svipc_msgbuf *sendmsg, size_t msgsz, int nowait); int svipc_msq_rcv(key_t key, long mtype, struct svipc_msgbuf **rcvmsg, int nowait); #ifdef __cplusplus } #endif #endif yp-svipc-0.16/common/svipc_sem.c000066400000000000000000000143011232651007300166340ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include /* Linux - semtimedop */ #if !defined(__USE_GNU) #define __USE_GNU #endif /* FreeBSD/Darwin - undef semun */ #if !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE #endif #include #include #include "svipc_misc.h" #include "svipc_sem.h" /******************************************************************* * define *******************************************************************/ union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ }; //--------------------------------------------------------------- // svipc_sem_init //--------------------------------------------------------------- int svipc_sem_init(key_t key, int numslots) { int i, status; int sempoolid = -1; Debug(5, "svipc_sem_init %x\n", key); if (numslots > 0) { sempoolid = semget(key, numslots, IPC_CREAT | IPC_PRIVATE | IPC_EXCL | 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } // all semaphores are locked at startup union semun semctlops; semctlops.val = 0; // fixme - SETALL perf improvement for (i = 0; i < numslots; i++) { status = semctl(sempoolid, i, SETVAL, semctlops); if (status == -1) { perror("sempoolid semctl failed"); return -1; } } } else if (numslots == 0) { // reset all the semaphores at 0 (hack functionality) sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } // find out how many sem are in the pool union semun semctlops; struct semid_ds stat; int i; semctlops.buf = &stat; status = semctl(sempoolid, 0, IPC_STAT, semctlops); if (status == -1) { perror("semctl IPC_STAT failed"); return -1; } for (i = 0; i < stat.sem_nsems; i++) { semctlops.val = 0; status = 0; status |= semctl(sempoolid, i, SETVAL, semctlops); } if (status == -1) { perror("sempoolid semctl failed"); return -1; } } else { // noop, print info return svipc_sem_info(key, 1); } return 0; } //--------------------------------------------------------------- // svipc_sem_cleanup //--------------------------------------------------------------- int svipc_sem_cleanup(key_t key) { int sempoolid; Debug(5, "svipc_sem_cleanup\n"); sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } int status = semctl(sempoolid, IPC_RMID, 0); if (status == -1) { perror("shmctl IPC_RMID failed"); return -1; } return 0; } //--------------------------------------------------------------- // svipc_sem_info //--------------------------------------------------------------- int svipc_sem_info(key_t key, int details) { int sempoolid, i, status; Debug(5, "svipc_sem_info %x\n", key); sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } union semun semctlops; struct semid_ds stat; semctlops.buf = &stat; status = semctl(sempoolid, 0, IPC_STAT, semctlops); if (status == -1) { perror("semctl IPC_STAT failed"); return -1; } if (details) { fprintf(stderr, "SemPool key: 0x%x id: %d\n", key, sempoolid); fprintf(stderr, "No. of semaphores in set: %ld\n", (long)stat.sem_nsems); // sem_nsems = long on Linux, int on freeBSD/Darwin fprintf(stderr, "Last semop time: %s", ctime(&stat.sem_otime)); fprintf(stderr, "Last change time: %s", ctime(&stat.sem_ctime)); } unsigned short *pvals = (unsigned short *)malloc(stat.sem_nsems * sizeof(unsigned short)); semctlops.array = pvals; status = semctl(sempoolid, 0, GETALL, semctlops); fprintf(stderr, "#id used? val\n"); fprintf(stderr, "----------------------\n"); for (i = 0; i < stat.sem_nsems; i++) { fprintf(stderr, "[%d] %s %2d\n", i, pvals[i] ? "Free" : "Used", pvals[i]); } free(pvals); return 0; } //--------------------------------------------------------------- // svipc_semtake //--------------------------------------------------------------- int svipc_semtake(key_t key, int id, int count, float wait) { int sempoolid, status; Debug(5, "svipc_semtake %f\n", wait); struct timespec timeout, *pto = NULL; if (wait >= 0.0) { timeout.tv_sec = (time_t) wait; timeout.tv_nsec = (long int)((wait - timeout.tv_sec) * 1e9); pto = &timeout; } sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } // take the semaphore struct sembuf sops; sops.sem_num = id; sops.sem_op = -count; // sops.sem_flg = 0; // fixme - undo if interrupted? status = semtimedop(sempoolid, &sops, 1, pto); if (status == -1) { if (errno != EAGAIN) perror("semop failed"); return -1; } return 0; } //--------------------------------------------------------------- // svipc_semgive //--------------------------------------------------------------- int svipc_semgive(key_t key, int id, int count) { int sempoolid; Debug(5, "svipc_semgive\n"); sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } // unlock the slot struct sembuf sops; sops.sem_num = id; sops.sem_op = count; sops.sem_flg = 0; int status = semop(sempoolid, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } yp-svipc-0.16/common/svipc_sem.h000066400000000000000000000021561232651007300166460ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SVIPC_SEM_H) #define SVIPC_SEM_H #ifdef __cplusplus extern "C" { #endif int svipc_sem_init(key_t key, int numslots); int svipc_sem_cleanup(key_t key); int svipc_sem_info(key_t key, int details); int svipc_semtake(key_t key, int id, int count, float wait); int svipc_semgive(key_t key, int id, int count); #ifdef __cplusplus } #endif #endif yp-svipc-0.16/common/svipc_shm.c000066400000000000000000000575741232651007300166620ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include /* Linux - semtimedop */ #if !defined(__USE_GNU) #define __USE_GNU #endif /* FreeBSD/Darwin - undef semun */ #if !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE #endif #include #include #include #include "svipc_misc.h" #define SVIPC_SZ_DEF #include "svipc_shm.h" /******************************************************************* * define *******************************************************************/ #define SLOT_DESC_STRING_MAX 80 union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ }; typedef struct { int typeID; int countdims; int flexible; } slot_segmap; typedef struct { int sss_shm_id; int sss_sem_id; int sss_lock_id; int sss_handsake_id; slot_segmap *segmap; } slot_snapshot; typedef struct { int slot_shmid; char desc[SLOT_DESC_STRING_MAX]; } slot_entry; typedef struct { int master_shmid; int master_semid; int numslots; slot_entry sse[]; } slot_master; // manages locally attached segments with a linked list typedef struct _segm { struct _segm *next; char id[SLOT_DESC_STRING_MAX]; void *addr; // the seqgment location void *pdata; // the pointer to data } _segm; // attached segment for this session // fixme: should be an array of segtable[key] _segm *segtable = NULL; //--------------------------------------------------------------- // static internals //--------------------------------------------------------------- /* static int find_master(key_t key); */ static slot_master *attach_master(key_t key); static int detach_master(slot_master * m); static int lock_master(slot_master * m); static int unlock_master(slot_master * m); static int lkup_slot(slot_master * m, char *id); static int getfree_slot(slot_master * m); static int lock_slot(slot_master * m, int slot); static int unlock_slot(slot_master * m, int slot); static int free_slot(slot_master * m, int slot); static void snap_slot(slot_master * m, int slot, slot_snapshot * sss); static int lock_snaphot(slot_snapshot * sss); static int unlock_snaphot(slot_snapshot * sss); static int publish_snapshot(slot_snapshot * sss); static int subscribe_snapshot(slot_snapshot * sss, struct timespec *pto); static int acquire_master(key_t key, slot_master ** pm); static int release_master(slot_master * m); static int acquire_slot(key_t key, char *id, long *payload, slot_snapshot * sss, struct timespec *pto); static int release_snapshot(slot_snapshot * sss); // yorick shm_var/unvar #if !defined(SVIPC_NOSEGFUNC) static _segm *seg_add(_segm * list, _segm * item); static _segm *seg_rem(_segm * list, _segm * item); static _segm *seg_lkupid(_segm * list, char *id); static _segm *seg_lkupdata(_segm * list, void *pdata); #endif //--------------------------------------------------------------- // private //--------------------------------------------------------------- /* find_master is an equivalent of 'ipcs' - we dont need it for our * implementation and SHM_STAT/SHM_INFO isn't portable across *nix * platforms. * In the future, we will follow the XSI Interprocess Communication API * which is open standard. (man 3p on Linux) * static int find_master(key_t key) * { * // find the first shm segment associated with a given key * // this only works for key != 0 * * struct shm_info info; * struct shmid_ds ds; * int shmid; * * // returns maxid btw * shmid = shmctl(0, SHM_INFO, (struct shmid_ds *) &info); * if (shmid == -1) { * perror("find_master SHM_INFO failed"); * return -1; * } * * int i; * for (i = 0; i < info.used_ids; i++) { * shmid = shmctl(i, SHM_STAT, &ds); * Debug(2, "** shmid %d key %d\n", shmid, ds.shm_perm.__key); * if (shmid == -1) { * // no read permission? (on fedora for example, user gdm creates segments with perm=600) * // if we cant read it, it's obviously not the one we are looking for. silently move on next * // perror ("SHM_STAT"); * continue; * } * if (shmid != -1 && key == ds.shm_perm.__key) { * return shmid; * } * } * * return -1; * } */ static slot_master *attach_master(key_t key) { Debug(2, "attach_master %x\n", key); int master_shmid = shmget(key, 0, 0666); if (master_shmid == -1) { return NULL; } return (slot_master *) shmat(master_shmid, NULL, 0); } static int detach_master(slot_master * m) { Debug(2, "detach_master\n"); if (shmdt((void *)m) == -1) { perror("detach_master failed"); return -1; } return 0; } static int lock_master(slot_master * m) { Debug(2, "lock_master\n"); // lock the master struct sembuf sops; sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = 0; int status = semop(m->master_semid, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } static int unlock_master(slot_master * m) { Debug(2, "unlock_master\n"); // lock the master struct sembuf sops; sops.sem_num = 0; sops.sem_op = 1; sops.sem_flg = 0; int status = semop(m->master_semid, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } static int lkup_slot(slot_master * m, char *id) { Debug(2, "lkup_slot %s\n", id); int i; for (i = 0; i < m->numslots; i++) { if (!strncmp(m->sse[i].desc, id, SLOT_DESC_STRING_MAX)) return i; } return -1; } static int getfree_slot(slot_master * m) { Debug(2, "getfree_slot\n"); int i; for (i = 0; i < m->numslots; i++) { if (m->sse[i].slot_shmid == 0) return i; } return -1; } static void snap_slot(slot_master * m, int slot, slot_snapshot * sss) { sss->sss_shm_id = m->sse[slot].slot_shmid; sss->sss_sem_id = m->master_semid; sss->sss_lock_id = 1 + slot; sss->sss_handsake_id = 1 + m->numslots + slot; } static int lock_slot(slot_master * m, int slot) { Debug(2, "lock_slot slot %d # %d\n", m->master_semid, slot + 1); // lock the slot struct sembuf sops; sops.sem_num = slot + 1; sops.sem_op = -1; sops.sem_flg = 0; int status = semop(m->master_semid, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } static int lock_snaphot(slot_snapshot * sss) { Debug(2, "lock_snaphot slot %d # %d\n", sss->sss_sem_id, sss->sss_lock_id); // lock the slot struct sembuf sops; sops.sem_num = sss->sss_lock_id; sops.sem_op = -1; sops.sem_flg = 0; int status = semop(sss->sss_sem_id, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } static int subscribe_snapshot(slot_snapshot * sss, struct timespec *pto) { Debug(2, "subscribe slot %d # %d\n", sss->sss_sem_id, sss->sss_handsake_id); // lock the slot struct sembuf sops; sops.sem_num = sss->sss_handsake_id; sops.sem_op = -1; // sops.sem_flg = 0; // fixme - undo if interrupted? int status; if (pto->tv_sec < 0) { // block till update now status = semop(sss->sss_sem_id, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } } else { // block till update or timeout status = semtimedop(sss->sss_sem_id, &sops, 1, pto); if (status == -1) { if (errno != EAGAIN) perror("semop failed"); return -1; } } return 0; } static int publish_snapshot(slot_snapshot * sss) { Debug(2, "publish slot %d # %d\n", sss->sss_sem_id, sss->sss_handsake_id); // how many processes are waiting? int numb = semctl(sss->sss_sem_id, sss->sss_handsake_id, GETNCNT); // unlock the slot struct sembuf sops; sops.sem_num = sss->sss_handsake_id; sops.sem_op = numb; // set count to be number of waiters sops.sem_flg = 0; // wake up int status = semop(sss->sss_sem_id, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } sops.sem_num = sss->sss_handsake_id; sops.sem_op = 0; // wait ack from all sops.sem_flg = 0; // wait till all ack'd status = semop(sss->sss_sem_id, &sops, 1); // fixme - timedop so we don't wait forever + set 0 if that happened if (status == -1) { perror("semop failed"); return -1; } return 0; } static int unlock_slot(slot_master * m, int slot) { Debug(2, "unlock_slot slot %d # %d\n", m->master_semid, slot + 1); // unlock the slot struct sembuf sops; sops.sem_num = slot + 1; sops.sem_op = 1; sops.sem_flg = 0; int status = semop(m->master_semid, &sops, 1); if (status == -1) { perror("semop failed"); return -1; } return 0; } static int unlock_snaphot(slot_snapshot * sss) { Debug(2, "unlock_snaphot slot %d # %d\n", sss->sss_sem_id, sss->sss_lock_id); // lock the slot struct sembuf sops; sops.sem_num = sss->sss_lock_id; sops.sem_op = 1; sops.sem_flg = 0; int status = semop(sss->sss_sem_id, &sops, 1); if (status == -1) { perror("unlock_snaphot semop failed"); return -1; } return 0; } static int free_slot(slot_master * m, int slot) { Debug(2, "free_slot%d\n", slot); if (m->sse[slot].slot_shmid != 0) { lock_slot(m, slot); // free segment int status = shmctl(m->sse[slot].slot_shmid, IPC_RMID, 0); if (status == -1) perror("IPC_RMID failed"); strcpy(m->sse[slot].desc, ""); m->sse[slot].slot_shmid = 0; unlock_slot(m, slot); } return 0; } //--------------------------------------------------------------- // private api //--------------------------------------------------------------- static int acquire_master(key_t key, slot_master ** pm) { // look up master *pm = attach_master(key); if (!*pm) { return -1; } // lock master if (lock_master(*pm)) { detach_master(*pm); return -1; } return 0; } static int release_master(slot_master * m) { int status = 0; // release master status |= unlock_master(m); status |= detach_master(m); return status; } static int acquire_slot(key_t key, char *id, long *payload, slot_snapshot * sss, struct timespec *pto) { int slot; int new = 0; slot_master *m; // acquire master if (acquire_master(key, &m)) { Debug(0, "master access error\n"); return -1; } // lookup slot if ((slot = lkup_slot(m, id)) < 0) { if (payload) { // not found, payload is set so create one slot = getfree_slot(m); if (slot < 0) { Debug(0, "no slot left\n"); release_master(m); return -1; } new = 1; } else { release_master(m); Debug(0, "slot not found\n"); return -1; } } if (pto) { // take a snapshot snap_slot(m, slot, sss); // release master release_master(m); // blocking - int status = subscribe_snapshot(sss, pto); if (status) { Debug(2, "subscribe failed or timeout\n"); return -1; } // lock slot if (lock_snaphot(sss)) { Debug(0, "failed to acquire lock on slot\n"); return -1; } } else { // lock slot if (lock_slot(m, slot)) { Debug(0, "failed to acquire lock on slot\n"); release_master(m); return -1; } // if new, create a segment if (new) { int shmid = shmget(key + slot + 1, *payload, 0666 | IPC_CREAT | IPC_EXCL); if (shmid == -1) { perror("shmget failed"); unlock_slot(m, slot); release_master(m); return -1; } // update the Id/slot name info snprintf(m->sse[slot].desc, SLOT_DESC_STRING_MAX, "%s", id); m->sse[slot].slot_shmid = shmid; } // take a snapshot snap_slot(m, slot, sss); // release master release_master(m); } // attach segment void *addr = (void *)shmat(sss->sss_shm_id, NULL, 0); if (addr == (void *)-1) { perror("shmat failed"); unlock_snaphot(sss); return -1; } // update segmap sss->segmap = (slot_segmap *) addr; if (new) { sss->segmap->typeID = -1; } // return slot return slot; } static int release_snapshot(slot_snapshot * sss) { int status; // detach segment status = shmdt((void *)sss->segmap); if (status == -1) { perror("shmdt failed"); unlock_snaphot(sss); return -1; } // unlock slot unlock_snaphot(sss); return 0; } #if !defined(SVIPC_NOSEGFUNC) //--------------------------------------------------------------- // local segm add/rem/lkup //--------------------------------------------------------------- static _segm *seg_add(_segm * list, _segm * item) { if (list == NULL) { list = item; item->next = NULL; } else { // go to the end of the list _segm *cursor = list; while (cursor->next != NULL) { cursor = cursor->next; } // and append cursor->next = item; item->next = NULL; } return list; } static _segm *seg_rem(_segm * list, _segm * item) { _segm *cursor = list; _segm *prev = NULL; while (cursor != item && cursor->next != NULL) { prev = cursor; cursor = cursor->next; } if (prev == NULL) { // remove first _segm return cursor->next; } else if (cursor->next == NULL) { return list; } else { prev->next = cursor->next; } return list; } static _segm *seg_lkupid(_segm * list, char *id) { _segm *cursor = list; while (cursor && strcmp(cursor->id, id)) { cursor = cursor->next; } return cursor; } static _segm *seg_lkupdata(_segm * list, void *pdata) { _segm *cursor = list; while (cursor && cursor->pdata != pdata) { cursor = cursor->next; } return cursor; } #endif //--------------------------------------------------------------- // svipc_shm_info //--------------------------------------------------------------- int svipc_shm_info(key_t key, int details) { int i; slot_master *m; // acquire master if (acquire_master(key, &m)) { Debug(0, "master access error\n"); return -1; } fprintf(stderr, "slot used? id"); if (details) fprintf(stderr, " type dims\n"); else fprintf(stderr, "\n"); fprintf(stderr, "----------------------------------\n"); for (i = 0; i < m->numslots; i++) { fprintf(stderr, "[%d] %2d \"%s\"", i, m->sse[i].slot_shmid != 0, m->sse[i].desc); if (details && m->sse[i].slot_shmid != 0) { lock_slot(m, i); void *addr = (void *)shmat(m->sse[i].slot_shmid, NULL, 0); if (addr == (void *)-1) perror("shmat failed"); int typeID = ((int *)addr)[0]; if (typeID == SVIPC_CHAR) fprintf(stderr, " char "); else if (typeID == SVIPC_SHORT) fprintf(stderr, " short "); else if (typeID == SVIPC_INT) fprintf(stderr, " int "); else if (typeID == SVIPC_LONG) fprintf(stderr, " long "); else if (typeID == SVIPC_FLOAT) fprintf(stderr, " float "); else if (typeID == SVIPC_DOUBLE) fprintf(stderr, " double "); else fprintf(stderr, " indef"); int countdims = ((int *)addr)[1]; long totalnumber = 1; int *p_addr = (int *)addr + 2; for (; countdims > 0; countdims--) { fprintf(stderr, ",%d", *p_addr); totalnumber *= *p_addr; p_addr++; } fprintf(stderr, "\n"); shmdt(addr); unlock_slot(m, i); } else fprintf(stderr, "\n"); } release_master(m); return 0; } //--------------------------------------------------------------- // svipc_shm_init //--------------------------------------------------------------- int svipc_shm_init(key_t key, int numslots) { // initialize a toplevel pool of semaphores protected memory segments // will allow all the process to query/access/etc shared memory // a slot is understood as a region in shared memory // there will be one semaphore per slot used to synchronise access // there will be one semaphore the control access to the master slot // the master slot will hold: // it's own semId // shmid int i; if (numslots >= 0) { // master int status; int master_shmid; int master_semid; master_semid = semget(key, 2 * numslots + 1, IPC_CREAT | IPC_PRIVATE | IPC_EXCL | 0666); if (master_semid == -1) { perror("master_semid semget failed"); return -1; } // all locking semaphores are free at startup union semun semctlops; semctlops.val = 1; // fixme - SETALL perf improvement for (i = 0; i < numslots + 1; i++) { status = semctl(master_semid, i, SETVAL, semctlops); if (status == -1) { perror("locking semctl failed"); return -1; } } // all handshake semaphores are empty at startup semctlops.val = 0; // fixme - SETALL perf improvement for (i = 0; i < numslots; i++) { status = semctl(master_semid, i + 1 + numslots, SETVAL, semctlops); if (status == -1) { perror("handshake semctl failed"); return -1; } } // fixme: there might be race condition at startup when we create the master pool // and have not yet to set the master semaphore. // create a shm mem pool long bytes = sizeof(master_shmid) + sizeof(master_semid) + sizeof(numslots) + numslots * sizeof(slot_entry); master_shmid = shmget(key, bytes, 0666 | IPC_CREAT | IPC_EXCL); slot_master *m = (slot_master *) shmat(master_shmid, NULL, 0); if (m == (slot_master *) - 1) { perror("shmat failed"); return -1; } memset(m, 0, bytes); m->master_shmid = master_shmid; m->master_semid = master_semid; m->numslots = numslots; //flexible arrays //m->se=&(m->se); for (i = 0; i < numslots; i++) { m->sse[i].slot_shmid = 0; strcpy(m->sse[i].desc, ""); } // fixme - call something like unlock_master+detach_master status = shmdt((void *)m); if (status == -1) { perror("shmdt failed"); return -1; } return 0; } else { // slave -> noop, print info return svipc_shm_info(key, 1); } } //--------------------------------------------------------------- // svipc_shm_write //--------------------------------------------------------------- int svipc_shm_write(key_t key, char *id, slot_array * a, int publish) { int status = 0; slot_snapshot sss; int *p_addr; int i; int typeID = a->typeID; int countdims = a->countdims; long totalnumber = 1; for (i = 0; i < countdims; i++) totalnumber *= *(a->number + i); long payload_bytes = totalnumber * slot_type_sz[typeID]; // data long shmbytes = 2 * sizeof(int) // typeID + number of dimensions + countdims * sizeof(long) // size of each dimension + payload_bytes; if (acquire_slot(key, id, &shmbytes, &sss, NULL) < 0) { Debug(0, "acquire_slot failure\n"); return -1; } if (sss.segmap->typeID == -1) { Debug(2, "new segment, fill headers\n"); // new segment, fill up header with type, dims and size information sss.segmap->typeID = typeID; sss.segmap->countdims = countdims; p_addr = &sss.segmap->flexible; for (i = 0; i < countdims; i++) { *p_addr++ = *(a->number + i); } } else { Debug(2, "exisiting segment, check consistency\n"); // check the reference we have been given is compatible with the one // we have in shared memory. status = 0; if (a->typeID != sss.segmap->typeID) { perror("incompatible type"); status |= 0x1; } if (a->countdims != sss.segmap->countdims) { perror("incompatible dims"); status |= 0x2; } p_addr = &sss.segmap->flexible; long shm_totalnumber = 1; for (i = 0; i < sss.segmap->countdims; i++) { shm_totalnumber *= *p_addr++; } if (totalnumber != shm_totalnumber) { perror("incompatible size"); status |= 0x4; } if (status) { unlock_snaphot(&sss); return -1; } } // copy data content memcpy((void *)p_addr, a->data, payload_bytes); status = release_snapshot(&sss); // wake up if (publish) status |= publish_snapshot(&sss); return status; } //--------------------------------------------------------------- // svipc_shm_read //--------------------------------------------------------------- int svipc_shm_read(key_t key, char *id, slot_array * a, float subscribe_t) { slot_snapshot sss; int status; struct timespec timeout, *pto = NULL; if (subscribe_t != 0.0) { timeout.tv_sec = (time_t) subscribe_t; timeout.tv_nsec = (long int)((subscribe_t - timeout.tv_sec) * 1e9); pto = &timeout; } if (acquire_slot(key, id, NULL, &sss, pto) < 0) { Debug(1, "acquire_slot failure\n"); // debug 1, could be a timeout return -1; } a->typeID = sss.segmap->typeID; a->countdims = sss.segmap->countdims; int *p_addr = &sss.segmap->flexible; int i; long totalnumber = 1; if (a->number == NULL) { a->number = (int *)malloc(a->countdims * sizeof(*a->number)); } for (i = 0; i < a->countdims; i++) { a->number[i] = *p_addr++; totalnumber *= a->number[i]; } long payload_bytes = totalnumber * slot_type_sz[a->typeID]; // data if (a->data == NULL) { a->data = malloc(payload_bytes); } memcpy(a->data, p_addr, payload_bytes); status = release_snapshot(&sss); return status; } //--------------------------------------------------------------- // svipc_shm_free //--------------------------------------------------------------- int svipc_shm_free(key_t key, char *id) { slot_master *m; // acquire master if (acquire_master(key, &m)) { Debug(0, "master access error\n"); return -1; } int slot; if ((slot = lkup_slot(m, id)) < 0) { Debug(0, "slot not found\n"); release_master(m); return -1; } free_slot(m, slot); release_master(m); return 0; } //--------------------------------------------------------------- // svipc_shm_cleanup //--------------------------------------------------------------- int svipc_shm_cleanup(key_t key) { int status; slot_master *m; // acquire master if (acquire_master(key, &m)) { Debug(0, "master access error\n"); return -1; } int i; for (i = 0; i < m->numslots; i++) { free_slot(m, i); } status = semctl(m->master_semid, IPC_RMID, 0); if (status == -1) { perror("locking semctl IPC_RMID failed"); return -1; } status = shmctl(m->master_shmid, IPC_RMID, 0); if (status == -1) { perror("shmctl IPC_RMID failed"); return -1; } detach_master(m); return 0; } //--------------------------------------------------------------- // cleanup_slot_array //--------------------------------------------------------------- int release_slot_array(slot_array * a) { free(a->number); free(a->data); return 0; } #if !defined(SVIPC_NOSEGFUNC) int svipc_shm_attach(key_t key, char *id, slot_array * a) { _segm *this; slot_snapshot sss; int status = 0; slot_segmap *pseg; int cleanup = 0; if ((this = seg_lkupid(segtable, id)) != NULL) { // already refd, return the address. pseg = (slot_segmap *) this->addr; } else { cleanup = 1; if (acquire_slot(key, id, NULL, &sss, NULL) < 0) { Debug(0, "acquire_slot failure\n"); return -1; } // the slot segment is now attached // append it to the local lkup this = (_segm *) malloc(sizeof(_segm)); snprintf(this->id, SLOT_DESC_STRING_MAX, "%s", id); this->addr = sss.segmap; segtable = seg_add(segtable, this); pseg = sss.segmap; } a->typeID = pseg->typeID; a->countdims = pseg->countdims; int *p_addr = &pseg->flexible; int i; a->number = (int *)malloc(a->countdims * sizeof(*a->number)); for (i = 0; i < a->countdims; i++) { a->number[i] = *p_addr++; } a->data = p_addr; // reverse lookup for unvar use the address of the data - make note of it now this->pdata = p_addr; if (cleanup) { // unlock (but don't detach) slot unlock_snaphot(&sss); } return status; } int svipc_shm_detach(void *addr) { int status = 0; _segm *this = seg_lkupdata(segtable, addr); if (this == NULL) { Debug(0, "no attached mem\n"); return -1; } else { // remove from lkup table and detach segtable = seg_rem(segtable, this); Debug(2, "detattach %p\n", this->addr); status = shmdt((void *)this->addr); strcpy(this->id, ""); this->addr = NULL; this->pdata = NULL; if (status == -1) perror("shmdt failed"); return status; } } #endif yp-svipc-0.16/common/svipc_shm.h000066400000000000000000000034721232651007300166530ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SVIPC_SHM_H) #define SVIPC_SHM_H #ifdef __cplusplus extern "C" { #endif typedef enum { SVIPC_CHAR, SVIPC_SHORT, SVIPC_INT, SVIPC_LONG, SVIPC_FLOAT, SVIPC_DOUBLE } slot_type; #if defined(SVIPC_SZ_DEF) int slot_type_sz[] = { sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(float), sizeof(double) }; #endif typedef struct { int typeID; // data type int countdims; // number of dimensions int *number; // number elts on each dimension void *data; // data pointer } slot_array; int svipc_shm_init(key_t key, int numslots); int svipc_shm_cleanup(key_t key); int svipc_shm_info(key_t key, int details); int svipc_shm_write(key_t key, char *id, slot_array * a, int publish); int svipc_shm_read(key_t key, char *id, slot_array * a, float subscribe); int svipc_shm_free(key_t key, char *id); int release_slot_array(slot_array * a); #if !defined(SVIPC_NOSEGFUNC) int svipc_shm_attach(key_t key, char *id, slot_array * a); int svipc_shm_detach(void *addr); #endif #ifdef __cplusplus } #endif #endif yp-svipc-0.16/demo/000077500000000000000000000000001232651007300141355ustar00rootroot00000000000000yp-svipc-0.16/demo/README000066400000000000000000000004021232651007300150110ustar00rootroot00000000000000DEMOS # python demo (requisite: svipc for python) ./sem-demo.py # yorick demo (requisite: svipc for yorick) yorick -i sem-demo.i yorick -i msq-demo.i yorick -i timing-demo.i # python/yorick demo (requisite: svipc for yorick and python) yorick -i ping.i yp-svipc-0.16/demo/msq-demo.i000066400000000000000000000012641232651007300160340ustar00rootroot00000000000000#include "svipc.i" // create ids my_msqid = 0x7dcb0000 | getpid(); // create our queue msq_init,my_msqid; // fork and go if (fork()!=0) { // parent aaa=[[1,2],[3,4],[5,6]]; // sends a message msq_snd,my_msqid,123,&aaa; // waits for reply bbb = msq_rcv(my_msqid,321); // cleanup msq_cleanup, my_msqid; // check result write, "pass?", allof(aaa==transpose(bbb)); // adios quit; } else { // fork child does not have stdout // child waits to read 123 message ccc=msq_rcv(my_msqid,123); // transposes it ddd=transpose(ccc); // and sends it back as 321 msq_snd,my_msqid,321,&ddd; // adios quit; } yp-svipc-0.16/demo/ping.i000066400000000000000000000027761232651007300152600ustar00rootroot00000000000000#include "svipc.i" // create ids my_shmid = 0x78080000 | getpid(); my_semid = 0x7dcb0000 | getpid(); my_msqid = 0x71010000 | getpid(); // create a pool of svipc shm_init,my_shmid,slots=1; sem_init,my_semid,nums=2; // id:0 yorick <- python, id:1 yorick -> python msq_init,my_msqid; // spawn pong.py func on_py_stdout(msg) { write,"from python:",msg; } pyfd = spawn(["python","pong.py", swrite(format="%d",my_shmid), swrite(format="%d",my_semid), swrite(format="%d",my_msqid) ], on_py_stdout); write,"Y: wait synch from python" sem_take,my_semid,0; // play 1 write,"Y: take sem 3 times"; for (i=0;i<3;i++) { s = sem_take(my_semid,0); write,"Y: sem taken",i; } // play 2 write,"--- shm 3 times"; // create the shm msg = [1,2,3,4] shm_write,my_shmid,"pingpong",&msg; write,"Y: python may go." sem_give,my_semid,1; pause,500; // allow python to get into its subscribe before we send our publish for (i=0;i<3;i++) { write,"Y: sending"; msg; shm_write,my_shmid,"pingpong",&msg,publish=1; reply = shm_read(my_shmid,"pingpong",subscribe=-1); write,"Y: received"; reply; } // play 3 write,"--- msq 3 times"; write,"Y: python may go." sem_give,my_semid,1; for (i=0;i<3;i++) { write,"Y: sending"; msg; msq_snd,my_msqid,1234,&msg; reply = msq_rcv(my_msqid,5678); write,"Y: received"; reply; } write,"Y: wait for python to be done" sem_take,my_semid,0; write,"Y: cleanup and exit" shm_cleanup, my_shmid; sem_cleanup, my_semid; msq_cleanup, my_msqid; // bye quit; yp-svipc-0.16/demo/pong.py000066400000000000000000000021621232651007300154530ustar00rootroot00000000000000#! /usr/bin/env python import svipc import sys import time # retreive ids my_shmid,my_semid,my_msqid = [int(a) for a in sys.argv[1:]] #let yorick wait .. for fun sys.stderr.write('P: sleeping 1s.\n') time.sleep(1) # tell it to go sys.stderr.write('P: yorick may go.\n') svipc.sem_give(my_semid,id=0) # play 1 for i in range(3): time.sleep(1) sys.stderr.write('P: sem give %d.\n' % i) svipc.sem_give(key=my_semid,id=0) # play 2 sys.stderr.write('P: wait synch from yorick\n') svipc.sem_take(my_semid,1) sys.stderr.write('P: going now\n') for i in range(3): msg = svipc.shm_read(my_shmid,id="pingpong",subscribe=-1.0) time.sleep(1) msg[i]=0 svipc.shm_write(my_shmid,"pingpong",data=msg,publish=1) # play 3 sys.stderr.write('P: wait synch from yorick\n') svipc.sem_take(my_semid,1) sys.stderr.write('P: going now\n') for i in range(3): sys.stderr.write('P: rcv\n') msg = svipc.msq_rcv(my_msqid,mtype=1234) msg[i]=0 sys.stderr.write('P: snd\n') svipc.msq_snd(my_msqid,mtype=5678,data=msg) # tell yorick we're done svipc.sem_give(my_semid,id=0) sys.stderr.write('P: exiting\n') exit() yp-svipc-0.16/demo/sem-demo.i000066400000000000000000000015451232651007300160220ustar00rootroot00000000000000#include "svipc.i" // create ids my_semid = 0x7dcb0000 | getpid(); // create a pool with one semaphore sem_init,my_semid,nums=1; // fork and go if ( fork() != 0 ) { // wait for child, forever write, "#1 - wait for child, forever"; s = sem_take(my_semid, 0); write, " ", s; // wait for child, 500ms write,"#2 - wait for child, 500ms (will timeout)"; s = sem_take(my_semid, 0, wait=0.5); write, " ", s; // wait for child to ack 10 times write,"#3 - wait for child 10x"; s = sem_take(my_semid, 0, count=10); write, " ", s; // cleanup sem_cleanup, my_semid; // adios quit; } else { // child test #1 pause,1000; sem_give,my_semid,0; // child test #2 pause,1000; sem_give,my_semid,0; // child test #3 pause,1000; for (i=0;i<10;i++) { sem_give,my_semid,0; } quit; } yp-svipc-0.16/demo/sem-demo.py000077500000000000000000000037701232651007300162270ustar00rootroot00000000000000#! /usr/bin/env python import sys, os from os import getpid, fork from time import sleep, time from svipc import sem_init, sem_take, sem_give, sem_cleanup # create id sid = 0x7dcb0000 | getpid() # create a pool with one semaphore sem_init(sid,nums=1) # time unit for test delay=0.5 class unit_test(object): def __init__(self): self.errmsg='' if fork(): if not self.parent(): print 'OK' else: print 'ERROR', self.errmsg else: self.child() exit() def parent(self): return 0 def child(self): pass class ut1(unit_test): def parent(self): print '- wait for child forever:' s = sem_take(sid, 0) return s def child(self): sleep(delay) sem_give(sid,0) class ut2(unit_test): def parent(self): print '- wait for child with timeout:' tstart=time() s = sem_take(sid, 0, wait= 2 * delay) if time()-tstart < delay: self.errmsg='timeout too quickly.' return -2 return s def child(self): sleep(delay) sem_give(sid,0) class ut3(unit_test): def parent(self): print '- wait for child with timeout, and timeout:' tstart=time() s = sem_take(sid, 0, wait=delay) if time()-tstart < delay: self.errmsg='did not wait long enough' return -2 self.errmsg='wait did not time out.' return not s def child(self): pass class ut4(unit_test): def parent(self): print '- wait for child x10 times:' s = sem_take(sid, 0, count=10) return s def child(self): for i in range(10): sem_give(sid,0) class ut5(unit_test): def parent(self): print '- try take semaphore (available):' sleep(delay) s = sem_take(sid, 0, wait=0) self.errmsg='sem was not available' return s def child(self): sem_give(sid,0) class ut6(unit_test): def parent(self): print '- try take semaphore (non-available):' s = sem_take(sid, 0, wait=0) self.errmsg='sem was available' return not s def child(self): pass ut1() ut2() ut3() ut4() ut5() ut6() sem_cleanup(sid) yp-svipc-0.16/demo/sem-demo3.py000077500000000000000000000040061232651007300163030ustar00rootroot00000000000000#! /usr/bin/env python3 import sys, os from os import getpid, fork from time import sleep, time from svipc import sem_init, sem_take, sem_give, sem_cleanup # create id sid = int(0x7dcb0000) | getpid() # create a pool with one semaphore sem_init(sid,nums=1) # time unit for test delay=0.5 class unit_test(object): def __init__(self): self.errmsg='' if fork(): if not self.parent(): print('OK') else: print('ERROR', self.errmsg) else: self.child() exit() def parent(self): return 0 def child(self): pass class ut1(unit_test): def parent(self): print('- wait for child forever:') s = sem_take(sid, 0) return s def child(self): sleep(delay) sem_give(sid,0) class ut2(unit_test): def parent(self): print('- wait for child with timeout:') tstart=time() s = sem_take(sid, 0, wait= 2 * delay) if time()-tstart < delay: self.errmsg='timeout too quickly.' return -2 return s def child(self): sleep(delay) sem_give(sid,0) class ut3(unit_test): def parent(self): print('- wait for child with timeout, and timeout:') tstart=time() s = sem_take(sid, 0, wait=delay) if time()-tstart < delay: self.errmsg='did not wait long enough' return -2 self.errmsg='wait did not time out.' return not s def child(self): pass class ut4(unit_test): def parent(self): print('- wait for child x10 times:') s = sem_take(sid, 0, count=10) return s def child(self): for i in range(10): sem_give(sid,0) class ut5(unit_test): def parent(self): print('- try take semaphore (available):') sleep(delay) s = sem_take(sid, 0, wait=0) self.errmsg='sem was not available' return s def child(self): sem_give(sid,0) class ut6(unit_test): def parent(self): print('- try take semaphore (non-available):') s = sem_take(sid, 0, wait=0) self.errmsg='sem was available' return not s def child(self): pass ut1() ut2() ut3() ut4() ut5() ut6() sem_cleanup(sid) yp-svipc-0.16/demo/shm-demo.py000077500000000000000000000014531232651007300162260ustar00rootroot00000000000000#! /usr/bin/env python # # cpu hog - demo used to check we're not leaking # from os import getpid, fork from svipc import shm_init, shm_read, shm_write, shm_cleanup from svipc import sem_init, sem_take, sem_give, sem_cleanup import numpy import time num_= 10000000 n = 32 stoopid=numpy.ones(n) stoopid[n-1]=n data = numpy.arange(n).reshape(stoopid) #print data.shape # create id svid0 = 0x7dcb0000 | getpid() svid1 = svid0+1 # create a pool with one shmaphore shm_init(svid0,slots=1) sem_init(svid1,nums=1) if fork(): for i in range(num_): shm_write(svid0,'slot0',data,publish=0) # shm id's are string ... doh sem_take(svid1,0) else: time.sleep(1) for i in range(num_): d=shm_read(svid0,'slot0',0) sem_give(svid1,0) ### print d exit() sem_cleanup(svid1) shm_cleanup(svid0) yp-svipc-0.16/demo/tictac.i000066400000000000000000000022171232651007300155600ustar00rootroot00000000000000/************************************/ /* SYSTEM AND PERFORMANCE functions */ /************************************/ func tic(counterNumber) /* DOCUMENT tic(counter_number) * Marks the beginning of a time lapse * ex: tic ; do_something ; tac() * will print out the time ellapsed between tic and tac * a counter number can optionaly be specified if several * counters have to be used in parallel. * F.Rigaut 2001/10 * SEE ALSO: tac */ { if (counterNumber == []) counterNumber = 1; if (counterNumber > 10) error,"tic and tac are limited to 10 time counters !"; el = array(double,3); timer,el; _nowtime(counterNumber) = el(3); } extern _nowtime; _nowtime = array(double,10); func tac(counterNumber) /* DOCUMENT tac(counter_number) * Marks the end of a time lapse * ex: tic ; do_something ; tac() * will print out the time ellapsed between tic and tac * a counter number can optionaly be specified if several * counters have to be used in parallel. * F.Rigaut 2001/10 * SEE ALSO: tic */ { if (counterNumber == []) counterNumber = 1; el = array(double,3); timer,el; elapsed = el(3)-_nowtime(counterNumber); return elapsed; } yp-svipc-0.16/demo/timing-demo.i000066400000000000000000000076521232651007300165320ustar00rootroot00000000000000#include "svipc.i" #include "tictac.i" func bigmatprod(a,b,np=) { /* DOCUMENT bigmatprod(a,b,np=) (array) a,b (int) np - the number of processes Parallelized array product using np processes Make sure the first dimension of 'a' is big */ if (np==[]) np = nprocs(); // check inputs dima = dimsof(a); dimb = dimsof(b); if ( dima(1) != 2 || dimb(1) != 2 ) { error,"bigmatprod input array must have dims=2" } if ( dima(3) != dimb(2) ) { error,"bigmatprod array size incompatible" } // split payload - dumb demo // we split along the first dimension of 'a' so make sure that one is big chunk_sz = array(dima(2)/np,np); // TODO: max all the chunks rather than max the last one // for now we'll assume even the small chunks are big so it can be reasonably ignored endchunk = dima(2)-np*chunk_sz(1); chunk_sz(0) += endchunk; chunk_start = array(0,np); for (i=1;i. */ #define NPY_NO_DEPRECATED_API 7 #include "Python.h" #include #if PY_MAJOR_VERSION >= 3 #define PyInt_FromLong PyLong_FromLong #endif #include #include #include "svipc.h" PyObject *python_svipc_module; PyObject *python_svipc_error; #define PYTHON_SVIPC_USAGE(fmt, ...) {\ PyErr_Format(python_svipc_error, "usage: " fmt, ## __VA_ARGS__);\ return NULL;\ } #define PYTHON_SVIPC_ERROR(fmt, ...) {\ PyErr_Format(python_svipc_error, fmt, ## __VA_ARGS__);\ return NULL;\ } /******************************************************************* * setaffinity *******************************************************************/ PyDoc_STRVAR(python_svipc_misc_setaffinity_doc, "setaffinity(cpu=cpu)\n\ (int) cpu - cpu id\n\ Set the running process affinity to cpu.\n\ "); PyObject *python_svipc_misc_setaffinity(PyObject * self, PyObject * args, PyObject * kwds) { static char *kwlist[] = { "cpu", NULL }; int cpu=0; if (!PyArg_ParseTupleAndKeywords (args, kwds, "i", kwlist, &cpu)) PYTHON_SVIPC_USAGE("setaffinity(cpu=cpu)"); int status = svipc_setaffinity(cpu); return PyInt_FromLong(status); } /******************************************************************* * ftok *******************************************************************/ PyDoc_STRVAR(python_svipc_misc_ftok_doc, "ftok(path, proj=0)\n\ (string) path - a unix file path\n\ (int) proj - a project number\n\ Convert a pathname and a project identifier to a System V IPC key\n\ "); PyObject *python_svipc_misc_ftok(PyObject * self, PyObject * args, PyObject * kwds) { char *path; static char *kwlist[] = { "path", "proj", NULL }; int proj=0; if (!PyArg_ParseTupleAndKeywords (args, kwds, "s|i", kwlist, &path, &proj)) PYTHON_SVIPC_USAGE("ftok(path, proj=0)"); long key = svipc_ftok(path, proj); return PyInt_FromLong(key); } /******************************************************************* * nprocs *******************************************************************/ PyDoc_STRVAR(python_svipc_misc_nprocs_doc, "nprocs()\n\ Returns the number of processors currently online (available).\n\ Note this might not catch virtualized CPUs.\n\ "); PyObject *python_svipc_misc_nprocs(PyObject * self, PyObject * args) { return PyInt_FromLong(svipc_nprocs()); } /******************************************************************* * shm info *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_info_doc, "shm_info(key, details=0)\n\ (int) key - a System V IPC key\n\ (int) details - the level of details to print\n\ Print a report on shared memory pool identified by 'key'.\n\ 'details' controls the level of information printed out.\n\ "); PyObject *python_svipc_shm_info(PyObject * self, PyObject * args, PyObject * kwds) { int key, details = 0; static char *kwlist[] = { "key", "details", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "i|i", kwlist, &key, &details)) PYTHON_SVIPC_USAGE("shm_info(key, details=0)"); int status = svipc_shm_info(key, details); return PyInt_FromLong(status); } /******************************************************************* * shm init *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_init_doc, "shm_init(key, slots)\n\ (int) key - a System V IPC key\n\ (int) slots - the number of shared memory segments to create\n\ Initialize a pool of shared memory identified by 'key' containing\n\ 'slots' segments of initially free Ids\n\ "); PyObject *python_svipc_shm_init(PyObject * self, PyObject * args, PyObject * kwds) { int key, numslots = -1; static char *kwlist[] = { "key", "slots", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "ii", kwlist, &key, &numslots)) PYTHON_SVIPC_USAGE("shm_init(key, slots)"); int status = svipc_shm_init(key, numslots); return PyInt_FromLong(status); } /******************************************************************* * shm write *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_write_doc, "shm_write(key,id,data,publish=0)\n\ (int) key - a System V IPC key\n\ (string) id - a slot Id\n\ (object) data - data to be written\n\ (bool) publish - broadcast to subscribers a new value has been written\n\ Write the content of the variable referenced by a in\n\ the slot identified by 'id' from the shared memory pool\n\ identified by 'key'.\n\ This operation is semaphore protected and guarantees\n\ consistency for external readers.\n\ "); PyObject *python_svipc_shm_write(PyObject * self, PyObject * args, PyObject * kwds) { int key; char *id; PyObject *a; int publish = 0; static char *kwlist[] = { "key", "id", "data", "publish", NULL }; slot_array arr; if (!PyArg_ParseTupleAndKeywords (args, kwds, "isO|i", kwlist, &key, &id, &a, &publish)) PYTHON_SVIPC_USAGE("shm_write(key,id,data,publish=0)"); PyArrayObject *inp_array = (PyArrayObject *) PyArray_FROM_O(a); if (PyArray_TYPE(inp_array) == NPY_BYTE) arr.typeID = SVIPC_CHAR; else if (PyArray_TYPE(inp_array) == NPY_SHORT) arr.typeID = SVIPC_SHORT; else if (PyArray_TYPE(inp_array) == NPY_INT) arr.typeID = SVIPC_INT; else if (PyArray_TYPE(inp_array) == NPY_LONG) arr.typeID = SVIPC_LONG; else if (PyArray_TYPE(inp_array) == NPY_FLOAT) arr.typeID = SVIPC_FLOAT; else if (PyArray_TYPE(inp_array) == NPY_DOUBLE) arr.typeID = SVIPC_DOUBLE; else { PYTHON_SVIPC_ERROR("type not supported"); } arr.countdims = PyArray_NDIM(inp_array); arr.number = (int *)malloc(arr.countdims * sizeof(*arr.number)); memcpy(arr.number, PyArray_DIMS(inp_array), arr.countdims * sizeof(*arr.number)); arr.data = PyArray_DATA(inp_array); int status = svipc_shm_write(key, id, &arr, publish); free(arr.number); Py_DECREF(inp_array); return PyInt_FromLong(status); } /******************************************************************* * shm read *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_read_doc, "shm_read(key,id,subscribe=0)\n\ (int) key - a System V IPC key\n\ (string) id - a slot Id\n\ (float) subscribe - if set, wait (block) for a publisher broadcast\n\ Read the content of the slot identified by 'id' from the\n\ shared memory pool identified by 'key'.\n\ If subscribe > 0, the parameter is understood as a maximum number of\n\ seconds to wait for a broadcast event, or timeout.\n\ \n\ If subscribe < 0, the calling process will block until reception of\n\ a broadcast.\n\ \n\ If subscribe = 0, read the current value from shared memory\n\ indepently of write broadcast.\n\ This operation is semaphore protected and guarantees\n\ consistency with external writers.\n\ "); PyObject *python_svipc_shm_read(PyObject * self, PyObject * args, PyObject * kwds) { int key; char *id; slot_array arr; float subscribe = 0.0; static char *kwlist[] = { "key", "id", "subscribe", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "is|f", kwlist, &key, &id, &subscribe)) PYTHON_SVIPC_USAGE("shm_read(key, id,subscribe=0)"); memset(&arr, 0, sizeof(arr)); int status = svipc_shm_read(key, id, &arr, subscribe); if (status == 0) { enum NPY_TYPES ret_py_type; if (arr.typeID == SVIPC_CHAR) ret_py_type = NPY_BYTE; else if (arr.typeID == SVIPC_SHORT) ret_py_type = NPY_SHORT; else if (arr.typeID == SVIPC_INT) ret_py_type = NPY_INT; else if (arr.typeID == SVIPC_LONG) ret_py_type = NPY_LONG; else if (arr.typeID == SVIPC_FLOAT) ret_py_type = NPY_FLOAT; else if (arr.typeID == SVIPC_DOUBLE) ret_py_type = NPY_DOUBLE; else { release_slot_array(&arr); PYTHON_SVIPC_ERROR("type not supported"); }; /* platform ints for numpy array dims */ npy_intp *dims = malloc(arr.countdims * sizeof(npy_intp)); int i; for (i = 0; i < arr.countdims; i++) dims[i] = arr.number[i]; PyArrayObject *res = (PyArrayObject *) PyArray_SimpleNewFromData(arr.countdims, dims, ret_py_type, arr.data); // free tmp free(dims); // to save us from copying the result, hand over the data to python // the slot_array dims though are not used and should be free. // sounds weird? trust me. arguably my API could be improved a bit. PyArray_ENABLEFLAGS(res,NPY_ARRAY_OWNDATA); free(arr.number); // yes return (PyObject *) res; } else { PYTHON_SVIPC_ERROR("status %d\n", status); } } /******************************************************************* * shm free *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_free_doc, "shm_free(key,id)\n\ (int) key - a System V IPC key\n\ (string) id - a slot Id\n\ Release the slot identified by 'id' from the\n\ shared memory pool identified by 'key'.\n\ This operation is semaphore protected and guarantees\n\ consistency with external readers and writers.\n\ "); PyObject *python_svipc_shm_free(PyObject * self, PyObject * args, PyObject * kwds) { int key; char *id; static char *kwlist[] = { "key", "id", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "is", kwlist, &key, &id)) PYTHON_SVIPC_USAGE("shm_free(key, id)"); int status = svipc_shm_free(key, id); return PyInt_FromLong(status); } /******************************************************************* * shm cleanup *******************************************************************/ PyDoc_STRVAR(python_svipc_shm_cleanup_doc, "shm_cleanup(key)\n\ (int) key - a System V IPC key\n\ Release all the slots from the shared memory pool\n\ identified by 'key'.\n\ This operation is semaphore protected and guarantees\n\ consistency with external readers and writers.\n\ "); PyObject *python_svipc_shm_cleanup(PyObject * self, PyObject * args, PyObject * kwds) { int key; static char *kwlist[] = { "key", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &key)) PYTHON_SVIPC_USAGE("shm_cleanup(key)"); int status = svipc_shm_cleanup(key); return PyInt_FromLong(status); } /******************************************************************* * sem info *******************************************************************/ PyDoc_STRVAR(python_svipc_sem_info_doc, "sem_info(key, details=0)\n\ (int) key - a System V IPC key\n\ (int) details - the level of details to print\n\ Print a report on semaphore pool identified by 'key'.\n\ 'details' controls the level of information printed out.\n\ "); PyObject *python_svipc_sem_info(PyObject * self, PyObject * args, PyObject * kwds) { int key; int details = 0; static char *kwlist[] = { "key", "details", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "i|i", kwlist, &key, &details)) PYTHON_SVIPC_USAGE("sem_info(key, details=0)"); int status = svipc_sem_info(key, details); return PyInt_FromLong(status); } /******************************************************************* * sem init *******************************************************************/ PyDoc_STRVAR(python_svipc_sem_init_doc, "sem_init(key, nums)\n\ (int) key - a System V IPC key\n\ (int) num - the number of semaphores to create\n\ Initialize a pool of semaphores identified by 'key' containing\n\ 'nums' initially taken (locked) semaphores.\n\ NB: nums=0 provides a hacked functionality and reset to 0 all the semaphores\n\ in the pool.\n\ nums<0 is equivalent to sem_info.\n\ "); PyObject *python_svipc_sem_init(PyObject * self, PyObject * args, PyObject * kwds) { int key, nums; static char *kwlist[] = { "key", "nums", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &key, &nums)) PYTHON_SVIPC_USAGE("sem_init(key, nums)"); int status = svipc_sem_init(key, nums); return PyInt_FromLong(status); } /******************************************************************* * sem cleanup *******************************************************************/ PyDoc_STRVAR(python_svipc_sem_cleanup_doc, "sem_cleanup(key)\n\ (int) key - a System V IPC key\n\ Release the semaphore pool identified by 'key'.\n\ "); PyObject *python_svipc_sem_cleanup(PyObject * self, PyObject * args, PyObject * kwds) { int key; static char *kwlist[] = { "key", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &key)) PYTHON_SVIPC_USAGE("sem_cleanup(key)"); int status = svipc_sem_cleanup(key); return PyInt_FromLong(status); } /******************************************************************* * sem take *******************************************************************/ PyDoc_STRVAR(python_svipc_sem_take_doc, "sem_take(key,id,count=1,wait=-1)\n\ (int) key - a System V IPC key\n\ (int) id - a semaphore Id\n\ (int) count - the number of operations on the semaphore\n\ (float) wait - a number of seconds\n\ \n\ Decrement semaphore Id by 'count'\n\ The default, count=1, is equivalent to 'take semaphore Id'.\n\ \n\ If wait > 0, the parameter is understood as the maximum number of\n\ seconds to wait to get hold of the semaphore, or timeout.\n\ \n\ If wait < 0, the calling process will block until it can take the\n\ semaphore.\n\ \n\ If wait = 0, returns immediately with a status if the operation\n\ succeeded or not.\n\ "); PyObject *python_svipc_semtake(PyObject * self, PyObject * args, PyObject * kwds) { int key, id, count; float wait = -1; count = 1; static char *kwlist[] = { "key", "id", "count", "wait", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "ii|if", kwlist, &key, &id, &count, &wait)) PYTHON_SVIPC_USAGE("sem_take(key,id,count=1,wait=-1)"); int status = svipc_semtake(key, id, count, wait); return PyInt_FromLong(status); } /******************************************************************* * sem give *******************************************************************/ PyDoc_STRVAR(python_svipc_sem_give_doc, "sem_give(key,id,count=1)\n\ (int) key - a System V IPC key\n\ (int) id - a semaphore Id\n\ (int) count - the number of operations on the semaphore\n\ \n\ Increment the semaphore Id by 'count'\n\ The default, count=1, is equivalent to 'release semaphore Id'.\n\ "); PyObject *python_svipc_semgive(PyObject * self, PyObject * args, PyObject * kwds) { int key, id, count; count = 1; static char *kwlist[] = { "key", "id", "count", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "ii|i", kwlist, &key, &id, &count)) PYTHON_SVIPC_USAGE("sem_give(key,id,count=1)"); int status = svipc_semgive(key, id, count); return PyInt_FromLong(status); } /******************************************************************* * msq info *******************************************************************/ PyDoc_STRVAR(python_svipc_msq_info_doc, "msq_info(key, details=0)\n\ (int) key - a System V IPC key\n\ (int) details - the level of details to print\n\ Print a report on message queue identified by 'key'.\n\ 'details' controls the level of information printed out.\n\ "); PyObject *python_svipc_msq_info(PyObject * self, PyObject * args, PyObject * kwds) { int key; int details = 0; static char *kwlist[] = { "key", "details", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "i|i", kwlist, &key, &details)) PYTHON_SVIPC_USAGE("msq_info(key, details=0)"); int status = svipc_msq_info(key, details); return PyInt_FromLong(status); } /******************************************************************* * msq init *******************************************************************/ PyDoc_STRVAR(python_svipc_msq_init_doc, "msq_init(key)\n\ (int) key - a System V IPC key\n\ Initialize a message queue identified by 'key'.\n\ "); PyObject *python_svipc_msq_init(PyObject * self, PyObject * args, PyObject * kwds) { int key; static char *kwlist[] = { "key", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &key)) PYTHON_SVIPC_USAGE("msq_init(key)"); int status = svipc_msq_init(key); return PyInt_FromLong(status); } /******************************************************************* * msq cleanup *******************************************************************/ PyDoc_STRVAR(python_svipc_msq_cleanup_doc, "msq_cleanup(key)\n\ (int) key - a System V IPC key\n\ Release the message queue identified by 'key'.\n\ "); PyObject *python_svipc_msq_cleanup(PyObject * self, PyObject * args, PyObject * kwds) { int key; static char *kwlist[] = { "key", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &key)) PYTHON_SVIPC_USAGE("msq_cleanup(key)"); int status = svipc_msq_cleanup(key); return PyInt_FromLong(status); } /******************************************************************* * msq snd *******************************************************************/ PyDoc_STRVAR(python_svipc_msq_snd_doc, "msq_snd(key,mtype,data,nowait=0)\n\ (int) key - a System V IPC key\n\ (long) mtype - a message type id\n\ (object) data - a python object\n\ (bool) nowait - a boolean\n\ \n\ Sends the content of the variable referenced by a to the message\n\ queue identified by 'key' with a message type of 'mtype'.\n\ \n\ The nowait flag controls if the execution should wait until there\n\ is space in the message queue to send the message or return with an\n\ error.\n\ "); PyObject *python_svipc_msqsnd(PyObject * self, PyObject * args, PyObject * kwds) { int key; int mtype; PyObject *a; int nowait = 0; static char *kwlist[] = { "key", "mtype", "data", "nowait", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "iiO|i", kwlist, &key, &mtype, &a, &nowait)) PYTHON_SVIPC_USAGE("msq_snd(key,mtype,data,nowait=0)"); PyArrayObject *inp_array = (PyArrayObject *) PyArray_FROM_O(a); int typeID; if (PyArray_TYPE(inp_array) == NPY_BYTE) typeID = SVIPC_CHAR; else if (PyArray_TYPE(inp_array) == NPY_SHORT) typeID = SVIPC_SHORT; else if (PyArray_TYPE(inp_array) == NPY_INT) typeID = SVIPC_INT; else if (PyArray_TYPE(inp_array) == NPY_LONG) typeID = SVIPC_LONG; else if (PyArray_TYPE(inp_array) == NPY_FLOAT) typeID = SVIPC_FLOAT; else if (PyArray_TYPE(inp_array) == NPY_DOUBLE) typeID = SVIPC_DOUBLE; else { PYTHON_SVIPC_ERROR("type not supported"); } int sizeoftype = PyArray_ITEMSIZE(inp_array); int countdims = PyArray_NDIM(inp_array); long totalnumber = PyArray_SIZE(inp_array); size_t msgsz = sizeof(typeID) + sizeof(countdims) + countdims * sizeof(countdims) + totalnumber * sizeoftype; struct svipc_msgbuf *sendmsg = malloc(sizeof(struct svipc_msgbuf) + msgsz); sendmsg->mtype = mtype; int *msgp_pint = (int *)sendmsg->mtext; *msgp_pint++ = typeID; *msgp_pint++ = countdims; int i; for (i = 0; i < countdims; i++) { *msgp_pint++ = *((int *)PyArray_DIMS(inp_array) + i); } memcpy(msgp_pint, PyArray_DATA(inp_array), totalnumber * sizeoftype); int status = svipc_msq_snd(key, sendmsg, msgsz, nowait); free(sendmsg); Py_DECREF(inp_array); return PyInt_FromLong(status); } /******************************************************************* * msq rcv *******************************************************************/ PyDoc_STRVAR(python_svipc_msq_rcv_doc, "msq_rcv(key,mtype,nowait=0)\n\ (int) key - a System V IPC key\n\ (long) mtype - a message type id\n\ (bool) nowait - a boolean\n\ Receive a message to queue identified by 'key'.\n\ "); PyObject *python_svipc_msqrcv(PyObject * self, PyObject * args, PyObject * kwds) { int key; int mtype; int nowait = 0; static char *kwlist[] = { "key", "mtype", "nowait", NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwds, "ii|i", kwlist, &key, &mtype, &nowait)) PYTHON_SVIPC_USAGE("msq_rcv(key,mtype,nowait=0)"); int *msgp_pint; struct svipc_msgbuf *recvmsg; int status = svipc_msq_rcv(key, mtype, &recvmsg, nowait); if (status == 0) { msgp_pint = (int *)recvmsg->mtext; int typeID = *msgp_pint++; int countdims = *msgp_pint++; int *pdims = msgp_pint; int *data = pdims + countdims; enum NPY_TYPES ret_py_type; if (typeID == SVIPC_CHAR) ret_py_type = NPY_BYTE; else if (typeID == SVIPC_SHORT) ret_py_type = NPY_SHORT; else if (typeID == SVIPC_INT) ret_py_type = NPY_INT; else if (typeID == SVIPC_LONG) ret_py_type = NPY_LONG; else if (typeID == SVIPC_FLOAT) ret_py_type = NPY_FLOAT; else if (typeID == SVIPC_DOUBLE) ret_py_type = NPY_DOUBLE; else { free(recvmsg); PYTHON_SVIPC_ERROR("type not supported"); }; /* platform ints for numpy array dims */ npy_intp *dims = malloc(countdims * sizeof(npy_intp)); int i; for (i = 0; i < countdims; i++) dims[i] = pdims[i]; PyArrayObject *res = (PyArrayObject *) PyArray_SimpleNewFromData(countdims, dims, ret_py_type, data); // array does not own data, shape can go PyArray_CLEARFLAGS(res,NPY_ARRAY_OWNDATA); free(dims); free(recvmsg); return (PyObject *) res; } else { PYTHON_SVIPC_ERROR("status %d\n", status); } } /******************************************************************* * module static method *******************************************************************/ static struct PyMethodDef python_svipc_methods[] = { {"setaffinity", (PyCFunction) python_svipc_misc_setaffinity, METH_VARARGS | METH_KEYWORDS, python_svipc_misc_setaffinity_doc}, {"ftok", (PyCFunction) python_svipc_misc_ftok, METH_VARARGS | METH_KEYWORDS, python_svipc_misc_ftok_doc}, {"nprocs", (PyCFunction) python_svipc_misc_nprocs, METH_NOARGS, python_svipc_misc_nprocs_doc}, {"shm_info", (PyCFunction) python_svipc_shm_info, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_info_doc}, {"shm_init", (PyCFunction) python_svipc_shm_init, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_init_doc}, {"shm_write", (PyCFunction) python_svipc_shm_write, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_write_doc}, {"shm_read", (PyCFunction) python_svipc_shm_read, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_read_doc}, {"shm_free", (PyCFunction) python_svipc_shm_free, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_free_doc}, {"shm_cleanup", (PyCFunction) python_svipc_shm_cleanup, METH_VARARGS | METH_KEYWORDS, python_svipc_shm_cleanup_doc}, {"sem_info", (PyCFunction) python_svipc_sem_info, METH_VARARGS | METH_KEYWORDS, python_svipc_sem_info_doc}, {"sem_init", (PyCFunction) python_svipc_sem_init, METH_VARARGS | METH_KEYWORDS, python_svipc_sem_init_doc}, {"sem_cleanup", (PyCFunction) python_svipc_sem_cleanup, METH_VARARGS | METH_KEYWORDS, python_svipc_sem_cleanup_doc}, {"sem_take", (PyCFunction) python_svipc_semtake, METH_VARARGS | METH_KEYWORDS, python_svipc_sem_take_doc}, {"sem_give", (PyCFunction) python_svipc_semgive, METH_VARARGS | METH_KEYWORDS, python_svipc_sem_give_doc}, {"msq_info", (PyCFunction) python_svipc_msq_info, METH_VARARGS | METH_KEYWORDS, python_svipc_msq_info_doc}, {"msq_init", (PyCFunction) python_svipc_msq_init, METH_VARARGS | METH_KEYWORDS, python_svipc_msq_init_doc}, {"msq_cleanup", (PyCFunction) python_svipc_msq_cleanup, METH_VARARGS | METH_KEYWORDS, python_svipc_msq_cleanup_doc}, {"msq_snd", (PyCFunction) python_svipc_msqsnd, METH_VARARGS | METH_KEYWORDS, python_svipc_msq_snd_doc}, {"msq_rcv", (PyCFunction) python_svipc_msqrcv, METH_VARARGS | METH_KEYWORDS, python_svipc_msq_rcv_doc}, {NULL} /* sentinel */ }; /******************************************************************* * NAME * initsvipc - module initialization * * DESCRIPTION * Initialize svipc module * * WARNING * this procedure must be called init * * PYTHON API: * import svipc * * PERSONNEL: * Matthieu Bec, Gemini Software Group - mbec@gemini.edu * * HISTORY: * 22/02/10 - created * *******************************************************************/ PyDoc_STRVAR(python_svipc_doc, "SysV IPC for Python.\n\ \n\ A module that encapsulates SysV IPC.\n\ "); #if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit_svipc(void) #else PyMODINIT_FUNC initsvipc(void) #endif { // initialize Python with thread support Py_Initialize(); // initialize numpy import_array(); /* Create the module and associated method */ #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef svipcdef = { PyModuleDef_HEAD_INIT, "svipc", /* m_name */ python_svipc_doc, /* m_doc */ -1, /* m_size */ python_svipc_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; python_svipc_module = PyModule_Create(&svipcdef); #else python_svipc_module = Py_InitModule3("svipc", python_svipc_methods, python_svipc_doc); #endif if (python_svipc_module == NULL) #if PY_MAJOR_VERSION >= 3 return NULL; #else return; #endif /* Add symbolic constants to the module */ PyModule_AddStringConstant(python_svipc_module, "version", PYTHON_SVIPC_VERSION); /* define module generic error */ python_svipc_error = PyErr_NewException("svipc.error", NULL, NULL); PyModule_AddObject(python_svipc_module, "error", python_svipc_error); /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("can't initialize module svipc"); // invoke something when the interpreter dies // Py_AtExit(python_svipc_cleanup); #if PY_MAJOR_VERSION >= 3 return python_svipc_module; #endif } yp-svipc-0.16/setup.py000066400000000000000000000037331232651007300147310ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright (C) 2011-2012 Matthieu Bec. # # This file is part of yp-svipc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from numpy.distutils.core import setup, Extension from os import uname, environ as env version = '0.16' # TODO yorick/svipc.i:SVIPC_VERSION undef_macros=[ # 'PYTHON_SVIPC_NODEBUG', # disable at compilation time. ] define_macros=[ ('PYTHON_SVIPC_VERSION', '\\\"%s\\\"' % version), ('SVIPC_NOSEGFUNC', None), ] platform=uname()[0] extra_compile_args=[ #'-g3', #'-ggdb3' ] setup(name='python-svipc', version=version, description='System V IPC for Python', long_description='A python plugin to System V IPC.', author='Matthieu D.C. Bec', url='https://github.com/mdcb', author_email='mdcb808@gmail.com', platforms=platform, license='GPL', ext_modules=[ Extension( name='svipc', sources = [ 'common/svipc_misc.c', 'common/svipc_shm.c', 'common/svipc_sem.c', 'common/svipc_msq.c', 'python/svipc_module.c', ], include_dirs=['common'], define_macros=define_macros, undef_macros=undef_macros, extra_compile_args = extra_compile_args, ) ], ) yp-svipc-0.16/yorick/000077500000000000000000000000001232651007300145115ustar00rootroot00000000000000yp-svipc-0.16/yorick/Makefile000066400000000000000000000064261232651007300161610ustar00rootroot00000000000000# # Copyright (C) 2011-2012 Matthieu Bec. # # This file is part of yp-svipc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # these values filled in by yorick -batch make.i Y_MAKEDIR=/export/home/mdcb/work/webrepos/yorick/relocate Y_EXE=/export/home/mdcb/work/webrepos/yorick/relocate/bin/yorick Y_EXE_PKGS= Y_EXE_HOME=/export/home/mdcb/work/webrepos/yorick/relocate Y_EXE_SITE=/export/home/mdcb/work/webrepos/yorick/relocate Y_HOME_PKG= # ----------------------------------------------------- optimization flags # options for make command line, e.g.- make COPT=-g TGT=exe COPT=$(COPT_DEFAULT) TGT=$(DEFAULT_TGT) # ------------------------------------------------ macros for this package PKG_NAME=svipc PKG_I=svipc.i OBJS=yorick_svipc.o common_svipc_misc.o common_svipc_shm.o common_svipc_sem.o common_svipc_msq.o # change to give the executable a name other than yorick PKG_EXENAME=yorick # PKG_DEPLIBS=-Lsomedir -lsomelib for dependencies of this package PKG_DEPLIBS= # set compiler (or rarely loader) flags specific to this package PKG_CFLAGS=-I ../common -Wall PKG_LDFLAGS= # list of additional package names you want in PKG_EXENAME # (typically Y_EXE_PKGS should be first here) EXTRA_PKGS=$(Y_EXE_PKGS) # list of additional files for clean PKG_CLEAN= # autoload file for this package, if any PKG_I_START= # non-pkg.i include files for this package, if any PKG_I_EXTRA= # -------------------------------- standard targets and rules (in Makepkg) # set macros Makepkg uses in target and dependency names # DLL_TARGETS, LIB_TARGETS, EXE_TARGETS # are any additional targets (defined below) prerequisite to # the plugin library, archive library, and executable, respectively PKG_I_DEPS=$(PKG_I) Y_DISTMAKE=distmake include $(Y_MAKEDIR)/Make.cfg include $(Y_MAKEDIR)/Makepkg include $(Y_MAKEDIR)/Make$(TGT) # override macros Makepkg sets for rules and other macros # Y_HOME and Y_SITE in Make.cfg may not be correct (e.g.- relocatable) Y_HOME=$(Y_EXE_HOME) Y_SITE=$(Y_EXE_SITE) # reduce chance of yorick-1.5 corrupting this Makefile MAKE_TEMPLATE = protect-against-1.5 # ------------------------------------- targets and rules for this package common_svipc_misc.o: ../common/svipc_misc.c ../common/svipc_misc.h $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c ../common/svipc_misc.c common_svipc_shm.o: ../common/svipc_shm.c ../common/svipc_shm.h $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c ../common/svipc_shm.c common_svipc_sem.o: ../common/svipc_sem.c ../common/svipc_sem.h $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c ../common/svipc_sem.c common_svipc_msq.o: ../common/svipc_msq.c ../common/svipc_msq.h $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c ../common/svipc_msq.c # -------------------------------------------------------- end of Makefile yp-svipc-0.16/yorick/svipc.i000066400000000000000000000374021232651007300160150ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ SVIPC_VERSION = 0.16; local svipc; /* DOCUMENT svipc plugin: System V inter-process communication Available functions (for more info, help,function) 1. shared memory shm_init ................ create a pool of shared memory Ids shm_cleanup ............. release a pool of shared memory Ids shm_info ................ print a report on shared memory pool usage shm_write ............... write to shared memory Id shm_read ................ read from shared memory Id shm_free ................ release a shared memory Id shm_var ................. create a variable bound to shared memory shm_unvar ............... destroys a variable bound to shared memory 2. semaphores sem_init ................ create a pool of semphores Ids sem_cleanup ............. release a pool of semphores Ids sem_info ................ print a report on semaphores usage sem_take ................ take semaphore Id sem_give ................ give (release) semaphore Id 3. message queues msq_init ................ create a message queue msq_cleanup ............. release a message queue msq_info ................ print a report on message queue msq_snd ................. send a message to a message queue msq_rcv ................. receive a message from a message queue 4. miscellaneous setaffinity ............. set the running process cpu affinity ftok .................... generate a System V IPC key svipc_debug.............. debug level for the module (int) fork..................... fork the current yorick process getpid................... get the running process (yorick session) id nprocs....................returns the number of processors currently online */ plug_in, "svipc"; //--------------------------------------------------------------- // setaffinity //--------------------------------------------------------------- func setaffinity(cpu) { /* DOCUMENT setaffinity(cpu) (int) cpu - cpu affinity Only available on Linux. */ return Y_setaffinity(cpu); } extern Y_setaffinity; /* PROTOTYPE void Y_setaffinity(int) */ //--------------------------------------------------------------- // fork //--------------------------------------------------------------- extern fork; /* DOCUMENT fork fork (clones, with a different pid) the current yorick session. The child stdin is replaced by a bogus fd, so is lost. The child stdout and stderr are unchanged, so they will appear on your terminal. This function has mostly applications in parallel problems, where one want to fork childs to process operations in parallel that would/could have been done with the parent process, with the loaded environment. Synchronization between the parent and the child processes has to be done through shared memory, semaphore and message passing, as implemented in this plugin. Example: func test(void) { if (fork()!=0) write,"I'm the parent"; else { write,"I'm the child"; function_to_be_executed_by_the_child; } } > test I'm the parent I'm the child AUTHOR: F.Rigaut SEE ALSO: spawn */ //--------------------------------------------------------------- // getpid //--------------------------------------------------------------- extern getpid; /* DOCUMENT getpid() Return id of the current yorick session AUTHOR: F.Rigaut */ //--------------------------------------------------------------- // shm_init //--------------------------------------------------------------- func shm_init(key, slots=) { /* DOCUMENT shm_init(key, slots=) (int) key - a System V IPC key (int) slots - the number of shared memory segments to create Initialize a pool of shared memory identified by 'key' containing 'slots' initially free segments. */ if (slots==[]) slots=int(-1); return Y_shm_init(key, slots); } extern Y_shm_init; /* PROTOTYPE void Y_shm_init(int, int) */ //--------------------------------------------------------------- // shm_info //--------------------------------------------------------------- func shm_info(key, details=) { /* DOCUMENT shm_info(key, details=) (int) key - a System V IPC key (int) details - the level of details to print Print a report on shared memory pool identified by 'key'. 'details' controls the level of information printed out. */ if (details==[]) details=int(0); return Y_shm_info(key,details); } extern Y_shm_info; /* PROTOTYPE void Y_shm_info(int,int) */ //--------------------------------------------------------------- // shm_write //--------------------------------------------------------------- func shm_write(key,id,a,publish=) { /* DOCUMENT shm_write(key, id, a, publish=) (int) key - a System V IPC key (string) id - a slot Id (&pointer) a - a yorick variable pointer (bool) publish - broadcast to subscribers a new value has been written Write the content of the variable referenced by a in the slot identified by 'id' from the shared memory pool identified by 'key'. This operation is semaphore protected and guarantees consistency for external readers. 'a' is reference to a yorick variable, usually &variable. */ if (publish==[]) publish=int(0); return Y_shm_write(key,id,a,publish); } extern Y_shm_write; /* PROTOTYPE void Y_shm_write(int,string,pointer,int) */ //--------------------------------------------------------------- // shm_read //--------------------------------------------------------------- func shm_read(key,id,subscribe=) { /* DOCUMENT shm_read(key, id, subscribe=) (int) key - a System V IPC key (string) id - a slot Id (float) subscribe - if set, wait (block) for a publisher broadcast Read the content of the slot identified by 'id' from the shared memory pool identified by 'key'. If subscribe > 0, the parameter is understood as a maximum number of seconds to wait for a broadcast event, or timeout. If subscribe < 0, the calling process will block until reception of a broadcast. If subscribe = 0, read the current value from shared memory indepently of write broadcast. This operation is semaphore protected and guarantees consistency with external writers. */ if (subscribe==[]) subscribe=float(0); return Y_shm_read(key,id,subscribe); } extern Y_shm_read; /* PROTOTYPE void Y_shm_read(int,string,float) */ //--------------------------------------------------------------- // shm_free //--------------------------------------------------------------- func shm_free(key,id) { /* DOCUMENT shm_free(key,id) (int) key - a System V IPC key (string) id - a slot Id Release the slot identified by 'id' from the shared memory pool identified by 'key'. This operation is semaphore protected and guarantees consistency with external readers and writers. */ return Y_shm_free(key,id); } extern Y_shm_free; /* PROTOTYPE void Y_shm_free(int,string) */ //--------------------------------------------------------------- // shm_cleanup //--------------------------------------------------------------- func shm_cleanup(key) { /* DOCUMENT shm_cleanup(key) (int) key - a System V IPC key Release all the slots from the shared memory pool identified by 'key'. This operation is semaphore protected and guarantees consistency with external readers and writers. */ return Y_shm_cleanup(key); } extern Y_shm_cleanup; /* PROTOTYPE void Y_shm_cleanup(int) */ //--------------------------------------------------------------- // shm_var //--------------------------------------------------------------- extern shm_var; /* DOCUMENT shm_var, key, id, reference (int) key - master shared memory key (string) id - shared variable lookup name reference - an unadorned yorick variable Binds a new reference variable to the content of the slot identified by 'id' from the shared memory pool identified by 'key'. Access to this new reference is *NOT* semaphore protected, consistency with external readers and writers must be handled by other means in your application. */ //--------------------------------------------------------------- // shm_unvar //--------------------------------------------------------------- extern shm_unvar; /* DOCUMENT shm_unvar,reference reference - an unadorned yorick variable Unbinds a new reference variable attached to the slot identified by 'id' from the shared memory pool identified by 'key'. */ //--------------------------------------------------------------- // ftok //--------------------------------------------------------------- func ftok(path, proj=) { /* DOCUMENT ftok(path, proj=) (string) path - a unix file path (int) proj - a project number (default=0) Convert a pathname and a project identifier to a System V IPC key */ if (proj==[]) proj=int(0); return Y_ftok(path,proj); } extern Y_ftok; /* PROTOTYPE void Y_ftok(string,int) */ //--------------------------------------------------------------- // nprocs //--------------------------------------------------------------- extern nprocs; /* DOCUMENT nprocs Returns the number of processors currently online (available). */ //--------------------------------------------------------------- // svipc_debug //--------------------------------------------------------------- extern svipc_debug; /* EXTERNAL svipc_debug */ reshape, svipc_debug, int; //--------------------------------------------------------------- // sem_init //--------------------------------------------------------------- func sem_init(key, nums=) { /* DOCUMENT sem_init(key, nums=) (int) key - a System V IPC key (int) num - the number of semaphores to create Initialize a pool of semaphores identified by 'key' containing 'num' initially taken (locked) semaphores. NB: nums=0 provides a hacked functionality and reset to 0 all the semaphores in the pool. nums<0 is equivalent to sem_info. */ if (nums==[]) nums=int(-1); return Y_sem_init(key, nums); } extern Y_sem_init; /* PROTOTYPE void Y_sem_init(int, int) */ //--------------------------------------------------------------- // sem_cleanup //--------------------------------------------------------------- func sem_cleanup(key) { /* DOCUMENT sem_cleanup(key) (int) key - a System V IPC key Release the pool of semaphores identified by 'key'. */ return Y_sem_cleanup(key); } extern Y_sem_cleanup; /* PROTOTYPE void Y_sem_cleanup(int) */ //--------------------------------------------------------------- // sem_info //--------------------------------------------------------------- func sem_info(key, details=) { /* DOCUMENT sem_info(key, details=) (int) key - a System V IPC key (int) details - the level of details to print Print a report on semaphore pool identified by 'key'. 'details' controls the level of information printed out. */ if (details==[]) details=int(0); return Y_sem_info(key,details); } extern Y_sem_info; /* PROTOTYPE void Y_sem_info(int,int) */ //--------------------------------------------------------------- // sem_take //--------------------------------------------------------------- func sem_take(key, id, count=, wait=) { /* DOCUMENT sem_take(key, id, count=, wait=) (int) key - a System V IPC key (int) id - a semaphore Id (int) count - the number of operations on the semaphore (float) wait - a number of seconds Decrement semaphore Id by 'count' The default, count=1, is equivalent to 'take semaphore Id'. If wait > 0, the parameter is understood as the maximum number of seconds to wait to get hold of the semaphore, or timeout. If wait < 0, the calling process will block until it can take the semaphore. If wait = 0, returns immediately with a status if the operation succeeded or not. */ if (count==[]) count=1; if (wait==[]) wait=-1.; return Y_sem_take(key,id,count,wait); } extern Y_sem_take; /* PROTOTYPE void Y_sem_take(int,int,int,float) */ //--------------------------------------------------------------- // sem_give //--------------------------------------------------------------- func sem_give(key,id,count=) { /* DOCUMENT sem_give(key, id, count=) (int) key - a System V IPC key (int) id - a semaphore Id (int) count - the number of operations on the semaphore Increment the semaphore Id by 'count' The default, count=1, is equivalent to 'release semaphore Id'. */ if (count==[]) count=1; return Y_sem_give(key,id,count); } extern Y_sem_give; /* PROTOTYPE void Y_sem_give(int,int,int) */ //--------------------------------------------------------------- // msq_init //--------------------------------------------------------------- func msq_init(key) { /* DOCUMENT msq_init(key) (int) key - a System V IPC key Creates a message queue identified by 'key'. */ return Y_msq_init(key); } extern Y_msq_init; /* PROTOTYPE void Y_msq_init(int) */ //--------------------------------------------------------------- // msq_cleanup //--------------------------------------------------------------- func msq_cleanup(key) { /* DOCUMENT msq_cleanup(key) (int) key - a System V IPC key Release the message queue identified by 'key'. */ return Y_msq_cleanup(key); } extern Y_msq_cleanup; /* PROTOTYPE void Y_msq_cleanup(int) */ //--------------------------------------------------------------- // msq_info //--------------------------------------------------------------- func msq_info(key, details=) { /* DOCUMENT msq_info(key, details=) (int) key - a System V IPC key (int) details - the level of details to print Print a report on the message queue identified by 'key'. 'details' controls the level of information printed out. */ if (details==[]) details=int(0); return Y_msq_info(key,details); } extern Y_msq_info; /* PROTOTYPE void Y_msq_info(int,int) */ //--------------------------------------------------------------- // msq_snd //--------------------------------------------------------------- func msq_snd(key,mtype,a,nowait=) { /* DOCUMENT msq_snd(key, mtype, a, nowait=) (int) key - a System V IPC key (long) mtype - a message type id (&pointer) a - a yorick variable pointer (bool) nowait - a boolean Sends the content of the variable referenced by a to the message queue identified by 'key' with a message type of 'mtype'. The nowait flag controls if the execution should wait until there is space in the message queue to send the message or return with an error. */ if (nowait==[]) nowait=0; return Y_msq_snd(key,mtype,a,nowait); } extern Y_msq_snd; /* PROTOTYPE void Y_msq_snd(int,long,pointer,int) */ //--------------------------------------------------------------- // msq_rcv //--------------------------------------------------------------- func msq_rcv(key,mtype,nowait=) { /* DOCUMENT msq_rcv(key, mtype, nowait=) To Be Documented. */ if (nowait==[]) nowait=0; return Y_msq_rcv(key, mtype, nowait); } extern Y_msq_rcv; /* PROTOTYPE void Y_msq_rcv(int,long,int) */ yp-svipc-0.16/yorick/yorick_svipc.c000066400000000000000000000314461232651007300173710ustar00rootroot00000000000000/* * Copyright (C) 2011-2012 Matthieu Bec * * This file is part of yp-svipc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "ydata.h" #include "svipc.h" //--------------------------------------------------------------- // Y_setaffinity //--------------------------------------------------------------- void Y_setaffinity(int cpu) { PushIntValue(svipc_setaffinity(cpu)); } //--------------------------------------------------------------- // Y_nprocs //--------------------------------------------------------------- void Y_nprocs(int nArgs) { PushLongValue(svipc_nprocs()); } //--------------------------------------------------------------- // Y_getpid //--------------------------------------------------------------- void Y_getpid(int nArgs) { PushIntValue(getpid()); } //--------------------------------------------------------------- // Y_fork //--------------------------------------------------------------- void Y_fork(int nArgs) { pid_t pid; // automatic child reaping signal(SIGCHLD, SIG_IGN); pid = fork(); if (pid == 0) { // the child needs a stdin to keep yorick's eventloop happy, // but independent from the parent one. Create a dummy one. int fd[2]; pipe(fd); // create a dummy pipe close(STDIN_FILENO); // close stdin inherited from fork dup2(fd[0], STDIN_FILENO); // swap in the pipe's read end as new stdin close(fd[1]); // pipe's write end is not used, close it } PushIntValue(pid); } //--------------------------------------------------------------- // Y_ftok //--------------------------------------------------------------- void Y_ftok(char *path, int proj) { key_t key = svipc_ftok(path, proj); PushIntValue(key); } //--------------------------------------------------------------- // Y_shm_init //--------------------------------------------------------------- void Y_shm_init(int key, int numslots) { int status = svipc_shm_init(key, numslots); PushIntValue(status); } //--------------------------------------------------------------- // Y_shm_cleanup //--------------------------------------------------------------- void Y_shm_cleanup(int key) { int status = svipc_shm_cleanup(key); PushIntValue(status); } //--------------------------------------------------------------- // Y_shm_info //--------------------------------------------------------------- void Y_shm_info(int key, int details) { int status = svipc_shm_info(key, details); PushIntValue(status); } //--------------------------------------------------------------- // Y_shm_write //--------------------------------------------------------------- void Y_shm_write(int key, char *id, void *a, int publish) { slot_array arr; Array *array = (Array *) Pointee(a); int typeID = array->type.base->dataOps->typeID; int countdims = CountDims(array->type.dims); if (!countdims) { Debug(0, "non array type not supported\n"); PushIntValue(-1); return; } // long totalnumber = TotalNumber(array->type.dims); // also as, array->type.number if (typeID == charStruct.dataOps->typeID) arr.typeID = SVIPC_CHAR; else if (typeID == shortStruct.dataOps->typeID) arr.typeID = SVIPC_SHORT; else if (typeID == intStruct.dataOps->typeID) arr.typeID = SVIPC_INT; else if (typeID == longStruct.dataOps->typeID) arr.typeID = SVIPC_LONG; else if (typeID == floatStruct.dataOps->typeID) arr.typeID = SVIPC_FLOAT; else if (typeID == doubleStruct.dataOps->typeID) arr.typeID = SVIPC_DOUBLE; else { Debug(0, "type not supported\n"); PushIntValue(-1); return; } arr.countdims = countdims; arr.number = (int *)malloc(arr.countdims * sizeof(*arr.number)); Dimension *d; int *pnum = arr.number; for (d = array->type.dims;; d = d->next) { *pnum++ = d->number; if (d->next == NULL) break; } arr.data = a; int status = svipc_shm_write(key, id, &arr, publish); // fixme: cleanup the api free(arr.number); PushIntValue(status); return; } //--------------------------------------------------------------- // Y_shm_read //--------------------------------------------------------------- void Y_shm_read(int key, char *id, float subscribe) { slot_array arr; memset(&arr, 0, sizeof(arr)); int status = svipc_shm_read(key, id, &arr, subscribe); if (status == 0) { Dimension *tmp = tmpDims; tmpDims = 0; FreeDimension(tmp); int countdims = arr.countdims; int *pnum = arr.number + arr.countdims - 1; long totalnumber = 1; for (; countdims > 0; countdims--) { totalnumber *= *pnum; tmpDims = NewDimension(*pnum--, 1L, tmpDims); } Array *a; if (arr.typeID == SVIPC_CHAR) a = NewArray(&charStruct, tmpDims); else if (arr.typeID == SVIPC_SHORT) a = NewArray(&shortStruct, tmpDims); else if (arr.typeID == SVIPC_INT) a = NewArray(&intStruct, tmpDims); else if (arr.typeID == SVIPC_LONG) a = NewArray(&longStruct, tmpDims); else if (arr.typeID == SVIPC_FLOAT) a = NewArray(&floatStruct, tmpDims); else if (arr.typeID == SVIPC_DOUBLE) a = NewArray(&doubleStruct, tmpDims); else { release_slot_array(&arr); Debug(0, "type not supported\n"); PushIntValue(-1); return; } char *buff = ((Array *) PushDataBlock(a))->value.c; memcpy(buff, arr.data, totalnumber * a->type.base->size); release_slot_array(&arr); } else { Debug(1, "read failed\n"); // debug level 1: could be a timeout PushIntValue(-1); return; } } //--------------------------------------------------------------- // Y_shm_free //--------------------------------------------------------------- void Y_shm_free(int key, char *id) { int status = svipc_shm_free(key, id); PushIntValue(status); } //-------------------------------------------------------------------- // Y_shm_var //-------------------------------------------------------------------- void Y_shm_var(int nArgs) { slot_array arr; int key = (int)yarg_sl(nArgs - 1); char *id = yarg_sq(nArgs - 2); int status = svipc_shm_attach(key, id, &arr); if (status) YError("svipc_shm_attach failed"); int typeID = arr.typeID; int countdims = arr.countdims; Dimension *tmp = tmpDims; tmpDims = 0; FreeDimension(tmp); int *pnum = arr.number + arr.countdims - 1; for (; countdims > 0; countdims--) { tmpDims = NewDimension(*pnum--, 1L, tmpDims); } Symbol *arg = sp - nArgs + 1; // skip over the two args we just parsed arg += 2; nArgs -= 2; long index; if (nArgs < 1 || arg->ops != &referenceSym) YError("first argument to reshape must be variable reference"); index = arg->index; StructDef *base = 0; void *address = 0; Array *owner = 0; /* LValue *result; */ address = (char *)arr.data; owner = 0; if (typeID == charStruct.dataOps->typeID) base = &charStruct; else if (typeID == shortStruct.dataOps->typeID) base = &shortStruct; else if (typeID == intStruct.dataOps->typeID) base = &intStruct; else if (typeID == longStruct.dataOps->typeID) base = &longStruct; else if (typeID == floatStruct.dataOps->typeID) base = &floatStruct; else if (typeID == doubleStruct.dataOps->typeID) base = &doubleStruct; else { Debug(0, "fatal: unsupported typeID !!!\n"); // fixme - leave nicely } Debug(3, "ref established at pdata %p\n", address); /* result = */ PushDataBlock(NewLValueM(owner, address, base, tmpDims)); PopTo(&globTab[index]); } //-------------------------------------------------------------------- // Y_shm_unvar //-------------------------------------------------------------------- void Y_shm_unvar(int nArgs) { Symbol *arg = sp - nArgs + 1; long index; DataBlock *db; if (nArgs != 1 || arg->ops != &referenceSym) YError("shm_unvar argument must be a variable reference"); index = arg->index; db = globTab[index].value.db; /* might not be meaningful... */ void *addr = ((LValue *) (globTab[index].value.db))->address.m; int status = svipc_shm_detach(addr); if (status) YError("svipc_shm_detach failed"); /* same as var=[], but works for LValues as well */ globTab[index].value.db = RefNC(&nilDB); if (globTab[index].ops == &dataBlockSym) { Unref(db); Debug(5, "Unref\n"); } else { globTab[index].ops = &dataBlockSym; Debug(5, "ok\n"); } Drop(1); } //-------------------------------------------------------------------- // sempahores //-------------------------------------------------------------------- void Y_sem_init(int key, int numslots) { int status = svipc_sem_init(key, numslots); PushIntValue(status); } void Y_sem_cleanup(int key) { int status = svipc_sem_cleanup(key); PushIntValue(status); } void Y_sem_info(int key, int details) { int status = svipc_sem_info(key, details); PushIntValue(status); } void Y_sem_take(int key, int id, int count, float wait) { int status = svipc_semtake(key, id, count, wait); PushIntValue(status); } void Y_sem_give(int key, int id, int count) { int status = svipc_semgive(key, id, count); PushIntValue(status); } //-------------------------------------------------------------------- // message queues //-------------------------------------------------------------------- void Y_msq_init(int key) { int status = svipc_msq_init(key); PushIntValue(status); } void Y_msq_cleanup(int key) { int status = svipc_msq_cleanup(key); PushIntValue(status); } void Y_msq_info(int key, int details) { int status = svipc_msq_info(key, details); PushIntValue(status); } void Y_msq_snd(int key, long mtype, void *a, int nowait) { Array *array = (Array *) Pointee(a); int typeID = array->type.base->dataOps->typeID; int countdims = CountDims(array->type.dims); long totalnumber = TotalNumber(array->type.dims); if (!countdims) { Debug(0, "non array type not supported\n"); PushIntValue(-1); return; } int sizeoftype; if (typeID == charStruct.dataOps->typeID) sizeoftype = sizeof(char); else if (typeID == shortStruct.dataOps->typeID) sizeoftype = sizeof(short); else if (typeID == intStruct.dataOps->typeID) sizeoftype = sizeof(int); else if (typeID == longStruct.dataOps->typeID) sizeoftype = sizeof(long); else if (typeID == floatStruct.dataOps->typeID) sizeoftype = sizeof(float); else if (typeID == doubleStruct.dataOps->typeID) sizeoftype = sizeof(double); else { Debug(0, "type not supported\n"); PushIntValue(-1); return; } size_t msgsz = sizeof(typeID) + sizeof(countdims) + countdims * sizeof(countdims) + totalnumber * sizeoftype; struct svipc_msgbuf *sendmsg = malloc(sizeof(struct svipc_msgbuf) + msgsz); sendmsg->mtype = mtype; int *msgp_pint = (int *)sendmsg->mtext; *msgp_pint++ = typeID; *msgp_pint++ = countdims; Dimension *d; for (d = array->type.dims;; d = d->next) { *msgp_pint++ = d->number; if (d->next == NULL) break; } memcpy(msgp_pint, a, totalnumber * sizeoftype); Debug(3, "Y_msq_snd typeID %d countdims %d totalnumber %ld\n", typeID, countdims, totalnumber); int status = svipc_msq_snd(key, sendmsg, msgsz, nowait); free(sendmsg); PushIntValue(status); } void Y_msq_rcv(int key, long mtype, int nowait) { int *msgp_pint; struct svipc_msgbuf *recvmsg; int status = svipc_msq_rcv(key, mtype, &recvmsg, nowait); msgp_pint = (int *)recvmsg->mtext; if (status == 0) { Dimension *tmp = tmpDims; tmpDims = 0; FreeDimension(tmp); int typeID = *msgp_pint++; status = typeID; int countdims = *msgp_pint++; long totalnumber = 1; int *msgp_pint0 = msgp_pint; for (; countdims > 0; countdims--) { int thisdim = *(msgp_pint0 + countdims - 1); msgp_pint++; totalnumber *= thisdim; tmpDims = NewDimension(thisdim, 1L, tmpDims); } Array *a; if (typeID == SVIPC_CHAR) a = NewArray(&charStruct, tmpDims); else if (typeID == SVIPC_SHORT) a = NewArray(&shortStruct, tmpDims); else if (typeID == SVIPC_INT) a = NewArray(&intStruct, tmpDims); else if (typeID == SVIPC_LONG) a = NewArray(&longStruct, tmpDims); else if (typeID == SVIPC_FLOAT) a = NewArray(&floatStruct, tmpDims); else if (typeID == SVIPC_DOUBLE) a = NewArray(&doubleStruct, tmpDims); else { Debug(0, "type not supported\n"); PushIntValue(-1); return; } char *buff = ((Array *) PushDataBlock(a))->value.c; memcpy(buff, msgp_pint, totalnumber * a->type.base->size); // cleanup free(recvmsg); } else { PushIntValue(status); } }