1  /*
2   * UAE - The Un*x Amiga Emulator
3   *
4   * Communication between threads
5   *
6   * Copyright 1997, 2001 Bernd Schmidt
7   */
8 
9 #ifndef UAE_COMMPIPE_H
10 #define UAE_COMMPIPE_H
11 
12 #include "uae/types.h"
13 #ifdef FSUAE
14 #include "uae/inline.h"
15 #include "threaddep/sem.h"
16 #include <stdlib.h>
17 #include <string.h>
18 #endif
19 
20 typedef union {
21     int i;
22     uae_u32 u32;
23     void *pv;
24 } uae_pt;
25 
26 /* These currently require the maximum size to be known at initialization
27  * time, but it wouldn't be hard to use a "normal" pipe as an extension once the
28  * user-level one gets full.
29  * We queue up to chunks pieces of data before signalling the other thread to
30  * avoid overhead. */
31 
32 typedef struct {
33     uae_sem_t lock;
34     uae_sem_t reader_wait;
35     uae_sem_t writer_wait;
36     uae_pt *data;
37     int size, chunks;
38     volatile int rdp, wrp;
39     volatile int writer_waiting;
40     volatile int reader_waiting;
41 } smp_comm_pipe;
42 
init_comm_pipe(smp_comm_pipe * p,int size,int chunks)43 STATIC_INLINE void init_comm_pipe (smp_comm_pipe *p, int size, int chunks)
44 {
45     memset (p, 0, sizeof (*p));
46     p->data = (uae_pt *)malloc (size*sizeof (uae_pt));
47     p->size = size;
48     p->chunks = chunks;
49     p->rdp = p->wrp = 0;
50     p->reader_waiting = 0;
51     p->writer_waiting = 0;
52     uae_sem_init (&p->lock, 0, 1);
53     uae_sem_init (&p->reader_wait, 0, 0);
54     uae_sem_init (&p->writer_wait, 0, 0);
55 }
56 
destroy_comm_pipe(smp_comm_pipe * p)57 STATIC_INLINE void destroy_comm_pipe (smp_comm_pipe *p)
58 {
59     uae_sem_destroy (&p->lock);
60     uae_sem_destroy (&p->reader_wait);
61     uae_sem_destroy (&p->writer_wait);
62 }
63 
maybe_wake_reader(smp_comm_pipe * p,int no_buffer)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 	uae_sem_post (&p->reader_wait);
71     }
72 }
73 
write_comm_pipe_pt(smp_comm_pipe * p,uae_pt data,int no_buffer)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     uae_sem_wait (&p->lock);
87     if (nxwrp == p->rdp) {
88 	/* Pipe full! */
89 	p->writer_waiting = 1;
90 	uae_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 	uae_sem_wait (&p->writer_wait);
95 	uae_sem_wait (&p->lock);
96     }
97     p->data[p->wrp] = data;
98     p->wrp = nxwrp;
99     maybe_wake_reader (p, no_buffer);
100     uae_sem_post (&p->lock);
101 }
102 
read_comm_pipe_pt_blocking(smp_comm_pipe * p)103 STATIC_INLINE uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p)
104 {
105     uae_pt data;
106 
107     uae_sem_wait (&p->lock);
108     if (p->rdp == p->wrp) {
109 	p->reader_waiting = 1;
110 	uae_sem_post (&p->lock);
111 	uae_sem_wait (&p->reader_wait);
112 	uae_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 	uae_sem_post (&p->writer_wait);
121     }
122     uae_sem_post (&p->lock);
123     return data;
124 }
125 
comm_pipe_has_data(smp_comm_pipe * p)126 STATIC_INLINE int comm_pipe_has_data (smp_comm_pipe *p)
127 {
128     return p->rdp != p->wrp;
129 }
130 
read_comm_pipe_int_blocking(smp_comm_pipe * p)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 }
read_comm_pipe_u32_blocking(smp_comm_pipe * p)136 STATIC_INLINE uae_u32 read_comm_pipe_u32_blocking (smp_comm_pipe *p)
137 {
138     uae_pt foo = read_comm_pipe_pt_blocking (p);
139     return foo.u32;
140 }
141 
read_comm_pipe_pvoid_blocking(smp_comm_pipe * p)142 STATIC_INLINE void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p)
143 {
144     uae_pt foo = read_comm_pipe_pt_blocking (p);
145     return foo.pv;
146 }
147 
write_comm_pipe_int(smp_comm_pipe * p,int data,int no_buffer)148 STATIC_INLINE void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer)
149 {
150     uae_pt foo;
151     foo.i = data;
152     write_comm_pipe_pt (p, foo, no_buffer);
153 }
154 
write_comm_pipe_u32(smp_comm_pipe * p,int data,int no_buffer)155 STATIC_INLINE void write_comm_pipe_u32 (smp_comm_pipe *p, int data, int no_buffer)
156 {
157     uae_pt foo;
158     foo.u32 = data;
159     write_comm_pipe_pt (p, foo, no_buffer);
160 }
161 
write_comm_pipe_pvoid(smp_comm_pipe * p,void * data,int no_buffer)162 STATIC_INLINE void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer)
163 {
164     uae_pt foo;
165     foo.pv = data;
166     write_comm_pipe_pt (p, foo, no_buffer);
167 }
168 
169 #endif /* UAE_COMMPIPE_H */
170