|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * "SSSSSYYYMMMETTTTTRIICCC MMMMMMULTIIIIIII PPPPPPENGGGGUIIIIN!!!!!" ! 5: * -- David S. Miller ! 6: * ! 7: * Symmetric Multi Penguin support - of course this also works on single ! 8: * penguin machines, but it's kind of pointless there. ! 9: * ! 10: * This is a rough, simpleminded draft - expect changes when it gets ported ! 11: * to other systems, and/or rewritten by someone who has experience with this ! 12: * kind of thing. This is just to get started and to see how this works out. ! 13: * ! 14: * Copyright 1997 Bernd Schmidt ! 15: */ ! 16: ! 17: #include <pthread.h> ! 18: #include <semaphore.h> ! 19: ! 20: /* Sempahores. We use POSIX semaphores; if you are porting this to a machine ! 21: * with different ones, make them look like POSIX semaphores. */ ! 22: typedef sem_t uae_sem_t; ! 23: #define uae_sem_init sem_init ! 24: #define uae_sem_post sem_post ! 25: #define uae_sem_wait sem_wait ! 26: #define uae_sem_trywait sem_trywait ! 27: #define uae_sem_getvalue sem_getvalue ! 28: ! 29: typedef union { ! 30: int i; ! 31: void *pv; ! 32: } uae_pt; ! 33: ! 34: /* These currently require the maximum size to be known at initialization ! 35: * time, but it wouldn't be hard to use a "normal" pipe as an extension once the ! 36: * user-level one gets full. ! 37: * We queue up to chunks pieces of data before signalling the other thread to ! 38: * avoid overhead. */ ! 39: ! 40: typedef struct { ! 41: uae_sem_t lock; ! 42: uae_sem_t reader_wait; ! 43: uae_sem_t writer_wait; ! 44: uae_pt *data; ! 45: int size, chunks; ! 46: volatile int rdp, wrp; ! 47: volatile int writer_waiting; ! 48: volatile int reader_waiting; ! 49: } smp_comm_pipe; ! 50: ! 51: static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks) ! 52: { ! 53: p->data = (uae_pt *)malloc (size*sizeof (uae_pt)); ! 54: p->size = size; ! 55: p->chunks = chunks; ! 56: p->rdp = p->wrp = 0; ! 57: p->reader_waiting = 0; ! 58: p->writer_waiting = 0; ! 59: sem_init (&p->lock, 0, 1); ! 60: sem_init (&p->reader_wait, 0, 0); ! 61: sem_init (&p->writer_wait, 0, 0); ! 62: } ! 63: ! 64: static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer) ! 65: { ! 66: if (p->reader_waiting ! 67: && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks)) ! 68: { ! 69: p->reader_waiting = 0; ! 70: sem_post (&p->reader_wait); ! 71: } ! 72: } ! 73: ! 74: static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer) ! 75: { ! 76: int nxwrp = (p->wrp + 1) % p->size; ! 77: ! 78: if (p->reader_waiting) { ! 79: /* No need to do all the locking */ ! 80: p->data[p->wrp] = data; ! 81: p->wrp = nxwrp; ! 82: maybe_wake_reader (p, no_buffer); ! 83: return; ! 84: } ! 85: ! 86: sem_wait (&p->lock); ! 87: if (nxwrp == p->rdp) { ! 88: /* Pipe full! */ ! 89: p->writer_waiting = 1; ! 90: sem_post (&p->lock); ! 91: /* Note that the reader could get in between here and do a ! 92: * sem_post on writer_wait before we wait on it. That's harmless. ! 93: * There's a similar case in read_comm_pipe_int_blocking. */ ! 94: sem_wait (&p->writer_wait); ! 95: sem_wait (&p->lock); ! 96: } ! 97: p->data[p->wrp] = data; ! 98: p->wrp = nxwrp; ! 99: maybe_wake_reader (p, no_buffer); ! 100: sem_post (&p->lock); ! 101: } ! 102: ! 103: static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p) ! 104: { ! 105: uae_pt data; ! 106: ! 107: sem_wait (&p->lock); ! 108: if (p->rdp == p->wrp) { ! 109: p->reader_waiting = 1; ! 110: sem_post (&p->lock); ! 111: sem_wait (&p->reader_wait); ! 112: sem_wait (&p->lock); ! 113: } ! 114: data = p->data[p->rdp]; ! 115: p->rdp = (p->rdp + 1) % p->size; ! 116: ! 117: /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */ ! 118: if (p->writer_waiting) { ! 119: p->writer_waiting = 0; ! 120: sem_post (&p->writer_wait); ! 121: } ! 122: sem_post (&p->lock); ! 123: return data; ! 124: } ! 125: ! 126: static __inline__ int comm_pipe_has_data (smp_comm_pipe *p) ! 127: { ! 128: return p->rdp != p->wrp; ! 129: } ! 130: ! 131: static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p) ! 132: { ! 133: uae_pt foo = read_comm_pipe_pt_blocking (p); ! 134: return foo.i; ! 135: } ! 136: ! 137: static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p) ! 138: { ! 139: uae_pt foo = read_comm_pipe_pt_blocking (p); ! 140: return foo.pv; ! 141: } ! 142: ! 143: static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer) ! 144: { ! 145: uae_pt foo; ! 146: foo.i = 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: } ! 156: ! 157: typedef pthread_t penguin_id; ! 158: #define BAD_PENGUIN -1 ! 159: ! 160: static __inline__ int start_penguin (void *(*f) (void *), void *arg, penguin_id *foo) ! 161: { ! 162: return pthread_create (foo, 0, f, arg); ! 163: } ! 164: #define UAE_PENGUIN_EXIT pthread_exit(0)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.