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
init_comm_pipe(smp_comm_pipe * p,int size,int chunks)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
destroy_comm_pipe(smp_comm_pipe * p)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
maybe_wake_reader(smp_comm_pipe * p,int no_buffer)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
write_comm_pipe_pt(smp_comm_pipe * p,uae_pt data,int no_buffer)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
read_comm_pipe_pt_blocking(smp_comm_pipe * p)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
comm_pipe_has_data(smp_comm_pipe * p)114 static __inline__ int comm_pipe_has_data (smp_comm_pipe *p)
115 {
116 return p->rdp != p->wrp;
117 }
118
read_comm_pipe_int_blocking(smp_comm_pipe * p)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 }
read_comm_pipe_u32_blocking(smp_comm_pipe * p)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
read_comm_pipe_pvoid_blocking(smp_comm_pipe * p)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
write_comm_pipe_int(smp_comm_pipe * p,int data,int no_buffer)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
write_comm_pipe_u32(smp_comm_pipe * p,int data,int no_buffer)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
write_comm_pipe_pvoid(smp_comm_pipe * p,void * data,int no_buffer)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