tbm_sync: tbm_sync_timeline/fence_import use dup
[platform/core/uifw/libtbm.git] / src / tbm_sync.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 - 2016 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>,
8          Changyeon Lee <cyeon.lee@samsung.com>,
9                  Boram Park <boram1288.park@samsung.com>,
10                  Sangjin Lee <lsj119@samsung.com>
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sub license, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
19
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
22 of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
28 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32 **************************************************************************/
33
34 #include "tbm_bufmgr.h"
35 #include "tbm_bufmgr_int.h"
36 #include "tbm_sync.h"
37
38 #include <string.h>
39 #include <errno.h>
40 #include <sys/ioctl.h>
41 #include <linux/types.h>
42
43 #define SYNC_IOC_MAGIC               '>'
44 #define SYNC_IOC_WAIT                _IOW(SYNC_IOC_MAGIC, 0, __s32)
45 #define SYNC_IOC_MERGE               _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
46 #define SW_SYNC_IOC_MAGIC            'W'
47 #define SW_SYNC_IOC_CREATE_FENCE     _IOWR(SW_SYNC_IOC_MAGIC, 0,\
48                                          struct sw_sync_create_fence_data)
49 #define SW_SYNC_IOC_INC              _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
50
51 #define SYNC_DEVICE_PATH             "/dev/sw_sync"
52
53 struct _tbm_sync_timeline {
54         int fd;
55 };
56
57 struct _tbm_sync_fence {
58         int fd;
59 };
60
61 static pthread_mutex_t tbm_sync_lock;
62 static int tbm_sync_support = 0;
63
64 static bool
65 _tbm_sync_mutex_init(void)
66 {
67         static bool tbm_sync_mutex_init = false;
68
69         if (tbm_sync_mutex_init)
70                 return true;
71
72         if (pthread_mutex_init(&tbm_sync_lock, NULL)) {
73                 TBM_LOG_E("fail: tbm_sync mutex init\n");
74                 return false;
75         }
76
77         tbm_sync_mutex_init = true;
78
79         return true;
80 }
81
82 static void
83 _tbm_sync_mutex_lock(void)
84 {
85         if (!_tbm_sync_mutex_init())
86                 return;
87
88         pthread_mutex_lock(&tbm_sync_lock);
89 }
90
91 static void
92 _tbm_sync_mutex_unlock(void)
93 {
94         pthread_mutex_unlock(&tbm_sync_lock);
95 }
96
97 static tbm_sync_error_e
98 _tbm_sync_check_capability(void)
99 {
100 #ifdef NOT_IMPELMENT_YET
101         tbm_bufmgr bufmgr = NULL;
102         unsigned int capabilities = TBM_BUFMGR_CAPABILITY_NONE;
103 #endif
104         struct stat st_buf;
105
106     if (tbm_sync_support)
107                 return TBM_SYNC_ERROR_NONE;
108
109 #ifdef NOT_IMPELMENT_YET
110         /* check the bufmgr */
111         bufmgr = _tbm_bufmgr_get_bufmgr();
112         if (!bufmgr) {
113                 return TBM_SYNC_ERROR_INVALID_OPERATION;
114         }
115
116         /* check the tbm_sync capability */
117         capabilities = tbm_bufmgr_get_capability(bufmgr);
118
119         if ((capabilities&TBM_BUFMGR_CAPABILITY_TBM_SYNC) != TBM_BUFMGR_CAPABILITY_TBM_SYNC) {
120                 //TODO: check the sw_sync device node... to verify the timeline sync
121                 tbm_sync_support = 1;
122
123                 return TBM_SYNC_ERROR_INVALID_OPERATION;
124         }
125 #endif
126
127         if (stat(SYNC_DEVICE_PATH, &st_buf) == 0) {
128                 tbm_sync_support = 1;
129         } else {
130                 TBM_LOG_E("TBM_SYNC not supported\n");
131                 return TBM_SYNC_ERROR_INVALID_OPERATION;
132         }
133
134         return TBM_SYNC_ERROR_NONE;
135 }
136
137 tbm_sync_timeline_h
138 tbm_sync_timeline_create(tbm_sync_error_e *error)
139 {
140         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
141         tbm_sync_timeline_h timeline = NULL;
142         int fd;
143
144         _tbm_sync_mutex_lock();
145
146         /* check the tbm_sync capability */
147         ret = _tbm_sync_check_capability();;
148         if (ret != TBM_SYNC_ERROR_NONE)
149                 goto done;
150
151         fd = open(SYNC_DEVICE_PATH, O_RDWR);
152         if (fd < 0) {
153                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
154                 TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC open failed", errno, strerror(errno));
155         } else {
156                 struct _tbm_sync_timeline *timeline_handle =
157                         calloc(1, sizeof(struct _tbm_sync_timeline));
158
159                 if (timeline_handle == NULL) {
160                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
161                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
162                         close(fd);
163                 } else {
164                         timeline_handle->fd = fd;
165                         timeline = timeline_handle;
166                 }
167         }
168
169 done:
170         if (error)
171                 *error = ret;
172
173         _tbm_sync_mutex_unlock();
174
175         return timeline;
176 }
177
178 tbm_sync_error_e
179 tbm_sync_timeline_destroy(tbm_sync_timeline_h timeline)
180 {
181         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
182
183         _tbm_sync_mutex_lock();
184
185         /* check the tbm_sync capability */
186         ret = _tbm_sync_check_capability();;
187         if (ret != TBM_SYNC_ERROR_NONE)
188                 goto done;
189
190         if (timeline) {
191                 struct _tbm_sync_timeline *timeline_handle = timeline;
192
193                 if (timeline_handle->fd != -1)
194                         close(timeline_handle->fd);
195                 free(timeline);
196         } else {
197                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
198         }
199
200 done:
201         _tbm_sync_mutex_unlock();
202
203     return ret;
204 }
205
206 tbm_sync_timeline_h
207 tbm_sync_timeline_import(int fd, tbm_sync_error_e *error)
208 {
209         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
210         tbm_sync_timeline_h timeline = NULL;
211         int new_fd;
212
213         _tbm_sync_mutex_lock();
214
215         /* check the tbm_sync capability */
216         ret = _tbm_sync_check_capability();;
217         if (ret != TBM_SYNC_ERROR_NONE)
218                 goto done;
219
220         if (fd < 0) {
221                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
222                 goto done;
223         }
224
225         new_fd = dup(fd);
226         if (new_fd < 0) {
227                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
228                 TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline dup failed",
229                                   errno, strerror(errno));
230         } else {
231                 struct _tbm_sync_timeline *timeline_handle =
232                         calloc(1, sizeof(struct _tbm_sync_timeline));
233                 int fd_flag;
234
235                 if ((fd_flag = fcntl(new_fd, F_GETFD, 0)) != -1) {
236                         fd_flag |= FD_CLOEXEC;
237                         fd_flag = fcntl(new_fd, F_SETFD, fd_flag);
238                 } else {
239                         TBM_LOG_W("%s\n", "TBM_SYNC fcntl failed");
240                 }
241
242                 if (timeline_handle == NULL) {
243                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
244                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
245                         close(new_fd);
246                 } else {
247                         timeline_handle->fd = new_fd;
248                         timeline = timeline_handle;
249                 }
250         }
251
252 done:
253         if (error)
254                 *error = ret;
255
256         _tbm_sync_mutex_unlock();
257
258         return timeline;
259 }
260
261 int
262 tbm_sync_timeline_export(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
263 {
264         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
265         int fd = -1;
266
267         _tbm_sync_mutex_lock();
268
269         /* check the tbm_sync capability */
270         ret = _tbm_sync_check_capability();;
271         if (ret != TBM_SYNC_ERROR_NONE)
272                 goto done;
273
274         if (timeline) {
275                 struct _tbm_sync_timeline *timeline_handle = timeline;
276                 int fd_flag;
277
278                 fd = dup(timeline_handle->fd);
279                 if (fd == -1) {
280                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
281                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline dup failed",
282                                           errno, strerror(errno));
283                 } else {
284                         if ((fd_flag = fcntl(fd, F_GETFD, 0)) != -1) {
285                                 fd_flag |= FD_CLOEXEC;
286                                 fd_flag = fcntl(fd, F_SETFD, fd_flag);
287                         } else {
288                                 TBM_LOG_W("%s\n", "TBM_SYNC fcntl failed");
289                         }
290                 }
291
292         } else {
293                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
294         }
295
296 done:
297         if (error)
298                 *error = ret;
299
300         _tbm_sync_mutex_unlock();
301
302         return fd;
303 }
304
305 tbm_sync_error_e
306 tbm_sync_timeline_increase_count(tbm_sync_timeline_h timeline, unsigned int interval)
307 {
308         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
309
310         _tbm_sync_mutex_lock();
311
312         /* check the tbm_sync capability */
313         ret = _tbm_sync_check_capability();;
314         if (ret != TBM_SYNC_ERROR_NONE)
315                 goto done;
316
317         if (timeline) {
318                 struct _tbm_sync_timeline *timeline_handle = timeline;
319                 __u32 arg = interval;
320
321                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_INC, &arg) == -1) {
322                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
323                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC timeline inc failed", errno, strerror(errno));
324                 }
325         } else {
326                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
327         }
328
329 done:
330         _tbm_sync_mutex_unlock();
331
332         return ret;
333 }
334
335 unsigned int
336 tbm_sync_timeline_get_cur_count(tbm_sync_timeline_h timeline, tbm_sync_error_e *error)
337 {
338         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
339         unsigned int cur_count = 0;
340
341         _tbm_sync_mutex_lock();
342
343         /* check the tbm_sync capability */
344         ret = _tbm_sync_check_capability();;
345         if (ret != TBM_SYNC_ERROR_NONE)
346                 goto done;
347
348         /* TODO: sync_timeline_get_cur_count */
349
350 done:
351         if (error)
352                 *error = ret;
353
354         _tbm_sync_mutex_unlock();
355
356         return cur_count;
357 }
358
359 tbm_sync_fence_h
360 tbm_sync_fence_create(tbm_sync_timeline_h timeline, const char *name, unsigned int count_val, tbm_sync_error_e *error)
361 {
362         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
363         tbm_sync_fence_h fence = NULL;
364
365         _tbm_sync_mutex_lock();
366
367         /* check the tbm_sync capability */
368         ret = _tbm_sync_check_capability();;
369         if (ret != TBM_SYNC_ERROR_NONE)
370                 goto done;
371
372         if (timeline) {
373                 struct _tbm_sync_timeline *timeline_handle = timeline;
374                 struct sw_sync_create_fence_data {
375                         __u32 value;
376                         char name[32];
377                         __s32 fence;
378                 } data;
379
380                 data.value = count_val;
381                 strncpy(data.name, name ? name : "", 32);
382                 data.name[31] = '\0';
383
384                 if (ioctl(timeline_handle->fd, SW_SYNC_IOC_CREATE_FENCE, &data) == -1) {
385                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
386                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC create fence failed",
387                                           errno, strerror(errno));
388                 } else {
389                         struct _tbm_sync_fence *fence_handle =
390                                 calloc(1, sizeof(struct _tbm_sync_fence));
391
392                         if (fence_handle == NULL) {
393                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
394                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
395                                 close(data.fence);
396                         } else {
397                                 fence_handle->fd = data.fence;
398                                 fence = fence_handle;
399                         }
400                 }
401         } else {
402                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
403         }
404
405 done:
406         if (error)
407                 *error = ret;
408
409         _tbm_sync_mutex_unlock();
410
411         return fence;
412 }
413
414 tbm_sync_error_e
415 tbm_sync_fence_destroy(tbm_sync_fence_h fence)
416 {
417         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
418
419         _tbm_sync_mutex_lock();
420
421         /* check the tbm_sync capability */
422         ret = _tbm_sync_check_capability();;
423         if (ret != TBM_SYNC_ERROR_NONE)
424                 goto done;
425
426         if (fence) {
427                 struct _tbm_sync_fence *fence_handle = fence;
428
429                 if (fence_handle->fd != -1)
430                         close(fence_handle->fd);
431                 free(fence);
432         }
433
434 done:
435         _tbm_sync_mutex_unlock();
436
437         return ret;
438 }
439
440 tbm_sync_error_e
441 tbm_sync_fence_wait(tbm_sync_fence_h fence, int timeout)
442 {
443         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
444
445         _tbm_sync_mutex_lock();
446
447         /* check the tbm_sync capability */
448         ret = _tbm_sync_check_capability();;
449         if (ret != TBM_SYNC_ERROR_NONE)
450                 goto done;
451
452         if (fence) {
453                 struct _tbm_sync_fence *fence_handle = fence;
454                 __s32 to = timeout;
455
456                 if (ioctl(fence_handle->fd, SYNC_IOC_WAIT, &to) == -1) {
457                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
458                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence wait failed", errno, strerror(errno));
459                 }
460         } else {
461                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
462         }
463
464 done:
465         _tbm_sync_mutex_unlock();
466
467         return ret;
468 }
469
470 tbm_sync_fence_h
471 tbm_sync_fence_merge(tbm_sync_fence_h fence1, tbm_sync_fence_h fence2, const char *name, tbm_sync_error_e *error)
472 {
473         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
474         tbm_sync_fence_h fence = NULL;
475
476         _tbm_sync_mutex_lock();
477
478         /* check the tbm_sync capability */
479         ret = _tbm_sync_check_capability();;
480         if (ret != TBM_SYNC_ERROR_NONE)
481                 goto done;
482
483         if (fence1 && fence2) {
484                 struct _tbm_sync_fence *fence_handle1 = fence1;
485                 struct _tbm_sync_fence *fence_handle2 = fence2;
486
487                 struct sync_merge_data {
488                         __s32 fd2;
489                         char name[32];
490                         __s32 fence;
491                 } data;
492
493                 data.fd2 = fence_handle2->fd;
494                 strncpy(data.name, name ? name : "", 32);
495                 data.name[31] = '\0';
496
497                 if (ioctl(fence_handle1->fd, SYNC_IOC_MERGE, &data) == -1) {
498                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
499                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence merge failed",
500                                           errno, strerror(errno));
501                 } else {
502                         struct _tbm_sync_fence *fence_handle =
503                                 calloc(1, sizeof(struct _tbm_sync_fence));
504
505                         if (fence_handle == NULL) {
506                                 ret = TBM_SYNC_ERROR_INVALID_OPERATION;
507                                 TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
508                                 close(data.fence);
509                         } else {
510                                 fence_handle->fd = data.fence;
511                         }
512                 }
513         } else {
514                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
515         }
516
517 done:
518         if (error)
519                 *error = ret;
520
521         _tbm_sync_mutex_unlock();
522
523         return fence;
524 }
525
526 unsigned int
527 tbm_sync_fence_get_count_val(tbm_sync_fence_h fence, tbm_sync_error_e *error)
528 {
529         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
530         unsigned int count_val = 0;
531
532         _tbm_sync_mutex_lock();
533
534         /* check the tbm_sync capability */
535         ret = _tbm_sync_check_capability();;
536         if (ret != TBM_SYNC_ERROR_NONE)
537                 goto done;
538
539         /* TODO: sync_fence_get_count_val */
540
541 done:
542         if (error)
543                 *error = ret;
544
545         _tbm_sync_mutex_unlock();
546
547         return count_val;
548 }
549
550 tbm_sync_fence_h
551 tbm_sync_fence_import(int fd, tbm_sync_error_e *error)
552 {
553         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
554         tbm_sync_fence_h fence = NULL;
555         int new_fd;
556
557         _tbm_sync_mutex_lock();
558
559         /* check the tbm_sync capability */
560         ret = _tbm_sync_check_capability();;
561         if (ret != TBM_SYNC_ERROR_NONE)
562                 goto done;
563
564         if (fd < 0) {
565                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
566                 goto done;
567         }
568
569         new_fd = dup(fd);
570         if (new_fd < 0) {
571                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
572                 TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence dup failed",
573                                   errno, strerror(errno));
574         } else {
575                 struct _tbm_sync_fence *fence_handle =
576                         calloc(1, sizeof(struct _tbm_sync_fence));
577                 int fd_flag;
578
579                 if ((fd_flag = fcntl(new_fd, F_GETFD, 0)) != -1) {
580                         fd_flag |= FD_CLOEXEC;
581                         fd_flag = fcntl(new_fd, F_SETFD, fd_flag);
582                 } else {
583                         TBM_LOG_W("%s\n", "TBM_SYNC fcntl failed");
584                 }
585
586                 if (fence_handle == NULL) {
587                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
588                         TBM_LOG_E("%s\n", "TBM_SYNC calloc failed");
589                         close(new_fd);
590                 } else {
591                         fence_handle->fd = fd;
592                         fence = fence_handle;
593                 }
594         }
595
596 done:
597         if (error)
598                 *error = ret;
599
600         _tbm_sync_mutex_unlock();
601
602         return fence;
603 }
604
605 int
606 tbm_sync_fence_export(tbm_sync_fence_h fence, tbm_sync_error_e *error)
607 {
608         tbm_sync_error_e ret = TBM_SYNC_ERROR_NONE;
609         int fd = -1;
610
611         _tbm_sync_mutex_lock();
612
613         /* check the tbm_sync capability */
614         ret = _tbm_sync_check_capability();;
615         if (ret != TBM_SYNC_ERROR_NONE)
616                 goto done;
617
618         if (fence) {
619                 struct _tbm_sync_fence *fence_handle = fence;
620                 int fd_flag;
621
622                 fd = dup(fence_handle->fd);
623                 if (fd == -1) {
624                         ret = TBM_SYNC_ERROR_INVALID_OPERATION;
625                         TBM_LOG_E("%s:%d(%s)\n", "TBM_SYNC fence dup failed",
626                                           errno, strerror(errno));
627                 } else {
628                         if ((fd_flag = fcntl(fd, F_GETFD, 0)) != -1) {
629                                 fd_flag |= FD_CLOEXEC;
630                                 fd_flag = fcntl(fd, F_SETFD, fd_flag);
631                         } else {
632                                 TBM_LOG_W("%s\n", "TBM_SYNC fcntl failed");
633                         }
634                 }
635
636         } else {
637                 ret = TBM_SYNC_ERROR_INVALID_PARAMETER;
638         }
639
640 done:
641         if (error)
642                 *error = ret;
643
644         _tbm_sync_mutex_unlock();
645
646         return fd;
647 }