|
|
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;
1.1.1.2 ! root 31: uae_u32 u32;
1.1 root 32: void *pv;
33: } uae_pt;
34:
35: /* These currently require the maximum size to be known at initialization
36: * time, but it wouldn't be hard to use a "normal" pipe as an extension once the
37: * user-level one gets full.
38: * We queue up to chunks pieces of data before signalling the other thread to
39: * avoid overhead. */
40:
41: typedef struct {
42: uae_sem_t lock;
43: uae_sem_t reader_wait;
44: uae_sem_t writer_wait;
45: uae_pt *data;
46: int size, chunks;
47: volatile int rdp, wrp;
48: volatile int writer_waiting;
49: volatile int reader_waiting;
50: } smp_comm_pipe;
51:
52: static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks)
53: {
54: p->data = (uae_pt *)malloc (size*sizeof (uae_pt));
55: p->size = size;
56: p->chunks = chunks;
57: p->rdp = p->wrp = 0;
58: p->reader_waiting = 0;
59: p->writer_waiting = 0;
60: sem_init (&p->lock, 0, 1);
61: sem_init (&p->reader_wait, 0, 0);
62: sem_init (&p->writer_wait, 0, 0);
63: }
64:
65: static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer)
66: {
67: if (p->reader_waiting
68: && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks))
69: {
70: p->reader_waiting = 0;
71: sem_post (&p->reader_wait);
72: }
73: }
74:
75: static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer)
76: {
77: int nxwrp = (p->wrp + 1) % p->size;
78:
79: if (p->reader_waiting) {
80: /* No need to do all the locking */
81: p->data[p->wrp] = data;
82: p->wrp = nxwrp;
83: maybe_wake_reader (p, no_buffer);
84: return;
85: }
86:
87: sem_wait (&p->lock);
88: if (nxwrp == p->rdp) {
89: /* Pipe full! */
90: p->writer_waiting = 1;
91: sem_post (&p->lock);
92: /* Note that the reader could get in between here and do a
93: * sem_post on writer_wait before we wait on it. That's harmless.
94: * There's a similar case in read_comm_pipe_int_blocking. */
95: sem_wait (&p->writer_wait);
96: sem_wait (&p->lock);
97: }
98: p->data[p->wrp] = data;
99: p->wrp = nxwrp;
100: maybe_wake_reader (p, no_buffer);
101: sem_post (&p->lock);
102: }
103:
104: static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p)
105: {
106: uae_pt data;
107:
108: sem_wait (&p->lock);
109: if (p->rdp == p->wrp) {
110: p->reader_waiting = 1;
111: sem_post (&p->lock);
112: sem_wait (&p->reader_wait);
113: sem_wait (&p->lock);
114: }
115: data = p->data[p->rdp];
116: p->rdp = (p->rdp + 1) % p->size;
117:
118: /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */
119: if (p->writer_waiting) {
120: p->writer_waiting = 0;
121: sem_post (&p->writer_wait);
122: }
123: sem_post (&p->lock);
124: return data;
125: }
126:
127: static __inline__ int comm_pipe_has_data (smp_comm_pipe *p)
128: {
129: return p->rdp != p->wrp;
130: }
131:
132: static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p)
133: {
134: uae_pt foo = read_comm_pipe_pt_blocking (p);
135: return foo.i;
136: }
1.1.1.2 ! root 137: static __inline__ uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p)
! 138: {
! 139: uae_pt foo = read_comm_pipe_pt_blocking (p);
! 140: return foo.u32;
! 141: }
1.1 root 142:
143: static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p)
144: {
145: uae_pt foo = read_comm_pipe_pt_blocking (p);
146: return foo.pv;
147: }
148:
149: static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer)
150: {
151: uae_pt foo;
152: foo.i = data;
153: write_comm_pipe_pt (p, foo, no_buffer);
154: }
155:
1.1.1.2 ! root 156: static __inline__ void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer)
! 157: {
! 158: uae_pt foo;
! 159: foo.u32 = data;
! 160: write_comm_pipe_pt (p, foo, no_buffer);
! 161: }
! 162:
1.1 root 163: static __inline__ void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer)
164: {
165: uae_pt foo;
166: foo.pv = data;
167: write_comm_pipe_pt (p, foo, no_buffer);
168: }
169:
170: typedef pthread_t penguin_id;
171: #define BAD_PENGUIN -1
172:
173: static __inline__ int start_penguin (void *(*f) (void *), void *arg, penguin_id *foo)
174: {
175: return pthread_create (foo, 0, f, arg);
176: }
177: #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.