/* 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 ** [Maintainers (after version 2.0-0.3.1):] ** 2001-2002 [maz] Marek Isalski ** 2002-2004 [dsr] David Rushby ** [Contributors:] ** 2001 [eac] Evgeny A. Cherkashin ** 2001-2002 [janez] Janez Jere */ /* 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 ****************************/