mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-26 08:03:03 +01:00
944 lines
23 KiB
C++
944 lines
23 KiB
C++
/*
|
|
* PROGRAM: JRD Access Method
|
|
* MODULE: vmsevent.c
|
|
* DESCRIPTION: Event Manager
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../jrd/common.h"
|
|
#include "gen/codes.h"
|
|
#include "../jrd/thd.h"
|
|
#include "../jrd/gdsassert.h"
|
|
#include "../jrd/event_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../jrd/isc_proto.h"
|
|
#include "../jrd/sch_proto.h"
|
|
|
|
#include descrip
|
|
#include lckdef
|
|
#include ssdef
|
|
|
|
#define MAX_EVENT_BUFFER 65500
|
|
|
|
|
|
/* Dummy global section header */
|
|
|
|
typedef struct evh {
|
|
SLONG evh_length;
|
|
} *EVH;
|
|
|
|
/* Session block */
|
|
|
|
typedef struct ses {
|
|
struct ses *ses_next; /* Next active session */
|
|
struct vms_req *ses_requests; /* Outstanding requests in session */
|
|
struct rint *ses_interests; /* Historical interests */
|
|
} *SES;
|
|
|
|
/* Event block */
|
|
|
|
typedef struct evnt {
|
|
struct evnt *evnt_next; /* Next lock */
|
|
struct evnt *evnt_parent; /* Parent lock, if any */
|
|
struct evnt *evnt_offspring; /* Offspring locks, if any */
|
|
struct rint *evnt_interests; /* Interests in event */
|
|
struct lksb evnt_lksb; /* Event lock status block */
|
|
SLONG evnt_count; /* Last know lock count */
|
|
USHORT evnt_length; /* Length of event string */
|
|
TEXT evnt_name[1];
|
|
} *EVNT;
|
|
|
|
/* Request block */
|
|
|
|
typedef struct vms_req {
|
|
struct vms_req *req_next; /* Next request in session */
|
|
struct ses *req_session; /* Parent session */
|
|
struct rint *req_interests; /* Request interests */
|
|
int (*req_ast) (); /* Associated AST (zero is fired) */
|
|
void *req_ast_arg; /* Argument for ast */
|
|
SLONG req_request_id; /* Request id */
|
|
} *VMS_REQ;
|
|
|
|
/* Request interest block */
|
|
|
|
typedef struct rint {
|
|
VMS_REQ rint_request; /* Parent request block */
|
|
EVNT rint_event; /* Parent event block */
|
|
struct rint *rint_req_interests; /* Other interests of request */
|
|
struct rint *rint_evnt_interests; /* Other interests for event */
|
|
SLONG rint_count; /* Threadhold count */
|
|
} *RINT;
|
|
|
|
|
|
static SES sessions;
|
|
static EVNT parent_events;
|
|
static SLONG request_id;
|
|
static POKE pokes;
|
|
static USHORT thread_started, delivery_flag;
|
|
|
|
static UCHAR *alloc(USHORT);
|
|
static void blocking_ast(EVNT);
|
|
static void delete_event(EVNT);
|
|
static void delete_request(VMS_REQ);
|
|
static void deliver(EVNT);
|
|
static void deliver_request(VMS_REQ);
|
|
static void delivery_thread(void);
|
|
static int delivery_wait(void);
|
|
static STATUS error(STATUS *, TEXT *, STATUS);
|
|
static EVNT find_event(USHORT, TEXT *, EVNT);
|
|
static void free(SCHAR *);
|
|
static RINT historical_interest(SES, EVNT);
|
|
static EVNT make_event(USHORT, TEXT *, EVNT);
|
|
static void poke_ast(POKE);
|
|
static BOOLEAN request_completed(VMS_REQ);
|
|
static int return_ok(STATUS *);
|
|
|
|
|
|
int EVENT_cancel(SLONG request_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ c a n c e l
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Cancel an outstanding event.
|
|
*
|
|
**************************************/
|
|
VMS_REQ request;
|
|
SES session;
|
|
|
|
for (session = sessions; session; session = session->ses_next)
|
|
for (request = session->ses_requests; request;
|
|
request =
|
|
request->req_next) if (request->req_request_id == request_id) {
|
|
delete_request(request);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
SLONG EVENT_create_session(STATUS status_vector)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ c r e a t e _ s e s s i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Create session.
|
|
*
|
|
**************************************/
|
|
SES session;
|
|
SLONG id;
|
|
|
|
session = (SES) alloc(sizeof(struct ses));
|
|
if (!session) {
|
|
assert(FALSE); /* No error handling */
|
|
return 0L;
|
|
}
|
|
session->ses_next = sessions;
|
|
sessions = session;
|
|
|
|
id = (SLONG) session;
|
|
|
|
return id;
|
|
}
|
|
|
|
|
|
void EVENT_delete_session(SLONG session_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ d e l e t e _ s e s s i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Delete a session.
|
|
*
|
|
**************************************/
|
|
SES session;
|
|
SES *ptr;
|
|
VMS_REQ request;
|
|
EVNT event;
|
|
RINT interest, *int_ptr;
|
|
|
|
session = (SES) session_id;
|
|
|
|
/* Delete all requests */
|
|
|
|
while (session->ses_requests)
|
|
delete_request(session->ses_requests);
|
|
|
|
/* Delete any historical interests */
|
|
|
|
while (interest = session->ses_interests) {
|
|
session->ses_interests = interest->rint_req_interests;
|
|
event = interest->rint_event;
|
|
for (int_ptr = &event->evnt_interests; *int_ptr;
|
|
int_ptr =
|
|
&(*int_ptr)->rint_req_interests) if (*int_ptr == interest) {
|
|
*int_ptr = interest->rint_req_interests;
|
|
break;
|
|
}
|
|
free(interest);
|
|
if (!event->evnt_interests)
|
|
delete_event(event);
|
|
}
|
|
|
|
/* Delete from global list of sessions */
|
|
|
|
for (ptr = &sessions; *ptr; ptr = &(*ptr)->ses_next)
|
|
if (*ptr == session) {
|
|
*ptr = session->ses_next;
|
|
break;
|
|
}
|
|
|
|
free(session);
|
|
}
|
|
|
|
|
|
EVH EVENT_init(STATUS * status_vector, USHORT server_flag)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ i n i t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Initialize for access to shared global region. If "server_flag" is true,
|
|
* create region if it doesn't exist. Return address of header if region
|
|
* exits, otherwise return NULL.
|
|
*
|
|
**************************************/
|
|
|
|
return_ok(status_vector);
|
|
|
|
return (EVH) TRUE;
|
|
}
|
|
|
|
|
|
int EVENT_post(
|
|
STATUS * status_vector,
|
|
USHORT major_length,
|
|
TEXT * major, USHORT minor_length, TEXT * minor, USHORT count)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ p o s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Post an event.
|
|
*
|
|
**************************************/
|
|
LKSB lksb;
|
|
POKE poke;
|
|
int status;
|
|
struct dsc$descriptor desc;
|
|
|
|
/* Get parent lock. If it isn't held, we will get an invalid lock block */
|
|
|
|
ISC_make_desc(major, &desc, major_length);
|
|
|
|
status = sys$enq(0, /* event flag */
|
|
LCK$K_CRMODE, /* lock mode */
|
|
&lksb, /* Lock status block */
|
|
LCK$M_SYSTEM, /* flags */
|
|
&desc, /* resource name */
|
|
0, /* parent id */
|
|
0, /* ast address */
|
|
0, /* ast argument */
|
|
0, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
|
|
if (!(status & 1))
|
|
return error(status_vector, "sys$enqw", status);
|
|
|
|
/* Find a free poke block to use */
|
|
|
|
for (poke = pokes; poke; poke = poke->poke_next)
|
|
if (!poke->poke_use_count)
|
|
break;
|
|
|
|
if (!poke) {
|
|
poke = (POKE) alloc(sizeof(struct poke));
|
|
/* FREE: unknown */
|
|
if (!poke) /* NOMEM: */
|
|
return error(status_vector, "gds__alloc", 0);
|
|
poke->poke_next = pokes;
|
|
pokes = poke;
|
|
}
|
|
|
|
++poke->poke_use_count;
|
|
|
|
/* If the parent lock looks kosher, try the next level down */
|
|
|
|
poke->poke_value = count;
|
|
poke->poke_parent_id = lksb.lksb_lock_id;
|
|
ISC_make_desc(minor, &desc, minor_length);
|
|
|
|
status = sys$enq(0, /* event flag */
|
|
LCK$K_PWMODE, /* lock mode */
|
|
&poke->poke_lksb, /* Lock status block */
|
|
LCK$M_SYSTEM | LCK$M_VALBLK, /* flags */
|
|
&desc, /* resource name */
|
|
poke->poke_parent_id, /* parent id */
|
|
poke_ast, /* ast address */
|
|
poke, /* ast argument */
|
|
0, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
|
|
if (!(status & 1))
|
|
return error(status_vector, "sys$enqw", status);
|
|
|
|
return return_ok(status_vector);
|
|
}
|
|
|
|
|
|
SLONG EVENT_que(STATUS * status_vector,
|
|
SLONG session_id,
|
|
USHORT string_length,
|
|
TEXT * string,
|
|
USHORT events_length,
|
|
UCHAR * events, void (*ast_routine) (), void *ast_arg)
|
|
{
|
|
/**************************************
|
|
*
|
|
* E V E N T _ q u e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Que an event.
|
|
*
|
|
**************************************/
|
|
SES session;
|
|
UCHAR *p, *end, *find_end;
|
|
USHORT count, flag, len;
|
|
VMS_REQ request, next;
|
|
EVNT event, parent;
|
|
RINT interest, *ptr, *ptr2;
|
|
SLONG id;
|
|
|
|
session = (SES) session_id;
|
|
|
|
if (!thread_started) {
|
|
thread_started = TRUE;
|
|
gds__thread_start(delivery_thread, 0, THREAD_high, THREAD_ast);
|
|
}
|
|
|
|
/* Cleanup any residual stuff */
|
|
|
|
for (next = session->ses_requests; next;)
|
|
if (next->req_ast)
|
|
next = next->req_next;
|
|
else {
|
|
request = next;
|
|
next = next->req_next;
|
|
delete_request(request);
|
|
}
|
|
|
|
/* Allocate request block */
|
|
|
|
request = (VMS_REQ) alloc(sizeof(struct vms_req));
|
|
/* FREE: unknown */
|
|
if (!request) /* NOMEM: */
|
|
return error(status_vector, "gds__alloc", 0);
|
|
|
|
request->req_session = session;
|
|
request->req_next = session->ses_requests;
|
|
session->ses_requests = request;
|
|
|
|
request->req_ast = ast_routine;
|
|
request->req_ast_arg = ast_arg;
|
|
request->req_request_id = id = ++request_id;
|
|
|
|
/* Find parent block */
|
|
|
|
if (!(parent = find_event(string_length, string, 0)))
|
|
parent = make_event(string_length, string, 0);
|
|
|
|
/* Process event block */
|
|
|
|
ptr = &request->req_interests;
|
|
p = events + 1;
|
|
end = events + events_length;
|
|
flag = FALSE;
|
|
|
|
while (p < end) {
|
|
count = *p++;
|
|
|
|
/* The data in the event block may have trailing blanks. Strip them off. */
|
|
|
|
for (find_end = p + count; --find_end >= p && *find_end == ' ';);
|
|
len = find_end - p + 1;
|
|
if (!(event = find_event(len, p, parent)))
|
|
event = make_event(len, p, parent);
|
|
p += count;
|
|
if (interest = historical_interest(session, event)) {
|
|
for (ptr2 = &session->ses_interests; *ptr2;
|
|
ptr2 = &(*ptr2)->rint_req_interests) if (*ptr2 == interest) {
|
|
*ptr2 = interest->rint_req_interests;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
interest = (RINT) alloc(sizeof(struct vms_req));
|
|
/* FREE: unknown */
|
|
if (!interest) /* NOMEM: */
|
|
return error(status_vector, "gds__alloc", 0);
|
|
interest->rint_evnt_interests = event->evnt_interests;
|
|
event->evnt_interests = interest;
|
|
interest->rint_event = event;
|
|
}
|
|
*ptr = interest;
|
|
ptr = &interest->rint_req_interests;
|
|
interest->rint_request = request;
|
|
interest->rint_count = gds__vax_integer(p, 4);
|
|
p += 4;
|
|
if (interest->rint_count <= event->evnt_count)
|
|
flag = TRUE;
|
|
}
|
|
|
|
if (flag)
|
|
sys$dclast(blocking_ast, event, 0);
|
|
|
|
return_ok(status_vector);
|
|
|
|
return id;
|
|
}
|
|
|
|
|
|
static UCHAR *alloc(USHORT size)
|
|
{
|
|
/**************************************
|
|
*
|
|
* a l l o c
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Allocate and zero some memory.
|
|
*
|
|
**************************************/
|
|
UCHAR *p, *block;
|
|
|
|
p = block = gds__alloc((SLONG) size);
|
|
/* FREE: handled by caller */
|
|
/* NOMEM: handled by caller */
|
|
if (!block)
|
|
return block;
|
|
|
|
do
|
|
*p++ = 0;
|
|
while (--size);
|
|
|
|
return block;
|
|
}
|
|
|
|
|
|
static void blocking_ast(EVNT event)
|
|
{
|
|
/**************************************
|
|
*
|
|
* b l o c k i n g _ a s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Somebody else is trying to post a lock.
|
|
*
|
|
**************************************/
|
|
LKSB *lksb;
|
|
int status;
|
|
|
|
lksb = &event->evnt_lksb;
|
|
|
|
/* Initially down grade the lock to let the other guy complete */
|
|
|
|
status = sys$enqw(0, /* event flag */
|
|
LCK$K_NLMODE, /* lock mode */
|
|
lksb, /* Lock status block */
|
|
LCK$M_CONVERT, /* flags */
|
|
0, /* resource name */
|
|
0, /* parent id */
|
|
0, /* ast address */
|
|
0, /* ast argument */
|
|
0, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
|
|
/* Now try to upgrade lock */
|
|
|
|
status = sys$enq(0, /* event flag */
|
|
LCK$K_PRMODE, /* lock mode */
|
|
lksb, /* Lock status block */
|
|
LCK$M_CONVERT | LCK$M_VALBLK, /* flags */
|
|
0, /* resource name */
|
|
0, /* parent id */
|
|
deliver, /* ast address */
|
|
event, /* ast argument */
|
|
blocking_ast, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
}
|
|
|
|
|
|
static void delete_event(EVNT event)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l e t e _ e v e n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Delete an unused and unloved event.
|
|
*
|
|
**************************************/
|
|
EVNT *ptr, parent;
|
|
int status;
|
|
|
|
/* Delete associated lock */
|
|
|
|
status = sys$deq(event->evnt_lksb.lksb_lock_id, 0, 0, 0);
|
|
|
|
if (parent = event->evnt_parent)
|
|
ptr = &parent->evnt_offspring;
|
|
else
|
|
ptr = &parent_events;
|
|
|
|
for (; *ptr; ptr = &(*ptr)->evnt_next)
|
|
if (*ptr == event) {
|
|
*ptr = event->evnt_next;
|
|
break;
|
|
}
|
|
|
|
free(event);
|
|
|
|
if (parent && !parent->evnt_offspring)
|
|
delete_event(parent);
|
|
}
|
|
|
|
|
|
static void delete_request(VMS_REQ request)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l e t e _ r e q u e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Release an unwanted and unloved request.
|
|
*
|
|
**************************************/
|
|
SES session;
|
|
RINT *ptr, interest;
|
|
EVNT event;
|
|
VMS_REQ *req_ptr;
|
|
|
|
session = request->req_session;
|
|
|
|
while (interest = request->req_interests) {
|
|
request->req_interests = interest->rint_req_interests;
|
|
if (historical_interest(session, interest->rint_event)) {
|
|
event = interest->rint_event;
|
|
for (ptr = &event->evnt_interests; *ptr;
|
|
ptr = &(*ptr)->rint_evnt_interests) if (*ptr == interest) {
|
|
*ptr = interest->rint_evnt_interests;
|
|
break;
|
|
}
|
|
free(interest);
|
|
}
|
|
else {
|
|
interest->rint_req_interests = session->ses_interests;
|
|
session->ses_interests = interest;
|
|
interest->rint_request = NULL;
|
|
}
|
|
}
|
|
|
|
for (req_ptr = &session->ses_requests; *req_ptr;
|
|
req_ptr = &(*req_ptr)->req_next) if (*req_ptr == request) {
|
|
*req_ptr = request->req_next;
|
|
break;
|
|
}
|
|
|
|
free(request);
|
|
}
|
|
|
|
|
|
static void deliver(EVNT event)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l i v e r
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* We've been poked -- deliver any satisfying requests.
|
|
*
|
|
**************************************/
|
|
RINT interest;
|
|
VMS_REQ request;
|
|
SES session;
|
|
USHORT flag;
|
|
|
|
event->evnt_count = event->evnt_lksb.lksb_value[0];
|
|
|
|
for (interest = event->evnt_interests; interest;
|
|
interest = interest->rint_evnt_interests) if (request =
|
|
interest->rint_request)
|
|
if (request->req_ast && request_completed(request))
|
|
delivery_flag = TRUE;
|
|
|
|
gds__completion_ast();
|
|
}
|
|
|
|
|
|
static void deliver_request(VMS_REQ request)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l i v e r _ r e q u e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Request has been satisfied, send updated event block to user, then
|
|
* Clean up request.
|
|
*
|
|
**************************************/
|
|
int (*ast) ();
|
|
void *arg;
|
|
SLONG count;
|
|
RINT interest;
|
|
EVNT event;
|
|
UCHAR buffer[512], *p, *event_buffer, *end;
|
|
|
|
ast = request->req_ast;
|
|
arg = request->req_ast_arg;
|
|
p = event_buffer = buffer;
|
|
end = buffer + sizeof(buffer);
|
|
*p++ = 1;
|
|
|
|
/* Loop thru interest block picking up event name, counts, and unlinking
|
|
stuff */
|
|
|
|
for (interest = request->req_interests; interest;
|
|
interest = interest->rint_req_interests) {
|
|
event = interest->rint_event;
|
|
if (end < p + event->evnt_length + 5) {
|
|
UCHAR *new_buffer;
|
|
/* Running out of space - allocate some more and copy it over */
|
|
assert(event_buffer == buffer); /* we're in this block only once */
|
|
new_buffer = gds__alloc((SLONG) MAX_EVENT_BUFFER);
|
|
/* FREE: at procedure return */
|
|
if (!new_buffer) { /* NOMEM: */
|
|
gds__log("failed to post all events");
|
|
break; /* exit loop and send what we have */
|
|
}
|
|
event_buffer = new_buffer;
|
|
memcpy(event_buffer, buffer, p - buffer);
|
|
p = event_buffer + (p - buffer);
|
|
end = event_buffer + MAX_EVENT_BUFFER;
|
|
}
|
|
*p++ = event->evnt_length;
|
|
memcpy(p, event->evnt_name, event->evnt_length);
|
|
p += event->evnt_length;
|
|
count = event->evnt_count + 1;
|
|
*p++ = count;
|
|
*p++ = count >> 8;
|
|
*p++ = count >> 16;
|
|
*p++ = count >> 24;
|
|
}
|
|
|
|
(*ast) (arg, p - buffer, buffer);
|
|
if (event_buffer != buffer)
|
|
gds__free(event_buffer);
|
|
}
|
|
|
|
|
|
static void delivery_thread(void)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l i v e r y _ t h r e a d
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Look for events to deliver.
|
|
*
|
|
**************************************/
|
|
VMS_REQ request;
|
|
SES session;
|
|
|
|
for (;;) {
|
|
delivery_flag = FALSE;
|
|
for (session = sessions; session; session = session->ses_next)
|
|
for (request = session->ses_requests; request;
|
|
request = request->req_next)
|
|
if (request->req_ast && request_completed(request)) {
|
|
deliver_request(request);
|
|
request->req_ast = NULL;
|
|
}
|
|
gds__thread_wait(delivery_wait, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static int delivery_wait(void)
|
|
{
|
|
/**************************************
|
|
*
|
|
* d e l i v e r y _ w a i t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* See if the deliver thread should wake up.
|
|
*
|
|
**************************************/
|
|
|
|
return delivery_flag;
|
|
}
|
|
|
|
|
|
static STATUS error(STATUS * status_vector;
|
|
TEXT * string;
|
|
STATUS status; {
|
|
/**************************************
|
|
*
|
|
* e r r o r
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Things suck.
|
|
*
|
|
**************************************/
|
|
|
|
*status_vector++ = gds_arg_gds;
|
|
*status_vector++ = gds__sys_request;
|
|
*status_vector++ = gds_arg_string;
|
|
*status_vector++ = (STATUS) string;
|
|
*status_vector++ = gds_arg_vms;
|
|
*status_vector++ = status; *status_vector++ = gds_arg_end;
|
|
return gds__sys_request;
|
|
}
|
|
|
|
|
|
static EVNT find_event(USHORT length,
|
|
TEXT * string, EVNT parent) {
|
|
/**************************************
|
|
*
|
|
* f i n d _ e v e n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Lookup an event.
|
|
*
|
|
**************************************/
|
|
EVNT event;
|
|
event = (parent) ? parent->evnt_offspring : parent_events;
|
|
for (; event; event = event->evnt_next)
|
|
if (event->evnt_length == length &&
|
|
!strncmp(string, event->evnt_name, length))
|
|
return event; return NULL;}
|
|
|
|
|
|
static void free(SCHAR * block) {
|
|
/**************************************
|
|
*
|
|
* f r e e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Release a block.
|
|
*
|
|
**************************************/
|
|
|
|
gds__free(block);}
|
|
|
|
|
|
static RINT historical_interest(SES session, EVNT event) {
|
|
/**************************************
|
|
*
|
|
* h i s t o r i c a l _ i n t e r e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Find a historical interest, if any, of an event with a session.
|
|
*
|
|
**************************************/
|
|
RINT interest, *ptr;
|
|
for (ptr = &session->ses_interests; interest = *ptr;
|
|
ptr = &(*ptr)->rint_req_interests)
|
|
if (interest->rint_event == event)
|
|
return interest; return NULL;}
|
|
|
|
|
|
static EVNT make_event(USHORT length,
|
|
TEXT * string, EVNT parent) {
|
|
/**************************************
|
|
*
|
|
* m a k e _ e v e n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Allocate an link in an event.
|
|
*
|
|
**************************************/
|
|
EVNT event, *ptr;
|
|
LKSB * lksb;
|
|
SLONG parent_id;
|
|
int status;
|
|
struct dsc$descriptor desc;
|
|
event = (EVNT) alloc(sizeof(struct evnt) + length);
|
|
if (!event) return NULL; if (parent) {
|
|
ptr = &parent->evnt_offspring;
|
|
parent_id = parent->evnt_lksb.lksb_lock_id;}
|
|
else
|
|
{
|
|
ptr = &parent_events; parent_id = 0;}
|
|
|
|
event->evnt_next = *ptr;
|
|
*ptr = event;
|
|
event->evnt_parent = parent;
|
|
event->evnt_length = length;
|
|
strncpy(event->evnt_name, string, length);
|
|
/* Request VMS lock on event */
|
|
ISC_make_desc(string, &desc, length);
|
|
lksb = &event->evnt_lksb; status = sys$enqw(0, /* event flag */
|
|
LCK$K_PRMODE, /* lock mode */
|
|
lksb, /* Lock status block */
|
|
LCK$M_SYSTEM | LCK$M_VALBLK, /* flags */
|
|
&desc, /* resource name */
|
|
parent_id, /* parent id */
|
|
0, /* ast address */
|
|
event, /* ast argument */
|
|
blocking_ast, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
event->evnt_count = lksb->lksb_value[0];
|
|
/* If the lock block is invalid, clean it up immediately */
|
|
if ((status & 1) &&
|
|
event->evnt_lksb.lksb_status == SS$_VALNOTVALID) {
|
|
status = sys$enqw(0, /* event flag */
|
|
LCK$K_PWMODE, /* lock mode */
|
|
lksb, /* Lock status block */
|
|
LCK$M_CONVERT, /* flags */
|
|
0, /* resource name */
|
|
0, /* parent id */
|
|
0, /* ast address */
|
|
event, /* ast argument */
|
|
blocking_ast, /* blocking ast */
|
|
0, /* access mode */
|
|
0);
|
|
event->evnt_count = lksb->lksb_value[0] = 0;
|
|
status = sys$enqw(0, /* event flag */
|
|
LCK$K_PRMODE, /* lock mode */
|
|
lksb, /* Lock status block */
|
|
LCK$M_CONVERT | LCK$M_VALBLK, /* flags */
|
|
0, /* resource name */
|
|
0, /* parent id */
|
|
0, /* ast address */
|
|
event, /* ast argument */
|
|
blocking_ast, /* blocking ast */
|
|
0, /* access mode */
|
|
0);}
|
|
|
|
return event;}
|
|
|
|
|
|
static void poke_ast(POKE poke) {
|
|
/**************************************
|
|
*
|
|
* p o k e _ a s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Lock to poke event has completed. Update value block
|
|
* and deque the lock.
|
|
*
|
|
**************************************/
|
|
int status;
|
|
LKSB * lksb;
|
|
lksb = &poke->poke_lksb;
|
|
lksb->lksb_value[0] += poke->poke_value;
|
|
status =
|
|
sys$deq(lksb->lksb_lock_id, lksb->lksb_value, 0, 0);
|
|
status = sys$deq(poke->poke_parent_id, 0, 0, 0);
|
|
--poke->poke_use_count;}
|
|
|
|
|
|
static BOOLEAN request_completed(VMS_REQ request) {
|
|
/**************************************
|
|
*
|
|
* r e q u e s t _ c o m p l e t e d
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* See if request is completed.
|
|
*
|
|
**************************************/
|
|
RINT interest;
|
|
EVNT event;
|
|
for (interest = request->req_interests; interest;
|
|
interest = interest->rint_req_interests) {
|
|
event = interest->rint_event;
|
|
if (interest->rint_count <=
|
|
event->evnt_count) return TRUE;}
|
|
|
|
return FALSE;}
|
|
|
|
|
|
static int return_ok(STATUS * status_vector) {
|
|
/**************************************
|
|
*
|
|
* r e t u r n _ o k
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Everything is ducky -- return success.
|
|
*
|
|
**************************************/
|
|
|
|
*status_vector++ = gds_arg_gds;
|
|
*status_vector++ = 0;
|
|
*status_vector = gds_arg_end; return 0;}
|