cvsuser 03/07/12 10:45:02
Modified: . tsq.c
Log:
Rework of some of the TSQ stuff
Revision Changes Path
1.3 +75 -77 parrot/tsq.c
Index: tsq.c
===================================================================
RCS file: /cvs/public/parrot/tsq.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- tsq.c 1 Jun 2003 00:17:44 -0000 1.2
+++ tsq.c 12 Jul 2003 17:45:01 -0000 1.3
@@ -1,9 +1,9 @@
/* tsq.c
* Copyright: 2003, Yet Another Society
* CVS Info
- * $Id: tsq.c,v 1.2 2003/06/01 00:17:44 josh Exp $
+ * $Id: tsq.c,v 1.3 2003/07/12 17:45:01 dan Exp $
* Overview:
- * Thread-safe and interrupt safe queues
+ * Thread-safe queues
* Data Structure and Algorithms:
* History:
* Notes:
@@ -12,87 +12,85 @@
#include "parrot/parrot.h"
-/* This code implements thread-safe and interrupt safe code, with the
- following caveats:
-
- Only mainline code may remove entries from the queue
-
- Mainline code may add entries to the queue
-
- Interrupt code may add entries to the queue
-
- Interrupt code may not interrupt other interrupt code (no nested
- interrupts)
-
- Interrupt code, in this case, is a C-level signal handler, AST
- callbacks, interrupt handlers, or any code that may have been
- invoked by the system while our user-level program is in an
- inconsistent state.
-
- Basically if you're not allowed to allocate memory or call a
- thread routine, it's interrupt code.
-
- Entries are *always* added at the tail of the queue, and *always*
- removed from the head of the queue
-
- In the case where there's a native queue management system, we'll
- use that instead, as doing this portably is profoundly nasty. And
- if an OS provides atomic queue management, who are we to disagree?
- They probably use Secret Hardware Tricks (like the VAX's queue
- management instructions, which are emulated in PAL code on the
- Alphas)
-
- To make this all work we *MUST* disable any and all instruction
- reordering, caching, and other compiler trickery. The code must
- execute in the order it is written in, and all queue and entry
- members must be treated as volatile and thus not cached in
- registers. Yeah, it'll make the code slower, but that beats bad
- code, and bad code at this level will likely kill things really
- badly which would be bad.
-
-
- The order of operations for interrupt code:
+/* A synchronized entry popper */
+QUEUE_ENTRY *
+pop_entry(QUEUE *queue) {
+ QUEUE_ENTRY *returnval;
+ queue_lock(queue);
+ returnval = nosync_pop_entry(queue);
+ queue_unlock(queue);
+ return returnval;
+}
- * Check queue in use flag. If false, just go do it since nothing's
- using the queue. If true,
+/* Grab an entry off the queue with no synchronization. Internal only,
+ because it's darned evil and shouldn't be used outside the
+ module. It's in here so we don't have to duplicate pop code */
+static
+QUEUE_ENTRY *
+nosync_pop_entry(QUEUE *queue) {
+ QUEUE_ENTRY *returnval;
+ if (!queue->head) {
+ return NULL;
+ }
+ returnval = queue->head;
+ if (queue->head == queue->tail) {
+ queue->head = NULL;
+ queue->tail = NULL;
+ } else {
+ queue->head = queue->head->next;
+ }
+ returnval->next = NULL;
+ return returnval;
+}
+QUEUE_ENTRY *
+wait_for_entry(QUEUE *queue) {
+ QUEUE_ENTRY *returnval;
+ queue_lock(queue);
+ while (queue->head == NULL) {
+ queue_wait(queue);
+ }
+ returnval = nosync_pop_entry(queue);
+ queue_unlock(queue);
+ return returnval;
-*/
+}
-#if defined(__GNUC__)
-# if defined(__OPTIMIZE__)
-# error "Can't compile this with optimizations of any sort"
-# endif
-#endif
-
-/* Insert an entry to the passed in queue. Callable only from within
- interrupt code */
-void Parrot_ins_queue_interrupt(QUEUE *queue, QUEUE_ENTRY *entry) {
- /* entry's next pointer is always NULL */
- entry->next = NULL;
-
- /* Is something using us? If not, just go do this */
- if (!queue->queue_in_use) {
- /* Is there a tail entry? */
+void
+push_entry(QUEUE *queue, QUEUE_ENTRY *entry) {
+ queue_lock(queue);
+ /* Is there something in the queue? */
if (queue->tail) {
- entry->next = NULL;
queue->tail->next = entry;
queue->tail = entry;
- }
- else {
- /* If no tail, then no head. Empty queue */
+ } else {
queue->head = entry;
queue->tail = entry;
}
+ queue_signal(queue);
+ queue_unlock(queue);
+}
+
+void
+queue_lock(QUEUE *queue) {
+ LOCK(queue->queue_mutex);
}
- else {
- /* This is the tricky bit. The queue is in use, which means
- something is mutating it. That means the queue header or
- entries could be in an inconsistent state. We need to tread
- really carefully here */
+
+void
+queue_unlock(QUEUE *queue) {
+ UNLOCK(queue->queue_mutex);
}
+
+/* This function wakes up *every* thread waiting on the queue */
+void
+queue_signal(QUEUE *queue) {
+ CONDITION_BROADCAST(queue->queue_condition);
}
+void
+queue_wait(QUEUE *queue) {
+ COND_WAIT(queue->queue_condition, queue->queue_mutex);
+}
/*
* Local variables: