source: mainline/uspace/lib/ipcgfx/src/server.c@ 8bf9058

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8bf9058 was fc4abca, checked in by Jiri Svoboda <jiri@…>, 5 years ago

IPC GC server needs to destroy all lingering bitmaps

The client could exit without destroying all bitmaps in case it is
misbehaving or if it crashed.

  • Property mode set to 100644
File size: 9.6 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libipcgfx
30 * @{
31 */
32/**
33 * @file GFX IPC server
34 *
35 * Serve a graphics context via HelenOS IPC.
36 */
37
38#include <as.h>
39#include <errno.h>
40#include <gfx/bitmap.h>
41#include <gfx/color.h>
42#include <gfx/render.h>
43#include <ipc/bd.h>
44#include <ipcgfx/ipc/gc.h>
45#include <ipcgfx/server.h>
46#include <stdint.h>
47#include <stdlib.h>
48#include <stdio.h>
49
50#include "../private/server.h"
51
52static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *, sysarg_t);
53
54static void gc_set_rgb_color_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
55{
56 uint16_t r, g, b;
57 gfx_color_t *color;
58 errno_t rc;
59
60 r = ipc_get_arg1(call);
61 g = ipc_get_arg2(call);
62 b = ipc_get_arg3(call);
63
64 rc = gfx_color_new_rgb_i16(r, g, b, &color);
65 if (rc != EOK) {
66 async_answer_0(call, ENOMEM);
67 return;
68 }
69
70 rc = gfx_set_color(srvgc->gc, color);
71 async_answer_0(call, rc);
72}
73
74static void gc_fill_rect_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
75{
76 gfx_rect_t rect;
77 errno_t rc;
78
79 rect.p0.x = ipc_get_arg1(call);
80 rect.p0.y = ipc_get_arg2(call);
81 rect.p1.x = ipc_get_arg3(call);
82 rect.p1.y = ipc_get_arg4(call);
83
84 rc = gfx_fill_rect(srvgc->gc, &rect);
85 async_answer_0(call, rc);
86}
87
88static void gc_bitmap_create_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
89{
90 gfx_bitmap_params_t params;
91 gfx_bitmap_alloc_t alloc;
92 gfx_bitmap_t *bitmap;
93 gfx_coord2_t dim;
94 ipc_gc_srv_bitmap_t *srvbmp = NULL;
95 ipc_call_t call;
96 size_t size;
97 unsigned int flags;
98 void *pixels;
99 errno_t rc;
100
101 if (!async_data_write_receive(&call, &size)) {
102 async_answer_0(&call, EREFUSED);
103 async_answer_0(icall, EREFUSED);
104 return;
105 }
106
107 if (size != sizeof(gfx_bitmap_params_t)) {
108 async_answer_0(&call, EINVAL);
109 async_answer_0(icall, EINVAL);
110 return;
111 }
112
113 rc = async_data_write_finalize(&call, &params, size);
114 if (rc != EOK) {
115 async_answer_0(&call, rc);
116 async_answer_0(icall, rc);
117 return;
118 }
119
120 /* Bitmap dimensions */
121 gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
122
123 if (!async_share_out_receive(&call, &size, &flags)) {
124 async_answer_0(icall, EINVAL);
125 return;
126 }
127
128 /* Check size */
129 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
130 async_answer_0(icall, EINVAL);
131 return;
132 }
133
134 rc = async_share_out_finalize(&call, &pixels);
135 if (rc != EOK || pixels == AS_MAP_FAILED) {
136 async_answer_0(icall, ENOMEM);
137 return;
138 }
139
140 alloc.pitch = dim.x * sizeof(uint32_t);
141 alloc.off0 = 0;
142 alloc.pixels = pixels;
143
144 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
145 if (srvbmp == NULL) {
146 as_area_destroy(pixels);
147 async_answer_0(icall, ENOMEM);
148 return;
149 }
150
151 rc = gfx_bitmap_create(srvgc->gc, &params, &alloc, &bitmap);
152 if (rc != EOK) {
153 free(srvbmp);
154 as_area_destroy(pixels);
155 async_answer_0(icall, rc);
156 return;
157 }
158
159 srvbmp->srvgc = srvgc;
160 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
161 srvbmp->bmp = bitmap;
162 srvbmp->bmp_id = srvgc->next_bmp_id++;
163
164 /* We created the memory area by sharing it in */
165 srvbmp->myalloc = true;
166 srvbmp->pixels = pixels;
167
168 async_answer_1(icall, EOK, srvbmp->bmp_id);
169}
170
171static void gc_bitmap_create_doutput_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
172{
173 gfx_bitmap_params_t params;
174 gfx_bitmap_alloc_t alloc;
175 gfx_bitmap_t *bitmap;
176 gfx_coord2_t dim;
177 ipc_gc_srv_bitmap_t *srvbmp = NULL;
178 ipc_call_t call;
179 size_t size;
180 errno_t rc;
181
182 if (!async_data_write_receive(&call, &size)) {
183 async_answer_0(&call, EREFUSED);
184 async_answer_0(icall, EREFUSED);
185 return;
186 }
187
188 if (size != sizeof(gfx_bitmap_params_t)) {
189 async_answer_0(&call, EINVAL);
190 async_answer_0(icall, EINVAL);
191 return;
192 }
193
194 rc = async_data_write_finalize(&call, &params, size);
195 if (rc != EOK) {
196 async_answer_0(&call, rc);
197 async_answer_0(icall, rc);
198 return;
199 }
200
201 /* Bitmap dimensions */
202 gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
203
204 if (!async_share_in_receive(&call, &size)) {
205 async_answer_0(icall, EINVAL);
206 return;
207 }
208
209 /* Check size */
210 if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
211 async_answer_0(&call, EINVAL);
212 async_answer_0(icall, EINVAL);
213 return;
214 }
215
216 rc = gfx_bitmap_create(srvgc->gc, &params, NULL, &bitmap);
217 if (rc != EOK) {
218 async_answer_0(&call, rc);
219 async_answer_0(icall, rc);
220 return;
221 }
222
223 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
224 if (rc != EOK) {
225 gfx_bitmap_destroy(bitmap);
226 async_answer_0(&call, rc);
227 async_answer_0(icall, rc);
228 return;
229 }
230
231 rc = async_share_in_finalize(&call, alloc.pixels, AS_AREA_READ |
232 AS_AREA_WRITE | AS_AREA_CACHEABLE);
233 if (rc != EOK) {
234 gfx_bitmap_destroy(bitmap);
235 async_answer_0(icall, EIO);
236 return;
237 }
238
239 srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
240 if (srvbmp == NULL) {
241 gfx_bitmap_destroy(bitmap);
242 async_answer_0(icall, ENOMEM);
243 return;
244 }
245
246 srvbmp->srvgc = srvgc;
247 list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
248 srvbmp->bmp = bitmap;
249 srvbmp->bmp_id = srvgc->next_bmp_id++;
250
251 /* Area allocated by backing GC, we just shared it out */
252 srvbmp->myalloc = false;
253 srvbmp->pixels = alloc.pixels; // Not really needed
254
255 async_answer_1(icall, EOK, srvbmp->bmp_id);
256}
257
258static void gc_bitmap_destroy_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
259{
260 sysarg_t bmp_id;
261 ipc_gc_srv_bitmap_t *bitmap;
262 errno_t rc;
263
264 bmp_id = ipc_get_arg1(call);
265
266 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
267 if (bitmap == NULL) {
268 async_answer_0(call, ENOENT);
269 return;
270 }
271
272 rc = gfx_bitmap_destroy(bitmap->bmp);
273 if (rc != EOK) {
274 async_answer_0(call, rc);
275 return;
276 }
277
278 if (bitmap->myalloc)
279 as_area_destroy(bitmap->pixels);
280
281 list_remove(&bitmap->lbitmaps);
282 free(bitmap);
283
284 async_answer_0(call, rc);
285}
286
287static void gc_bitmap_render_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
288{
289 ipc_gc_srv_bitmap_t *bitmap;
290 sysarg_t bmp_id;
291 gfx_rect_t srect;
292 gfx_coord2_t offs;
293 ipc_call_t call;
294 size_t size;
295 errno_t rc;
296
297 if (!async_data_write_receive(&call, &size)) {
298 async_answer_0(&call, EREFUSED);
299 async_answer_0(icall, EREFUSED);
300 return;
301 }
302
303 if (size != sizeof(gfx_rect_t)) {
304 async_answer_0(&call, EINVAL);
305 async_answer_0(icall, EINVAL);
306 return;
307 }
308
309 rc = async_data_write_finalize(&call, &srect, size);
310 if (rc != EOK) {
311 async_answer_0(&call, rc);
312 async_answer_0(icall, rc);
313 return;
314 }
315
316 bmp_id = ipc_get_arg1(icall);
317 offs.x = ipc_get_arg2(icall);
318 offs.y = ipc_get_arg3(icall);
319
320 bitmap = gc_bitmap_lookup(srvgc, bmp_id);
321 if (bitmap == NULL) {
322 async_answer_0(icall, ENOENT);
323 return;
324 }
325
326 rc = gfx_bitmap_render(bitmap->bmp, &srect, &offs);
327 async_answer_0(icall, rc);
328}
329
330errno_t gc_conn(ipc_call_t *icall, gfx_context_t *gc)
331{
332 ipc_gc_srv_t srvgc;
333 ipc_gc_srv_bitmap_t *bitmap;
334 link_t *link;
335
336 /* Accept the connection */
337 async_accept_0(icall);
338
339 srvgc.gc = gc;
340 list_initialize(&srvgc.bitmaps);
341 srvgc.next_bmp_id = 1;
342
343 while (true) {
344 ipc_call_t call;
345 async_get_call(&call);
346 sysarg_t method = ipc_get_imethod(&call);
347
348 if (!method) {
349 /* The other side has hung up */
350 async_answer_0(&call, EOK);
351 break;
352 }
353
354 switch (method) {
355 case GC_SET_RGB_COLOR:
356 gc_set_rgb_color_srv(&srvgc, &call);
357 break;
358 case GC_FILL_RECT:
359 gc_fill_rect_srv(&srvgc, &call);
360 break;
361 case GC_BITMAP_CREATE:
362 gc_bitmap_create_srv(&srvgc, &call);
363 break;
364 case GC_BITMAP_CREATE_DOUTPUT:
365 gc_bitmap_create_doutput_srv(&srvgc, &call);
366 break;
367 case GC_BITMAP_DESTROY:
368 gc_bitmap_destroy_srv(&srvgc, &call);
369 break;
370 case GC_BITMAP_RENDER:
371 gc_bitmap_render_srv(&srvgc, &call);
372 break;
373 default:
374 async_answer_0(&call, EINVAL);
375 break;
376 }
377 }
378
379 /*
380 * Destroy all remaining bitmaps. A client should destroy all
381 * the bitmaps before closing connection. But it could happen
382 * that the client is misbehaving or was abruptly disconnected
383 * (e.g. crashed).
384 */
385 link = list_first(&srvgc.bitmaps);
386 while (link != NULL) {
387 bitmap = list_get_instance(link, ipc_gc_srv_bitmap_t,
388 lbitmaps);
389
390 (void) gfx_bitmap_destroy(bitmap->bmp);
391 if (bitmap->myalloc)
392 as_area_destroy(bitmap->pixels);
393 list_remove(&bitmap->lbitmaps);
394 free(bitmap);
395
396 link = list_first(&srvgc.bitmaps);
397 }
398
399 return EOK;
400}
401
402static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *srvgc,
403 sysarg_t bmp_id)
404{
405 link_t *link;
406 ipc_gc_srv_bitmap_t *bmp;
407
408 link = list_first(&srvgc->bitmaps);
409 while (link != NULL) {
410 bmp = list_get_instance(link, ipc_gc_srv_bitmap_t, lbitmaps);
411 if (bmp->bmp_id == bmp_id)
412 return bmp;
413 link = list_next(link, &srvgc->bitmaps);
414 }
415
416 return NULL;
417}
418
419/** @}
420 */
Note: See TracBrowser for help on using the repository browser.