|
|
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.