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
|
/* KInterbasDB Python Package - Implementation of Event Waiting - UNIX
**
** Version 3.1
**
** 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-2004 [dsr] David Rushby <woodsplitter@rocketmail.com>
** [Contributors:]
** 2001 [eac] Evgeny A. Cherkashin <eugeneai@icc.ru>
** 2001-2002 [janez] Janez Jere <janez.jere@void.si>
*/
/* This source file is designed to be directly included in _kievents.c,
** without the involvement of a header file. */
/************************* PUBLIC FUNCTIONS:BEGIN ****************************/
PlatformEventType platform_create_event_object() {
/* We use kimem_plain_malloc here rather than kimem_main_malloc because it's
** not safe to assume the GIL is held. */
platform_event_struct *event = kimem_plain_malloc(sizeof(platform_event_struct));
if (event == NULL) {
goto PLATFORM_CREATE_EVENT_OBJECT_FAILED;
}
memset( (void *) event, '\0', sizeof(platform_event_struct));
if ( pthread_mutex_init(&event->mutex, NULL) != 0 ) {
goto PLATFORM_CREATE_EVENT_OBJECT_FAILED;
}
if ( pthread_cond_init(&event->cond, NULL) != 0 ) {
goto PLATFORM_CREATE_EVENT_OBJECT_FAILED;
}
return event;
PLATFORM_CREATE_EVENT_OBJECT_FAILED:
platform_free_event_object(event);
return NULL;
} /* platform_create_event_object */
void platform_free_event_object(PlatformEventType event) {
if (event == NULL) {
return;
}
if (&event->mutex != NULL) {
/* YYY: Perhaps should trylock+unlock before destroying? */
pthread_mutex_destroy(&event->mutex);
}
if (&event->cond != NULL) {
pthread_cond_destroy(&event->cond);
}
/* We use kimem_plain_free here rather than kimem_main_free because it's
** not safe to assume the GIL is held (even if there GIL were held *right
** here*, we'd still have to use kimem_plain_free because the memory was
** allocated with kimem_plain_malloc). */
kimem_plain_free(event);
} /* platform_free_event_object */
int event_queue_wait(EventQueue *queue, long timeout_millis) {
PlatformEventType event = queue->event;
int wait_result;
if ( pthread_mutex_lock(&event->mutex) != 0 ) {
return EVENT_ERROR;
}
if (timeout_millis == (long) WAIT_INFINITELY) {
wait_result = pthread_cond_wait(&event->cond, &event->mutex);
} else {
struct timeval now;
struct timespec abstime;
long rel_secs = timeout_millis / 1000;
long rel_millis = timeout_millis % 1000;
long rel_nanos = rel_millis * 1000000;
/* 1. use $now to get the absolute time
** 2. transfer the values from $now to $abstime
** 3. add the relative timeout to $abstime
** 4. call pthread_cond_timedwait, passing $abstime
*/
/* 1: */
gettimeofday(&now, NULL);
/* 2: */
abstime.tv_sec = now.tv_sec;
abstime.tv_nsec = now.tv_usec * 1000;
/* 3: */
abstime.tv_sec += rel_secs;
{
long total_nanos = abstime.tv_nsec + rel_nanos;
abstime.tv_sec += total_nanos / 1000000000;
abstime.tv_nsec = total_nanos % 1000000000;
}
/* 4: */
wait_result = pthread_cond_timedwait(&event->cond, &event->mutex, &abstime);
}
if ( pthread_mutex_unlock(&event->mutex) != 0 ) {
return EVENT_ERROR;
}
if (wait_result == ETIMEDOUT) {
return EVENT_TIMEOUT;
} else if (wait_result == 0) {
return EVENT_OK;
} else {
return EVENT_ERROR;
}
} /* event_queue_wait */
int event_queue_signal(EventQueue *queue) {
PlatformEventType event = queue->event;
int signal_result;
if ( pthread_mutex_lock(&event->mutex) != 0 ) {
return -1;
}
signal_result = pthread_cond_signal(&event->cond);
/* Notice the side-effective call to release the mutex in the conditional: */
if ( pthread_mutex_unlock(&event->mutex) != 0 || signal_result != 0 ) {
return -1;
}
return 0;
} /* event_queue_signal */
int event_queue_unsignal(EventQueue *queue) {
/* Do nothing; this implementation uses automatically reset synch objects. */
return 0;
} /* event_queue_unsignal */
/************************* PUBLIC FUNCTIONS:END ****************************/
|