|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * Communication between threads ! 5: * ! 6: * Copyright 1997, 2001 Bernd Schmidt ! 7: */ ! 8: ! 9: typedef union { ! 10: int i; ! 11: uae_u32 u32; ! 12: void *pv; ! 13: } uae_pt; ! 14: ! 15: /* These currently require the maximum size to be known at initialization ! 16: * time, but it wouldn't be hard to use a "normal" pipe as an extension once the ! 17: * user-level one gets full. ! 18: * We queue up to chunks pieces of data before signalling the other thread to ! 19: * avoid overhead. */ ! 20: ! 21: typedef struct { ! 22: uae_sem_t lock; ! 23: uae_sem_t reader_wait; ! 24: uae_sem_t writer_wait; ! 25: uae_pt *data; ! 26: int size, chunks; ! 27: volatile int rdp, wrp; ! 28: volatile int writer_waiting; ! 29: volatile int reader_waiting; ! 30: } smp_comm_pipe; ! 31: ! 32: static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks) ! 33: { ! 34: p->data = (uae_pt *)malloc (size*sizeof (uae_pt)); ! 35: p->size = size; ! 36: p->chunks = chunks; ! 37: p->rdp = p->wrp = 0; ! 38: p->reader_waiting = 0; ! 39: p->writer_waiting = 0; ! 40: uae_sem_init (&p->lock, 0, 1); ! 41: uae_sem_init (&p->reader_wait, 0, 0); ! 42: uae_sem_init (&p->writer_wait, 0, 0); ! 43: } ! 44: ! 45: static __inline__ void destroy_comm_pipe (smp_comm_pipe *p) ! 46: { ! 47: uae_sem_destroy (&p->lock); ! 48: uae_sem_destroy (&p->reader_wait); ! 49: uae_sem_destroy (&p->writer_wait); ! 50: } ! 51: ! 52: static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer) ! 53: { ! 54: if (p->reader_waiting ! 55: && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks)) ! 56: { ! 57: p->reader_waiting = 0; ! 58: uae_sem_post (&p->reader_wait); ! 59: } ! 60: } ! 61: ! 62: static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer) ! 63: { ! 64: int nxwrp = (p->wrp + 1) % p->size; ! 65: ! 66: if (p->reader_waiting) { ! 67: /* No need to do all the locking */ ! 68: p->data[p->wrp] = data; ! 69: p->wrp = nxwrp; ! 70: maybe_wake_reader (p, no_buffer); ! 71: return; ! 72: } ! 73: ! 74: uae_sem_wait (&p->lock); ! 75: if (nxwrp == p->rdp) { ! 76: /* Pipe full! */ ! 77: p->writer_waiting = 1; ! 78: uae_sem_post (&p->lock); ! 79: /* Note that the reader could get in between here and do a ! 80: * sem_post on writer_wait before we wait on it. That's harmless. ! 81: * There's a similar case in read_comm_pipe_int_blocking. */ ! 82: uae_sem_wait (&p->writer_wait); ! 83: uae_sem_wait (&p->lock); ! 84: } ! 85: p->data[p->wrp] = data; ! 86: p->wrp = nxwrp; ! 87: maybe_wake_reader (p, no_buffer); ! 88: uae_sem_post (&p->lock); ! 89: } ! 90: ! 91: static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p) ! 92: { ! 93: uae_pt data; ! 94: ! 95: uae_sem_wait (&p->lock); ! 96: if (p->rdp == p->wrp) { ! 97: p->reader_waiting = 1; ! 98: uae_sem_post (&p->lock); ! 99: uae_sem_wait (&p->reader_wait); ! 100: uae_sem_wait (&p->lock); ! 101: } ! 102: data = p->data[p->rdp]; ! 103: p->rdp = (p->rdp + 1) % p->size; ! 104: ! 105: /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */ ! 106: if (p->writer_waiting) { ! 107: p->writer_waiting = 0; ! 108: uae_sem_post (&p->writer_wait); ! 109: } ! 110: uae_sem_post (&p->lock); ! 111: return data; ! 112: } ! 113: ! 114: static __inline__ int comm_pipe_has_data (smp_comm_pipe *p) ! 115: { ! 116: return p->rdp != p->wrp; ! 117: } ! 118: ! 119: static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p) ! 120: { ! 121: uae_pt foo = read_comm_pipe_pt_blocking (p); ! 122: return foo.i; ! 123: } ! 124: static __inline__ uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p) ! 125: { ! 126: uae_pt foo = read_comm_pipe_pt_blocking (p); ! 127: return foo.u32; ! 128: } ! 129: ! 130: static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p) ! 131: { ! 132: uae_pt foo = read_comm_pipe_pt_blocking (p); ! 133: return foo.pv; ! 134: } ! 135: ! 136: static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer) ! 137: { ! 138: uae_pt foo; ! 139: foo.i = data; ! 140: write_comm_pipe_pt (p, foo, no_buffer); ! 141: } ! 142: ! 143: static __inline__ void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer) ! 144: { ! 145: uae_pt foo; ! 146: foo.u32 = data; ! 147: write_comm_pipe_pt (p, foo, no_buffer); ! 148: } ! 149: ! 150: static __inline__ void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer) ! 151: { ! 152: uae_pt foo; ! 153: foo.pv = data; ! 154: write_comm_pipe_pt (p, foo, no_buffer); ! 155: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.