1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
/* KInterbasDB Python Package - Header File for Events Support
*
* Version 3.3
*
* The following contributors hold Copyright (C) over their respective
* portions of code (see license.txt for details):
*
* [Original Author (maintained through version 2.0-0.3.1):]
* 1998-2001 [alex] Alexander Kuznetsov <alexan@users.sourceforge.net>
* [Maintainers (after version 2.0-0.3.1):]
* 2001-2002 [maz] Marek Isalski <kinterbasdb@maz.nu>
* 2002-2007 [dsr] David Rushby <woodsplitter@rocketmail.com>
* [Contributors:]
* 2001 [eac] Evgeny A. Cherkashin <eugeneai@icc.ru>
* 2001-2002 [janez] Janez Jere <janez.jere@void.si> */
/* Throughout these declarations, note the use of the 'volatile' modifier to
* ensure that an altered variable's value is written back to main memory
* instead of mistakenly written only to one CPU's cache on a
* multiprocessor. */
#ifndef _KIEVENTS_H
#define _KIEVENTS_H
#include "_kinterbasdb.h"
#ifdef ENABLE_DB_EVENT_SUPPORT
#include "_kinterbasdb_exception_functions_without_python.h"
#include "_kisupport.h"
#include "_kisupport_threadsafe_fifo_queue.h"
#ifdef FIREBIRD_2_0_OR_LATER
#define EVENT_CALLBACK_FUNCTION ISC_EVENT_CALLBACK
#else
#define EVENT_CALLBACK_FUNCTION isc_callback
#endif
#define DV_VOID(void_ptr) DEVOLATILE(void *, void_ptr)
#define DV_STR(char_ptr) DEVOLATILE(char *, char_ptr)
#define DV_STR_PTR(char_ptr_ptr) DEVOLATILE(char **, char_ptr_ptr)
#define DV_Q(q) DEVOLATILE(ThreadSafeFIFOQueue *, q)
#define DV_EOTC(eotc) DEVOLATILE(EventOpThreadContext *, eotc)
#define DV_ERB(erb) DEVOLATILE(EventRequestBlock *, erb)
#define DV_CALCTX(callctx) DEVOLATILE(EventCallbackThreadContext *, callctx)
#define DV_ISC_STATUS(ISC_STATUS_) DEVOLATILE(ISC_STATUS, ISC_STATUS_)
#define DV_STATVEC(ISC_STATUS_ptr) DEVOLATILE(ISC_STATUS *, ISC_STATUS_ptr)
#define DV_DB_HANDLE_PTR(isc_db_handle_ptr) DEVOLATILE(isc_db_handle *, isc_db_handle_ptr)
#define DV_LONG_PTR(long_ptr) DEVOLATILE(long *, long_ptr)
#define DV_ISC_LONG_PTR(ISC_LONG_ptr) DEVOLATILE(ISC_LONG *, ISC_LONG_ptr)
#define DV_THREADID_PTR(thread_id_ptr) \
DEVOLATILE(PlatformThreadIdType *, thread_id_ptr)
/******************** HARD-CODED LIMITS:BEGIN ********************/
/* EVENT_BLOCK_SIZE is a limitation imposed by the DB client library, but
* kinterbasdb transparently eliminates it from the Python programmer's
* perspective. */
#define EVENT_BLOCK_SIZE 15
/******************** HARD-CODED LIMITS:END ********************/
/******************** MODULE TYPE DEFINITIONS:BEGIN ********************/
typedef enum {
ECALL_UNINITIALIZED = 1,
ECALL_DUMMY = 2,
ECALL_NORMAL = 3,
ECALL_DEAD = 4
} EventCallbackThreadState;
typedef struct {
PlatformMutexType lock;
volatile EventCallbackThreadState state;
volatile int block_number;
volatile PlatformThreadIdType op_thread_id;
/* op_q is a pointer to the operation request queue in the
* EventOpThreadContext. The queue's memory and member cleanup is managed
* by the EventOpThreadContext, not by EventCallbackThreadContext. */
volatile ThreadSafeFIFOQueue *op_q;
} EventCallbackThreadContext;
typedef struct {
#define NULL_EVENT_ID -1
volatile ISC_LONG event_id;
volatile char *req_buf;
volatile short req_buf_len;
/* The EventOpThread never accesses the members of this structure. The only
* threads that do so are the thread that creates/destroys the
* EventConduit, as well as (obviously) the respective EventCallbackThreads
* themselves. */
volatile EventCallbackThreadContext callback_ctx;
} EventRequestBlock;
typedef enum {
/* Requested by the thread that creates the event conduit: */
OP_CONNECT,
OP_REGISTER,
OP_DIE,
/* Requested by the event callback (which runs for all except its final
* iteration in a thread started by the database client library).
* During this operation, the EventOpThread:
* 1) Calculates and posts to the EventFiredQueue an EventFiredNode that
* contains the counts of the events that the EventOpNode indicates
* occurred. The EventConduit.wait method is where EventFiredNodes are
* consumed from the EventFiredQueue.
* 2) Re-registers the event callback to be called by the database client
* library the next time the server detects the occurence of any of the
* events that were specified by the client programmer in the
* event_names parameter to the EventConduit constructor. */
OP_RECORD_AND_REREGISTER,
/* Sent by the event callback thread in case of error: */
OP_CALLBACK_ERROR
} EventOpThreadOpCode;
typedef enum {
OPTHREADSTATE_NONE = 1,
OPTHREADSTATE_WAITING_FOR_CONNECTION_REQUEST = 2,
OPTHREADSTATE_WAITING_FOR_REGISTER_REQUEST = 3,
OPTHREADSTATE_READY = 4,
OPTHREADSTATE_FATALLY_WOUNDED = 5,
OPTHREADSTATE_DEAD = 6
} EventOpThreadState;
typedef struct {
PlatformMutexType lock;
volatile EventOpThreadState state;
volatile PlatformThreadIdType event_op_thread_id;
volatile int n_event_blocks;
/* error_info is used to transfer error information from one piece of code
* that uses the EventOpThreadContext to another. This member is always
* manipulated by the EventOpThread, except during its initialization and
* (potentially) its destruction. */
NonPythonSQLErrorInfo *error_info;
/* Members to support the database API calls: */
volatile EventRequestBlock *er_blocks;
volatile isc_db_handle db_handle;
volatile ISC_STATUS sv[STATUS_VECTOR_SIZE];
/* Members used to communicate with other threads: */
/* Threads that want the EventOpThread to do something post EventOpNodes
* bearing an EventOpThreadOpCode to this queue: */
ThreadSafeFIFOQueue op_q;
/* The thread(s) that make "administrative requests" of the EventOpThread
* wait for acknowledgement on this queue; the EventOpThread provides those
* acknowledgements in the form of AdminResponseNodes. Although it's
* possible for different threads to wait on this queue, they won't do it
* simultaneously, so there's no risk of a waiting thread receiving
* acknowledgement of an operation that another thread requested. */
ThreadSafeFIFOQueue admin_response_q;
/* event_q is a pointer to the EventConduit's event queue. The EventOpThread
* posts EventFiredNodes to this queue in reaction to EventOpNodes that it
* receives via op_q from the EventCallbackThread. The EventConduit.wait
* method is where EventFiredNodes are consumed from event_q.*/
volatile ThreadSafeFIFOQueue *event_q;
} EventOpThreadContext;
typedef enum {
CONDUIT_STATE_CREATED,
CONDUIT_STATE_OPEN,
CONDUIT_STATE_CLOSED
} EventConduitState;
typedef struct {
PyObject_HEAD /* Python API - infrastructural macro. */
/* Since EventConduits are Python objects, access to them is implicitly
* serialized by the GIL. Destructive operations on those members of an
* EventConduit that might be in use in multiple threads are not performed
* until the destructor. Therefore, no explicit lock is necessary. */
EventConduitState state;
PyObject *py_event_names;
int n_event_names;
int n_event_blocks;
PyObject *py_event_counts_dict_template;
ThreadSafeFIFOQueue event_q;
/* The only time a thread other than the EventOpThread accesses the members
* of op_thread_context is during the creation or destruction of the
* EventConduit. */
EventOpThreadContext op_thread_context;
/* This thread reference is used during EventConduit destruction to ensure
* that the EventOpThread has actually exited before the thread that's
* destroying the EventOpThread's context pulls the rug out from under it. */
PlatformThreadRefType op_thread_ref;
} EventConduit;
/* Node types used as elements of the various ThreadSafeFIFOQueues: */
typedef struct {
volatile EventOpThreadOpCode op_code;
#define NO_TAG -1
volatile int tag;
volatile void *payload; /* Might be NULL. */
} EventOpNode;
typedef struct {
volatile EventOpThreadOpCode op_code;
volatile long status;
volatile ISC_STATUS sql_error_code;
volatile char *message; /* Might be NULL. */
} AdminResponseNode;
#ifdef FIREBIRD_2_0_OR_LATER
#define UPDATED_BUF_SIGNEDNESS unsigned
#else
#define UPDATED_BUF_SIGNEDNESS
#endif
typedef struct {
volatile int block_number;
UPDATED_BUF_SIGNEDNESS char *updated_buf;
} EventCallbackOutputNode;
typedef struct {
volatile int block_number;
volatile long counts[EVENT_BLOCK_SIZE];
#define COUNTS_BUF_SIZE (sizeof(long) * EVENT_BLOCK_SIZE)
} EventFiredNode;
typedef struct {
volatile char *dsn;
volatile short dsn_len;
volatile char *dpb;
volatile short dpb_len;
volatile short dialect;
} ConnParamsNode;
/******************** MODULE TYPE DEFINITIONS:END ********************/
#endif /* ENABLE_DB_EVENT_SUPPORT */
#endif /* if not def _KIEVENTS_H */
|