8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:03:03 +01:00
firebird-mirror/src/jrd/vmsthread.cpp
eku 4eaf8c0914 Autoconf cleanup:
o since the define 'VAX' was only used to tell that the byte order is
   LITTLE_ENDIAN (it have nothing else to do with the VAX computer family)
   it can safely replaced with '!WORDS_BIGENDIAN'.
 o check if pointers are 64 bit
 o replaced HAS_64BIT_POINTERS with 'SIZEOF_VOID_P == 8'
2002-09-17 05:58:40 +00:00

317 lines
7.6 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: vmsthread.c
* DESCRIPTION: VMS Thread 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 <pthread.h>
#define TCB_STACKSIZE 65536
/* Thread control block */
typedef struct tcb {
struct tcb *tcb_next;
int (*tcb_routine) ();
long tcb_routine_arg;
int (*tcb_callback) ();
long tcb_callback_arg;
pthread_cond_t tcb_cond_wait;
pthread_t tcb_tid;
char tcb_flags;
} *TCB;
#define TCB_active 1 /* Thread control block is active. */
/* Mutex for synchronizing condition variables. */
static pthread_once_t init_block = pthread_once_init;
static pthread_attr_t thread_attributes;
static pthread_mutex_t threads_mutex;
static TCB threads = 0;
static void thread_init();
static void thread_starter();
THREAD_ast_active()
{
/**************************************
*
* T H R E A D _ a s t _ a c t i v e
*
**************************************
*
* Functional description
* Called as completion ast for any asynchronous
* system service.
*
**************************************/
return FALSE;
}
THREAD_wakeup()
{
/**************************************
*
* T H R E A D _ w a k e u p
*
**************************************
*
* Functional description
* Called as completion ast for any asynchronous
* system service.
*
**************************************/
TCB tcb;
int (*callback) ();
if (pthread_once(&init_block, thread_init))
gds__put_error("THREAD_completion: pthread_once error!\n");
if (pthread_mutex_lock(&threads_mutex))
gds__put_error("THREAD_completion: pthread_mutex_lock error!\n");
for (tcb = threads; tcb; tcb = tcb->tcb_next) {
if (tcb->tcb_flags & TCB_active &&
(callback = tcb->tcb_callback) &&
(*callback) (tcb->tcb_callback_arg))
if (pthread_cond_signal(&tcb->tcb_cond_wait))
gds__put_error
("THREAD_completion: pthread_cond_signal error!\n");
}
if (pthread_mutex_unlock(&threads_mutex))
gds__put_error("THREAD_completion: pthread_mutex_unlock error!\n");
}
THREAD_completion_ast()
{
/**************************************
*
* T H R E A D _ c o m p l e t i o n _ a s t
*
**************************************
*
* Functional description
* Called as completion ast for any asynchronous
* system service.
*
**************************************/
TCB tcb;
int (*callback) ();
for (tcb = threads; tcb; tcb = tcb->tcb_next) {
if (tcb->tcb_flags & TCB_active &&
(callback = tcb->tcb_callback) &&
(*callback) (tcb->tcb_callback_arg))
if (pthread_cond_signal_int_np(&tcb->tcb_cond_wait))
gds__put_error
("THREAD_completion_ast: pthread_cond_signal_int error!\n");
}
}
THREAD_start(routine, arg, priority, flags)
int (*routine) ();
long arg;
int priority;
int flags;
{
/**************************************
*
* T H R E A D _ s t a r t
*
**************************************
*
* Functional description
* Start a new thread. Return 0 if successful,
* status if not.
*
**************************************/
TCB tcb, prior;
/* Make sure thread subsystem has been initialized. */
if (pthread_once(&init_block, thread_init))
gds__put_error("THREAD_start: pthread_once error!\n");
if (pthread_mutex_lock(&threads_mutex))
gds__put_error("THREAD_start: pthread_mutex_lock error!\n");
prior = threads;
for (tcb = threads; tcb; tcb = tcb->tcb_next) {
if (!(tcb->tcb_flags & TCB_active))
break;
prior = tcb;
}
if (!tcb) {
tcb = (TCB) gds__alloc((long) sizeof(struct tcb));
memset(tcb, 0, sizeof(struct tcb));
if (pthread_cond_init(&tcb->tcb_cond_wait, pthread_condattr_default))
gds__put_error("THREAD_start: pthread_cond_init error!\n");
prior->tcb_next = tcb;
}
tcb->tcb_callback = 0;
tcb->tcb_routine = routine;
tcb->tcb_routine_arg = arg;
tcb->tcb_flags |= TCB_active;
if (pthread_mutex_unlock(&threads_mutex))
gds__put_error("THREAD_start: pthread_mutex_unlock error!\n");
if (pthread_create(&tcb->tcb_tid, thread_attributes,
(pthread_startroutine_t) thread_starter, tcb))
gds__put_error("THREAD_start: pthread_create error!\n");
return 0;
}
THREAD_wait(callback, arg)
int (*callback) ();
long arg;
{
/**************************************
*
* T H R E A D _ w a i t
*
**************************************
*
* Functional description
* Wait on thread condition variable.
*
**************************************/
pthread_t self;
TCB tcb;
if (pthread_once(&init_block, thread_init))
gds__put_error("THREAD_wait: pthread_once() error!\n");
self = pthread_self();
if (pthread_mutex_lock(&threads_mutex))
gds__put_error("THREAD_wait: pthread_mutex_lock() error!\n");
/* Find this thread's control block. */
for (tcb = threads; tcb; tcb = tcb->tcb_next)
if (pthread_equal(tcb->tcb_tid, self))
break;
if (!tcb)
gds__put_error("THREAD_wait: can't find thread control block.\n");
/* Catch-all thread completion AST will signal condition
variables after testing callbacks. */
tcb->tcb_callback_arg = arg;
tcb->tcb_callback = callback;
/* Wait for callback predicate to evaluate to TRUE
before returning. */
while (!(*callback) (arg))
if (pthread_cond_wait(&tcb->tcb_cond_wait, &threads_mutex))
gds__put_error("THREAD_wait: pthread_cond_wait error!\n");
tcb->tcb_callback = 0;
if (pthread_mutex_unlock(&threads_mutex))
gds__put_error("THREAD_wait: pthread_mutex_unlock error!\n");
}
static void thread_init()
{
/**************************************
*
* t h r e a d _ i n i t
*
**************************************
*
* Functional description
* Initialize global mutex and thread characteristics
* once and for all.
*
**************************************/
TCB tcb;
if (pthread_mutex_init(&threads_mutex, pthread_mutexattr_default))
gds__put_error("thread_init: pthread_mutex_init error!\n");
if (pthread_attr_create(&thread_attributes))
gds__put_error("thread_init: pthread_attr_create error!\n");
if (pthread_attr_setstacksize(&thread_attributes, TCB_STACKSIZE))
gds__put_error("thread_init: pthread_attr_setstacksize error!\n");
tcb = (TCB) gds__alloc((long) sizeof(struct tcb));
memset(tcb, 0, sizeof(struct tcb));
if (pthread_cond_init(&tcb->tcb_cond_wait, pthread_condattr_default))
gds__put_error("thread_init: pthread_cond_init error!\n");
tcb->tcb_tid = pthread_self();
tcb->tcb_flags |= TCB_active;
threads = tcb;
}
static void thread_starter(tcb)
TCB tcb;
{
/**************************************
*
* t h r e a d _ s t a r t e r
*
**************************************
*
* Functional description
* Wrapper to start a thread. Releases
* thread control block on exit.
*
**************************************/
tcb->tcb_tid = pthread_self();
/* Reclaim thread storage on exit. */
/*
if (pthread_detach (&tcb->tcb_tid))
gds__put_error ("thread_starter: pthread_detach error!\n");
*/
(*tcb->tcb_routine) (tcb->tcb_routine_arg);
tcb->tcb_callback = 0;
tcb->tcb_flags &= ~TCB_active;
if (pthread_detach(&tcb->tcb_tid))
gds__put_error("thread_starter: pthread_detach error!\n");
}