From 088452702812614cbbbaa64b116f29971920fac2 Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Sat, 15 Aug 2009 11:51:15 +0200 Subject: Renamed 'mq' to 'ipc' --- portato/ipc.pyx | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 portato/ipc.pyx (limited to 'portato/ipc.pyx') diff --git a/portato/ipc.pyx b/portato/ipc.pyx new file mode 100644 index 0000000..4a06102 --- /dev/null +++ b/portato/ipc.pyx @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# +# File: portato/ipc.pyx +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2006-2009 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann + +class MessageQueueError(Exception): + pass + +class MessageQueueRemovedError (MessageQueueError): + pass + +cdef class MessageQueue (object): + + CREAT = IPC_CREAT + EXCL = IPC_EXCL + + cdef int msgid + cdef readonly key_t key + + def __init__ (self, key = None, int flags = 0): + + if (flags & IPC_EXCL) and not (flags & IPC_CREAT): + raise MessageQueueError("EXCL must be combined with CREAT.") + + if key is None and not (flags & IPC_EXCL): + raise MessageQueueError("The key can only be None if EXCL is set.") + + # make sure there is nothing ... obscure + flags &= (IPC_CREAT | IPC_EXCL) + + flags |= 0600 # mode + + if key is None: + check = True + while check: + self.key = self.random_key() + self.msgid = msgget(self.key, flags) + check = (self.msgid == -1 and errno == EEXIST) + else: + self.key = key + self.msgid = msgget(key, flags) + + if self.msgid == -1: + if errno == EACCES: + raise MessageQueueError("Permission denied.") + elif errno == EEXIST: + raise MessageQueueError("Queue already exists.") + elif errno == ENOENT: + raise MessageQueueError("Queue does not exist and CREAT is not set.") + elif errno == ENOMEM or errno == ENOSPC: + raise MessageQueueError("Insufficient ressources.") + else: + raise OSError(errno, strerror(errno)) + + def remove (self): + cdef msqid_ds info + cdef int ret + + ret = msgctl(self.msgid, IPC_RMID, &info) + + if ret == -1: + if errno == EIDRM or errno == EINVAL: + raise MessageQueueRemovedError("Queue already removed.") + elif errno == EPERM: + raise MessageQueueError("Permission denied.") + else: + raise OSError(errno, strerror(errno)) + + def send (self, message, int type = 1): + cdef msg_data * msg + cdef int ret + cdef long size = len(message) + + if type <= 0: + raise ValueError("type must be > 0") + + if size >= MAX_MESSAGE_SIZE: + raise ValueError("Message must be smaller than %d", MAX_MESSAGE_SIZE) + + msg = PyMem_Malloc(sizeof(msg_data) + size) + + if msg is NULL: + raise MemoryError("Out of memory") + + memcpy(msg.mtext, message, size) + msg.mtype = type + + with nogil: + ret = msgsnd(self.msgid, msg, size, 0) + + try: + if ret == -1: + if errno == EIDRM or errno == EINVAL: + raise MessageQueueRemovedError("Queue was removed.") + elif errno == EINTR: + raise MessageQueueError("Signaled while waiting.") + elif errno == EACCES: + raise MessageQueueError("Permission denied.") + else: + raise OSError(errno, strerror(errno)) + finally: + PyMem_Free(msg) + + def receive (self): + cdef msg_data * msg + cdef int ret + cdef object retTuple + + msg = PyMem_Malloc(sizeof(msg_data) + MAX_MESSAGE_SIZE) + + if msg is NULL: + raise MemoryError("Out of memory") + + msg.mtype = 0 + + with nogil: + ret = msgrcv(self.msgid, msg, MAX_MESSAGE_SIZE, 0, 0) + + try: + if ret == -1: + if errno == EIDRM or errno == EINVAL: + raise MessageQueueRemovedError("Queue was removed.") + elif errno == EINTR: + raise MessageQueueError("Signaled while waiting.") + elif errno == EACCES: + raise MessageQueueError("Permission denied.") + else: + raise OSError(errno, strerror(errno)) + + retTuple = (PyString_FromStringAndSize(msg.mtext, ret), msg.mtype) + finally: + PyMem_Free(msg) + + return retTuple + + cdef key_t random_key (self): + return (rand() / (RAND_MAX + 1) * INT_MAX) -- cgit v1.2.3-70-g09d2 From 2fdd70e3a102f666ab9f036d76e7e892421f6840 Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Sat, 15 Aug 2009 12:09:43 +0200 Subject: documentation --- doc/Changelog | 1 + portato/ipc.pyx | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'portato/ipc.pyx') diff --git a/doc/Changelog b/doc/Changelog index ea9605c..8fcb404 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,7 @@ next: - allow eix as backend DB +- use an internal messagequeue module instead of external shm 0.13: - allow lines w/o keyword in package.keywords diff --git a/portato/ipc.pyx b/portato/ipc.pyx index 4a06102..e9340cf 100644 --- a/portato/ipc.pyx +++ b/portato/ipc.pyx @@ -11,12 +11,21 @@ # Written by René 'Necoro' Neumann class MessageQueueError(Exception): + """ + Base class for different queue errors. + """ pass class MessageQueueRemovedError (MessageQueueError): + """ + This class is used iff the queue is already removed. + """ pass cdef class MessageQueue (object): + """ + A simple interface to the SysV message queues. + """ CREAT = IPC_CREAT EXCL = IPC_EXCL @@ -25,12 +34,18 @@ cdef class MessageQueue (object): cdef readonly key_t key def __init__ (self, key = None, int flags = 0): + """ + Create a new MessageQueue instance. Depending on the passed in flags, + different behavior occurs. See man msgget for the details. + + If key is None, a random key is created. + """ if (flags & IPC_EXCL) and not (flags & IPC_CREAT): - raise MessageQueueError("EXCL must be combined with CREAT.") + raise ValueError("EXCL must be combined with CREAT.") if key is None and not (flags & IPC_EXCL): - raise MessageQueueError("The key can only be None if EXCL is set.") + raise ValueError("The key can only be None if EXCL is set.") # make sure there is nothing ... obscure flags &= (IPC_CREAT | IPC_EXCL) @@ -55,11 +70,14 @@ cdef class MessageQueue (object): elif errno == ENOENT: raise MessageQueueError("Queue does not exist and CREAT is not set.") elif errno == ENOMEM or errno == ENOSPC: - raise MessageQueueError("Insufficient ressources.") + raise MemoryError("Insufficient ressources.") else: raise OSError(errno, strerror(errno)) def remove (self): + """ + Removes the message queue. + """ cdef msqid_ds info cdef int ret @@ -74,6 +92,12 @@ cdef class MessageQueue (object): raise OSError(errno, strerror(errno)) def send (self, message, int type = 1): + """ + Sends a message with a specific type. + + The type must be larger zero. + Also note, that this is always blocking. + """ cdef msg_data * msg cdef int ret cdef long size = len(message) @@ -109,6 +133,11 @@ cdef class MessageQueue (object): PyMem_Free(msg) def receive (self): + """ + Receives a message from the queue and returns the (msg, type) pair. + + Note that this method is always blocking. + """ cdef msg_data * msg cdef int ret cdef object retTuple -- cgit v1.2.3-70-g09d2