Include/switchboard.h (24 lines of code) (raw):
/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */
#ifndef SWITCHBOARD_H
#define SWITCHBOARD_H
#include "Python.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* A switchboard provides an abstraction for broadcasting changes to an object
* to a set of subscribers.
*
* Switchboards are used to notify the JIT about changes to dependencies of JIT
* compiled functions. The JIT makes assumptions about the state of the world
* in order to generate more efficient code. As a result, it may need to
* de-optimize JIT compiled functions when any of the assumptions are no longer
* valid.
*
* For example, the JIT compiled version of a function depends on the code
* object that is attached to the function. When the code object is
* re-assigned, the compiled code is no longer valid and we'll need to fall
* back to the interpreted version (or recompile).
*
* There is typically one switchboard per type being monitored (e.g. Function,
* Type). When a Function is JIT compiled, the JIT subscribes to the
* appropriate objects using Switchboard_Subscribe and the appropriate
* switchboard. When a change occurs, the changed object is responsible for
* using Switchboard_Notify to notify subscribers. If the object is gc-ed,
* the Switchboard will handle notifying subscribers that the object has
* gone away and will remove all subscribers.
*
* To avoid keeping subscribed objects alive, switchboards must not keep strong
* references to them. These creates an unfortunate amount of complexity, as we
* must store weak references to an object that is being watched.
*/
/*
* A callback is invoked when the object that is monitored by a subscription
* changes.
*
* handle - An opaque handle that represents the subscription. It may be used
* to unsubscribe.
* arg - An arbitrary argument that was registered with the subscription.
* watched - A weak reference to the object being monitored.
*/
typedef void (*Switchboard_Callback)(PyObject *handle, PyObject *arg, PyObject *watched);
typedef struct {
PyObject_HEAD
/*
* Dictionary mapping a weakref for an object to the set of subscriptions for
* the object.
*/
PyObject *subscrs;
/* Head of the list of weak references to the switchboard */
PyObject *weaklist;
/* Callback object to notify subscribers when an object is destroyed. */
PyObject *obj_gone_callback;
} Switchboard;
/*
* This must be called before using any switchboard functionality.
*/
int Switchboard_Init(void);
/*
* Create a new switchboard.
*
* Returns the switchboard on success, or NULL on error.
*/
Switchboard *Switchboard_New(void);
/*
* Watch an object for changes.
*
* obj must be weak-referenceable.
*
* Callback will be called with arg when the watch is triggered; pass NULL to
* supply no argument.
*
* Returns a handle to the subscription on success or NULL on error.
*/
PyObject *Switchboard_Subscribe(Switchboard *switchboard, PyObject *obj, Switchboard_Callback cb, PyObject *cb_arg);
/*
* Notify subscribers that an object has changed.
*
* This will invoke any callbacks that were registered for the object that
* changed. This does not clear any subscriptions.
*
* Returns 0 on success and -1 on error.
*/
int Switchboard_Notify(Switchboard *switchboard, PyObject *object);
/*
* Return the number of subscriptions for object.
*
* Returns a value >= 0 on success or -1 on error.
*/
Py_ssize_t Switchboard_GetNumSubscriptions(Switchboard *switchboard, PyObject *object);
/*
* Remove a subscription
*
* Returns
* 1 if the subscription existed and was removed successfully
* 0 if the subscription did not exist
* -1 if an error occurred
*/
int Switchboard_Unsubscribe(Switchboard *switchboard, PyObject *handle);
/*
* Remove all supplied subscriptions
*
* handles is expected to be an iterable of subscription objects
*
* Returns
* 0 on success
* -1 if an error occurred
*/
int Switchboard_UnsubscribeAll(Switchboard *switchboard, PyObject *handles);
#ifdef __cplusplus
}
#endif
#endif /* SWITCHBOARD_H */