KBUS Python bindings for Ksocks

KBUS lightweight message system.

Ksock

class kbus.Ksock(which=0, mode='rw')

Bases: object

A wrapper around a KBUS device, for purposes of message sending.

which is which KBUS device to open – so if which is 3, we open /dev/kbus3.

mode should be ‘r’ or ‘rw’ – i.e., whether to open the device for read or write (opening for write also allows reading, of course).

Ksock can act like an iterable container; it implements __iter__() and next() in the usual way. It also provides __enter__() and __exit__() methods to support the use of with.

I’m not really very keen on the name Ksock, but it’s better than the original “File”, which I think was actively misleading.

IOC_BIND = 1074293506
IOC_DISCARD = 27401
IOC_KSOCKID = 2148035332
IOC_LASTSENT = 2148035338
IOC_LENLEFT = 2148035335
IOC_MAGIC = 'k'
IOC_MAXMSGS = 3221777163
IOC_MAXMSGSIZE = 3221777170
IOC_MSGONLYONCE = 3221777166
IOC_NEWDEVICE = 2148035344
IOC_NEXTMSG = 2148035334
IOC_NUMMSGS = 2148035340
IOC_REPLIER = 3221777157
IOC_REPORTREPLIERBINDS = 3221777169
IOC_RESET = 27393
IOC_SEND = 2148035336
IOC_UNBIND = 1074293507
IOC_UNREPLIEDTO = 2148035341
IOC_VERBOSE = 3221777167
bind(name, replier=False)

Bind the given name to the file descriptor.

If replier, then we are binding as the only fd that can reply to this message name.

close()

Shuts down the socket. This implicitly unbinds the Ksock client object from every name it was bound to. Any further attempt to use the object will cause errors.

discard()

Discard the message being written.

Indicates that we have should throw away the message we’ve been writing. Has no effect if there is no current message being written (for instance, because send() has already been called). be sent.

fileno()

Return the integer file descriptor from our internal fd.

This allows a Ksock instance to be used in a call of select.select() - so, for instance, one should be able to do:

(r, w, x) = select.select([ksock1, ksock2, ksock3], None, None)

instead of the (less friendly, but also valid):

(r, w, x) = select.select([ksock1.fd, ksock2.fd, ksock3.fd], None, None)
find_replier(name)

Find the id of the replier (if any) for this message.

Returns None if there was no replier, otherwise the replier’s id.

kernel_module_verbose(verbose=True, just_ask=False)

Determine whether the kernel module should output verbose messages.

Determine whether the kernel module should output verbose messages for this device (this Ksock). This will only have any effect if the kernel module was built with CONFIG_KBUS_DEBUG defined.

The default is False, i.e., not to output verbose messages (as this clutters up the kernel log).

  • if verbose is true then we want verbose messages.
  • if just_ask is true, then we just want to find out the current state of the flag, and verbose will be ignored.

Returns the previous value of the flag (i.e., what it used to be set to). Which, if just_ask is true, will also be the current state.

Beware that setting this flag affects the Ksock as a whole, so it is possible for several programs to open a Ksock and “disagree” about how this flag should be set.

ksock_id()

Return the internal ‘Ksock id’ for this file descriptor.

last_msg_id()

Return the id of the last message written on this file descriptor.

Returns 0 before any messages have been sent.

len_left()

Return how many bytes of the current message are still to be read.

Returns 0 if there is no current message (i.e., next_msg() has not been called), or if there are no bytes left.

max_message_size()

Return the maximum message size that can be written to this KBUS device.

max_messages()

Return the number of messages that can be queued on this Ksock.

new_device()

Request that KBUS set up a new device (/dev/kbus<n>).

Note that it can take a little while for the hotplugging mechanisms to set the new device up for user access.

Returns the new device number (<n>).

next()

This provides iteration support. Each iteration gives a whole message as returned by read_next_msg(). We stop when there is no next message to read.

next_msg()

Indicates that we want to start reading the next message.

Returns the length of the next message, or 0 if there is no next message at the present time.

num_messages()

Return the number of messages that are queued on this Ksock.

num_unreplied_to()

Return the number of replies we still have outstanding.

That is, the number of Requests that we have read, which had the Message.WANT_YOU_TO_REPLY flag set, but for which we have not yet sent a Reply.

read_data(count)

Read the next count bytes, and return them.

Returns ‘’ (the empty string) if there was nothing to be read, which is consistent with now Python file reads normally behave at end-of-file.

read_msg(length)

Read a Message of length length bytes.

It is assumed that length was returned by a previous call of next_msg(). It must be large enough to cause the entire message to be read.

After the data has been read, it is passed to Message to construct a message instance, which is returned.

Returns None if there was nothing to be read.

read_next_msg()

Read the next Message.

Equivalent to a call of next_msg(), followed by reading the appropriate number of bytes and passing that to Message to construct a message instance, which is returned.

Returns None if there was nothing to be read.

report_replier_binds(report_events=True, just_ask=False)

Determine whether the kernel module should report Replier bind/unbind events.

Determine whether the kernel module should output a “synthetic” message to announce each Replier bind/unbind event.

When the flag is set, then each time a Replier binds or unbinds to a message (i.e., when ksock.bind(name,True) or ksock.unbind(name,True is called), a message will automatically be generated and sent.

The message generated is called ‘$.KBUS.ReplierBindEvent’, and it has data:

  • a 32-bit value, 1 if this is a bind, 0 if it is an unbind
  • a 32-bit value, the Ksock id of the binder
  • the name of the message being bound to by a Replier (terminated by a null byte, and then, if necessary, padded up to the next four-byte boundary with null bytes

The default is False, i.e., not to output report such events.

  • if report_events is true then we want bind/unbind messages.
  • if just_ask is true, then we just want to find out the current state of the flag, and report_events will be ignored.

Returns the previous value of the flag (i.e., what it used to be set to). Which, if just_ask is true, will also be the current state.

Beware that setting this flag affects the Ksock as a whole, so it is possible for several programs to open a Ksock and “disagree” about how this flag should be set.

send()

Indicates that we have finished writing a message, and it should be sent.

Returns the MessageId of the send message.

Raises IOError with errno ENOMSG if no message has been written, i.e. there is nothing to send.

send_msg(message)

Write a Message, and then send it.

Entirely equivalent to calling write_msg() and then send(), and returns the MessageId of the sent message, as send() does.

set_max_message_size(count)

Set the maximum message size that can be written to this KBUS device.

A count of 0 does not actually change the value - this may thus be used to query the Ksock for the current value of the maximum.

A ‘count’ of 1 also does not change the value, instead, it returns the absolute maximum size that the value may be set to.

The method max_message_size() method is provided as a possibly simpler to use alternative for a call of ‘count’ 0.

Returns the maximum size of message that may be written to this KBUS device, or a query result as described above.

set_max_messages(count)

Set the number of messages that can be queued on this Ksock.

A count of 0 does not actually change the value - this may thus be used to query the Ksock for the current value of the maximum. However, the “more Pythonic” max_messages() method is provided for use when such a query is wanted, which is just syntactic sugar around such a call.

Returns the number of messages that are allowed to be queued on this Ksock.

unbind(name, replier=False)

Unbind the given name from the file descriptor.

The arguments need to match the binding that we want to unbind.

wait_for_msg(timeout=None)

Wait for the next Message.

This is a simple wrapper around select.select(), waiting for the next Message on this Ksock.

If timeout is given, it is a floating point number of seconds, after which to timeout the select, otherwise this method will wait forever.

Returns the new Message, or None if the timeout expired.

want_messages_once(only_once=False, just_ask=False)

Determine whether multiply-bound messages are only received once.

Determine whether we should receive a particular message once, even if we are both a Replier and Listener for the message, or if we are registered more than once as a Listener for the message name.

Note that in the case of a Request that we should reply to, we will always get the Request, and it will be the Listener’s version of the message that will be “dropped”.

The default is False, i.e., to receive each message as many times as we are bound to its name.

  • if only_once is true then we want to receive each message once only.
  • if just_ask is true, then we just want to find out the current state of the flag, and only_once will be ignored.

Returns the previous value of the flag (i.e., what it used to be set to). Which, if just_ask is true, will also be the current state.

Beware that setting this flag affects how messages are added to the Ksock’s message queue as soon as it is set - so changing it and then changing it back “at once” is not (necessarily) a null operation.

write_data(data)

Write out (and flush) some data.

This does not actually send the message and does not imply that what has been written is all of a message (although clearly it should form some of a message).

write_msg(message)

Write a Message. Doesn’t send it.

Ksock/C datastructures

Bind/unbind argument

class kbus.BindStruct

Bases: _ctypes.Structure

The datastucture we need to describe an IOC_BIND argument

is_replier

Structure/Union member

len

Structure/Union member

name

Structure/Union member

Result of find_replier

class kbus.ReplierStruct

Bases: _ctypes.Structure

The datastucture we need to describe an IOC_REPLIER argument

len

Structure/Union member

name

Structure/Union member

return_id

Structure/Union member

Result of send

class kbus.SendResultStruct

Bases: _ctypes.Structure

The datastucture we need to describe an IOC_SEND argument/return

msg_id

Structure/Union member

retval

Structure/Union member

Other functions

read_bindings

kbus.read_bindings(names)

Read the bindings from /proc/kbus/bindings, and return a list

/proc/kbus/bindings gives us data like:

0: 10 16319 R $.Fred
0: 11 17420 L $.Fred.Bob
0: 12 17422 R $.William

(i.e., device, file descriptor id, PID of process, whether it is Replier or Listener, and the message name concerned).

names is a dictionary of file descriptor binding id to string (name) - for instance:

{ 10:’f1’, 11:’f2’ }

If there is no entry in the names dictionary for a given id, then the id will be used (as an integer).

Thus with the above we would return a list of the form:

[ ('f1', True, '$.Fred'), ('f2', False, '$.Fred.Bob'),
  (12, True, '$.William' ]