extern "C" {
#endif
+#include <time.h>
+#include <sys/syscall.h>
+
+
/**
* @file tdm_log.h
* @brief The header file to print logs in frontend and backend modules
#ifdef TDM_CONFIG_DLOG
#include <dlog.h>
-#include <time.h>
#ifdef LOG_TAG
#undef LOG_TAG
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
LOGD("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args); \
- printf("[TDM_DBG][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_DBG][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_INFO(fmt, args...) \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
LOGI("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args); \
- printf("[TDM_INF][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_INF][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_WRN(fmt, args...) \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
LOGI("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args); \
- printf("[TDM_WRN][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_WRN][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_ERR(fmt, args...) \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
LOGE("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args); \
- printf("[TDM_ERR][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_ERR][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#else /* TDM_CONFIG_DLOG */
#include <stdio.h>
-#include <time.h>
#define TDM_DBG(fmt, args...) \
if (tdm_debug) \
do { \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
- printf("[TDM_DBG][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_DBG][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_INFO(fmt, args...) \
do { \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
- printf("[TDM_INF][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_INF][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_WRN(fmt, args...) \
do { \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
- printf("[TDM_WRN][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_WRN][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#define TDM_ERR(fmt, args...) \
do { \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
- printf("[TDM_ERR][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec, \
- (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+ printf("[TDM_ERR][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
} while (0);
#endif /* TDM_CONFIG_DLOG */
libtdm_la_SOURCES = \
tdm_backend.c \
tdm_event.c \
+ tdm_thread.c \
tdm_helper.c \
tdm_buffer.c \
tdm_display.c \
return NULL;
}
+INTERN tdm_private_output *
+tdm_display_find_output_stamp(tdm_private_display *private_display,
+ unsigned long stamp)
+{
+ tdm_private_output *private_output = NULL;
+
+ LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
+ if (private_output->stamp == stamp)
+ return private_output;
+ }
+
+ return NULL;
+}
+
static void
_tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
{
_tdm_display_destroy_caps_output(&private_output->caps);
+ private_output->stamp = 0;
free(private_output);
}
return ret;
}
-static void
-_tdm_output_cb_status(tdm_output *output, tdm_output_conn_status status,
- void *user_data)
+INTERN void
+tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
+ void *user_data)
{
+ tdm_private_display *private_display;
tdm_private_output *private_output = user_data;
tdm_value value;
TDM_RETURN_IF_FAIL(private_output);
+ private_display = private_output->private_display;
+
+ if (!tdm_thread_in_display_thread(private_display)) {
+ tdm_thread_cb_output_status output_status;
+ tdm_error ret;
+
+ output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS;
+ output_status.base.length = sizeof output_status;
+ output_status.output_stamp = private_output->stamp;
+ output_status.status = status;
+ output_status.user_data = user_data;
+
+ ret = tdm_thread_send_cb(private_display, &output_status.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return;
+ }
+
value.u32 = status;
tdm_output_call_change_handler_internal(private_output,
TDM_OUTPUT_CHANGE_CONNECTION,
private_output = calloc(1, sizeof(tdm_private_output));
TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
+ private_output->stamp = tdm_helper_get_time_in_millis();
+ while (tdm_display_find_output_stamp(private_display, private_output->stamp))
+ private_output->stamp++;
+
LIST_ADD(&private_output->link, &private_display->output_list);
+
private_output->private_display = private_display;
private_output->output_backend = output_backend;
private_output->pipe = pipe;
if (func_output->output_set_status_handler) {
private_output->regist_change_cb = 1;
ret = func_output->output_set_status_handler(output_backend,
- _tdm_output_cb_status,
+ tdm_output_cb_status,
private_output);
if (ret != TDM_ERROR_NONE)
goto failed_update;
LIST_INITHEAD(&private_display->output_list);
LIST_INITHEAD(&private_display->pp_list);
+ LIST_INITHEAD(&private_display->capture_list);
if (!only_display) {
ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
int tdm_debug;
int tdm_debug_buffer;
+int tdm_debug_thread;
int tdm_debug_mutex;
static tdm_private_display *g_private_display;
if (debug && (strstr(debug, "1")))
tdm_debug_buffer = 1;
+ debug = getenv("TDM_DEBUG_THREAD");
+ if (debug && (strstr(debug, "1")))
+ tdm_debug_thread = 1;
+
debug = getenv("TDM_DEBUG_MUTEX");
if (debug && (strstr(debug, "1")))
tdm_debug_mutex = 1;
ret = tdm_event_init(private_display);
if (ret != TDM_ERROR_NONE)
- goto failed_load;
+ goto failed_event;
+
+ ret = tdm_thread_init(private_display);
+ if (ret != TDM_ERROR_NONE)
+ goto failed_thread;
ret = _tdm_display_load_module(private_display);
if (ret != TDM_ERROR_NONE)
if (ret != TDM_ERROR_NONE)
goto failed_update;
- tdm_event_create_main_source(private_display);
+ tdm_event_create_backend_source(private_display);
private_display->init_count = 1;
failed_update:
_tdm_display_unload_module(private_display);
failed_load:
+ tdm_thread_deinit(private_display);
+failed_thread:
+ tdm_event_deinit(private_display);
+failed_event:
pthread_mutex_destroy(&private_display->lock);
failed_mutex_init:
free(private_display);
_pthread_mutex_lock(&private_display->lock);
+ tdm_thread_deinit(private_display);
+ tdm_event_deinit(private_display);
+
_tdm_display_destroy_private_display(private_display);
_tdm_display_unload_module(private_display);
- tdm_event_deinit(private_display);
tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
return TDM_ERROR_NONE;
}
-static void
-_tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
- void *user_data)
+INTERN void
+tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
+ void *user_data)
{
tdm_private_capture *private_capture = user_data;
tdm_private_display *private_display = private_capture->private_display;
int lock_after_cb_done = 0;
int ret;
+ if (!tdm_thread_in_display_thread(private_display)) {
+ tdm_thread_cb_capture_done capture_done;
+ tdm_error ret;
+
+ capture_done.base.type = TDM_THREAD_CB_PP_DONE;
+ capture_done.base.length = sizeof capture_done;
+ capture_done.capture_stamp = private_capture->stamp;
+ capture_done.buffer = buffer;
+ capture_done.user_data = user_data;
+
+ ret = tdm_thread_send_cb(private_display, &capture_done.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return;
+ }
+
if (tdm_debug_buffer)
TDM_INFO("capture(%p) done: %p", private_capture, buffer);
}
INTERN tdm_private_capture *
+tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp)
+{
+ tdm_private_capture *private_capture = NULL;
+
+ LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
+ if (private_capture->stamp == stamp)
+ return private_capture;
+ }
+
+ return NULL;
+}
+
+INTERN tdm_private_capture *
tdm_capture_create_output_internal(tdm_private_output *private_output,
tdm_error *error)
{
}
ret = func_capture->capture_set_done_handler(capture_backend,
- _tdm_caputre_cb_done, private_capture);
+ tdm_capture_cb_done, private_capture);
if (ret != TDM_ERROR_NONE) {
TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
func_capture->capture_destroy(capture_backend);
return NULL;
}
+ private_capture->stamp = tdm_helper_get_time_in_millis();
+ while (tdm_capture_find_stamp(private_display, private_capture->stamp))
+ private_capture->stamp++;
+
LIST_ADD(&private_capture->link, &private_output->capture_list);
+ LIST_ADD(&private_capture->display_link, &private_display->capture_list);
+
private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
private_capture->private_display = private_display;
private_capture->private_output = private_output;
return NULL;
}
- LIST_ADD(&private_capture->link, &private_output->capture_list);
+ private_capture->stamp = tdm_helper_get_time_in_millis();
+ while (tdm_capture_find_stamp(private_display, private_capture->stamp))
+ private_capture->stamp++;
+
+ LIST_ADD(&private_capture->link, &private_layer->capture_list);
+ LIST_ADD(&private_capture->display_link, &private_display->capture_list);
+
private_capture->target = TDM_CAPTURE_TARGET_LAYER;
private_capture->private_display = private_display;
private_capture->private_output = private_output;
return;
LIST_DEL(&private_capture->link);
+ LIST_DEL(&private_capture->display_link);
func_capture = &private_capture->private_display->func_capture;
func_capture->capture_destroy(private_capture->capture_backend);
}
}
+ private_capture->stamp = 0;
free(private_capture);
}
_pthread_mutex_lock(&private_display->lock);
- *fd = tdm_event_get_fd(private_display);
+ if (private_display->private_thread)
+ *fd = tdm_thread_get_fd(private_display);
+ else
+ *fd = tdm_event_get_fd(private_display);
_pthread_mutex_unlock(&private_display->lock);
EXTERN tdm_error
tdm_display_handle_events(tdm_display *dpy)
{
+ struct pollfd fds;
+ int fd = -1;
+
DISPLAY_FUNC_ENTRY();
+ ret = tdm_display_get_fd(dpy, &fd);
+ TDM_RETURN_VAL_IF_FAIL(fd >= 0, ret);
+
+ fds.events = POLLIN;
+ fds.fd = fd;
+ fds.revents = 0;
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) polling in", fd);
+
+ while (poll(&fds, 1, -1) < 0) {
+ if (errno == EBUSY) /* normal case */
+ continue;
+ else {
+ TDM_ERR("poll failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) polling out", fd);
+
_pthread_mutex_lock(&private_display->lock);
- ret = tdm_event_dispatch(private_display);
+ if (private_display->private_thread)
+ ret = tdm_thread_handle_cb(private_display);
+ else
+ ret = tdm_event_dispatch(private_display);
_pthread_mutex_unlock(&private_display->lock);
return ret;
}
-static void
-_tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+INTERN void
+tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
tdm_private_vblank_handler *vblank_handler = user_data;
tdm_private_display *private_display;
private_display = vblank_handler->private_output->private_display;
+ if (!tdm_thread_in_display_thread(private_display)) {
+ tdm_thread_cb_output_vblank output_vblank;
+ tdm_error ret;
+
+ output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
+ output_vblank.base.length = sizeof output_vblank;
+ output_vblank.output_stamp = vblank_handler->private_output->stamp;
+ output_vblank.sequence = sequence;
+ output_vblank.tv_sec = tv_sec;
+ output_vblank.tv_usec = tv_usec;
+ output_vblank.user_data = user_data;
+
+ ret = tdm_thread_send_cb(private_display, &output_vblank.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return;
+ }
+
if (vblank_handler->func) {
_pthread_mutex_unlock(&private_display->lock);
vblank_handler->func(vblank_handler->private_output, sequence,
free(vblank_handler);
}
-static void
-_tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
- unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+INTERN void
+tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
tdm_private_commit_handler *commit_handler = user_data;
tdm_private_display *private_display;
private_output = commit_handler->private_output;
private_display = private_output->private_display;
+ if (!tdm_thread_in_display_thread(private_display)) {
+ tdm_thread_cb_output_commit output_commit;
+ tdm_error ret;
+
+ output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
+ output_commit.base.length = sizeof output_commit;
+ output_commit.output_stamp = private_output->stamp;
+ output_commit.sequence = sequence;
+ output_commit.tv_sec = tv_sec;
+ output_commit.tv_usec = tv_usec;
+ output_commit.user_data = user_data;
+
+ ret = tdm_thread_send_cb(private_display, &output_commit.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return;
+ }
+
LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
if (!private_layer->waiting_buffer)
continue;
if (!private_output->regist_vblank_cb) {
private_output->regist_vblank_cb = 1;
ret = func_output->output_set_vblank_handler(private_output->output_backend,
- _tdm_output_cb_vblank);
+ tdm_output_cb_vblank);
}
_pthread_mutex_unlock(&private_display->lock);
if (!private_output->regist_commit_cb) {
private_output->regist_commit_cb = 1;
ret = func_output->output_set_commit_handler(private_output->output_backend,
- _tdm_output_cb_commit);
+ tdm_output_cb_commit);
}
return ret;
struct _tdm_private_event {
struct wl_display *wl_display;
struct wl_event_loop *event_loop;
- tdm_event_source *main_source;
+
+ int backend_fd;
+ tdm_event_source *backend_source;
+
+ struct wl_display *wl_display2;
+ struct wl_event_loop *event_loop2;
};
typedef struct _tdm_event_source_base
_tdm_event_main_fd_handler(int fd, tdm_event_mask mask, void *user_data)
{
tdm_private_display *private_display = (tdm_private_display*)user_data;
+ tdm_private_event *private_event;
tdm_func_display *func_display;
TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED);
+ TDM_RETURN_VAL_IF_FAIL(private_display->private_event != NULL, TDM_ERROR_OPERATION_FAILED);
+
+ private_event = private_display->private_event;
+
+ if (tdm_debug_thread)
+ TDM_INFO("backend fd(%d) event happens", private_event->backend_fd);
func_display = &private_display->func_display;
if (!func_display->display_handle_events)
return TDM_ERROR_OUT_OF_MEMORY;
}
+ private_event->backend_fd = -1;
+
private_event->wl_display = wl_display_create();
if (!private_event->wl_display) {
TDM_ERR("creating a wayland display failed");
return TDM_ERROR_OUT_OF_MEMORY;
}
+ TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_event->event_loop));
+
+ private_event->wl_display2 = wl_display_create();
+ if (!private_event->wl_display2) {
+ TDM_ERR("creating a wayland display2 failed");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ private_event->event_loop2 = wl_display_get_event_loop(private_event->wl_display2);
+ if (!private_event->event_loop2) {
+ TDM_ERR("no event loop2");
+ wl_display_destroy(private_event->wl_display2);
+ private_event->wl_display2 = NULL;
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
private_display->private_event = private_event;
return TDM_ERROR_NONE;
if (!private_display->private_event)
return;
- if (private_display->private_event->main_source)
- tdm_event_source_remove(private_display->private_event->main_source);
+ if (private_display->private_event->backend_source)
+ tdm_event_source_remove(private_display->private_event->backend_source);
if (private_display->private_event->wl_display)
wl_display_destroy(private_display->private_event->wl_display);
}
INTERN void
-tdm_event_create_main_source(tdm_private_display *private_display)
+tdm_event_create_backend_source(tdm_private_display *private_display)
{
tdm_private_event *private_event = private_display->private_event;
tdm_func_display *func_display;
return;
}
- private_event->main_source =
+ private_event->backend_source =
tdm_event_add_fd_handler(private_display, fd, TDM_EVENT_READABLE,
_tdm_event_main_fd_handler, private_display,
&ret);
- if (!private_event->main_source) {
- TDM_ERR("no main event source");
+ if (!private_event->backend_source) {
+ TDM_ERR("no backend fd(%d) source", fd);
return;
}
- TDM_INFO("main event source created");
+ private_event->backend_fd = fd;
+
+ TDM_INFO("backend fd(%d) source created", private_event->backend_fd);
}
INTERN int
TDM_RETURN_VAL_IF_FAIL(private_event->event_loop != NULL, TDM_ERROR_OPERATION_FAILED);
- if (wl_event_loop_dispatch(private_event->event_loop, 0) < 0) {
+ if (tdm_debug_thread)
+ TDM_INFO("dispatch");
+
+ /* Don't set timeout to -1. It can make deadblock by two mutex locks.
+ * If need to set -1, use poll() and call tdm_event_dispatch() after
+ * escaping polling.
+ */
+ if (wl_event_loop_dispatch(private_event->event_loop, 0) < 0)
TDM_ERR("dispatch failed");
- return TDM_ERROR_OPERATION_FAILED;
- }
return TDM_ERROR_NONE;
}
#include <tbm_surface.h>
#include <tbm_surface_internal.h>
#include <string.h>
+#include <time.h>
#include "tdm.h"
#include "tdm_private.h"
static const char *dump_prefix[2] = {"png", "yuv"};
+INTERN unsigned long
+tdm_helper_get_time_in_millis(void)
+{
+ struct timespec tp;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+ return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+
+ return 0;
+}
+
static void
_tdm_helper_dump_raw(const char *file, void *data1, int size1, void *data2,
int size2, void *data3, int size3)
return TDM_ERROR_NONE;
}
-static void
-_tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
- void *user_data)
+INTERN void
+tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
+ void *user_data)
{
tdm_private_pp *private_pp = user_data;
tdm_private_display *private_display = private_pp->private_display;
int lock_after_cb_done = 0;
int ret;
+ if (!tdm_thread_in_display_thread(private_display)) {
+ tdm_thread_cb_pp_done pp_done;
+ tdm_error ret;
+
+ pp_done.base.type = TDM_THREAD_CB_PP_DONE;
+ pp_done.base.length = sizeof pp_done;
+ pp_done.pp_stamp = private_pp->stamp;
+ pp_done.src = src;
+ pp_done.dst = dst;
+ pp_done.user_data = user_data;
+
+ ret = tdm_thread_send_cb(private_display, &pp_done.base);
+ TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+ return;
+ }
+
if (tdm_debug_buffer)
TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
}
INTERN tdm_private_pp *
+tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
+{
+ tdm_private_pp *private_pp = NULL;
+
+ LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
+ if (private_pp->stamp == stamp)
+ return private_pp;
+ }
+
+ return NULL;
+}
+
+INTERN tdm_private_pp *
tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
{
tdm_func_display *func_display;
return NULL;
}
- ret = func_pp->pp_set_done_handler(pp_backend, _tdm_pp_cb_done, private_pp);
+ ret = func_pp->pp_set_done_handler(pp_backend, tdm_pp_cb_done, private_pp);
if (ret != TDM_ERROR_NONE) {
TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
func_pp->pp_destroy(pp_backend);
return NULL;
}
+ private_pp->stamp = tdm_helper_get_time_in_millis();
+ while (tdm_pp_find_stamp(private_display, private_pp->stamp))
+ private_pp->stamp++;
+
LIST_ADD(&private_pp->link, &private_display->pp_list);
private_pp->private_display = private_display;
private_pp->pp_backend = pp_backend;
}
}
+ private_pp->stamp = 0;
free(private_pp);
}
#include <fcntl.h>
#include <dlfcn.h>
#include <dirent.h>
+#include <poll.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
#include <tbm_bufmgr.h>
#include <tbm_surface_queue.h>
extern int tdm_debug_buffer;
extern int tdm_debug_mutex;
+extern int tdm_debug_thread;
#undef EXTERN
#undef DEPRECATED
typedef struct _tdm_private_pp tdm_private_pp;
typedef struct _tdm_private_capture tdm_private_capture;
typedef struct _tdm_private_event tdm_private_event;
+typedef struct _tdm_private_thread tdm_private_thread;
typedef struct _tdm_private_vblank_handler tdm_private_vblank_handler;
typedef struct _tdm_private_commit_handler tdm_private_commit_handler;
typedef struct _tdm_private_change_handler tdm_private_change_handler;
/* output, pp list */
struct list_head output_list;
struct list_head pp_list;
+ struct list_head capture_list;
void **outputs_ptr;
/* for event handling */
tdm_private_event *private_event;
+
+ /* for own event thread */
+ tdm_private_thread *private_thread;
};
struct _tdm_private_output {
struct list_head link;
+ unsigned long stamp;
+
tdm_private_display *private_display;
tdm_caps_output caps;
struct _tdm_private_pp {
struct list_head link;
+ unsigned long stamp;
+
tdm_private_display *private_display;
tdm_pp *pp_backend;
struct _tdm_private_capture {
struct list_head link;
+ struct list_head display_link;
+
+ unsigned long stamp;
tdm_capture_target target;
struct list_head link;
} tdm_buffer_info;
+tdm_private_output *
+tdm_display_find_output_stamp(tdm_private_display *private_display,
+ unsigned long stamp);
+tdm_private_pp *
+tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp);
+tdm_private_capture *
+tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp);
+
+void
+tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+void
+tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+void
+tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
+ void *user_data);
+void
+tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
+ void *user_data);
+void
+tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
+ void *user_data);
+
void
tdm_output_call_change_handler_internal(tdm_private_output *private_output,
tdm_output_change_type type,
void
tdm_event_deinit(tdm_private_display *private_display);
void
-tdm_event_create_main_source(tdm_private_display *private_display);
+tdm_event_create_backend_source(tdm_private_display *private_display);
int
tdm_event_get_fd(tdm_private_display *private_display);
tdm_error
tdm_event_add_socket(tdm_private_display *private_display, const char *name);
+typedef enum {
+ TDM_THREAD_CB_NONE,
+ TDM_THREAD_CB_OUTPUT_COMMIT,
+ TDM_THREAD_CB_OUTPUT_VBLANK,
+ TDM_THREAD_CB_OUTPUT_STATUS,
+ TDM_THREAD_CB_PP_DONE,
+ TDM_THREAD_CB_CAPTURE_DONE,
+} tdm_thread_cb_type;
+
+typedef struct _tdm_thread_cb_base tdm_thread_cb_base;
+typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_commit;
+typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_vblank;
+typedef struct _tdm_thread_cb_output_status tdm_thread_cb_output_status;
+typedef struct _tdm_thread_cb_pp_done tdm_thread_cb_pp_done;
+typedef struct _tdm_thread_cb_capture_done tdm_thread_cb_capture_done;
+
+struct _tdm_thread_cb_base {
+ tdm_thread_cb_type type;
+ unsigned int length;
+};
+
+struct _tdm_thread_cb_output_vblank {
+ tdm_thread_cb_base base;
+ unsigned long output_stamp;
+ unsigned int sequence;
+ unsigned int tv_sec;
+ unsigned int tv_usec;
+ void *user_data;
+};
+
+struct _tdm_thread_cb_output_status {
+ tdm_thread_cb_base base;
+ unsigned long output_stamp;
+ tdm_output_conn_status status;
+ void *user_data;
+};
+
+struct _tdm_thread_cb_pp_done {
+ tdm_thread_cb_base base;
+ unsigned long pp_stamp;
+ tbm_surface_h src;
+ tbm_surface_h dst;
+ void *user_data;
+};
+
+struct _tdm_thread_cb_capture_done {
+ tdm_thread_cb_base base;
+ unsigned long capture_stamp;
+ tbm_surface_h buffer;
+ void *user_data;
+};
+
+tdm_error
+tdm_thread_init(tdm_private_display *private_display);
+void
+tdm_thread_deinit(tdm_private_display *private_display);
+int
+tdm_thread_get_fd(tdm_private_display *private_display);
+tdm_error
+tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base);
+tdm_error
+tdm_thread_handle_cb(tdm_private_display *private_display);
+int
+tdm_thread_in_display_thread(tdm_private_display *private_display);
+
+unsigned long
+tdm_helper_get_time_in_millis(void);
+
#define _pthread_mutex_lock(l) \
do {if (tdm_debug_mutex) TDM_INFO("mutex lock"); pthread_mutex_lock(l);} while (0)
#define _pthread_mutex_unlock(l) \
--- /dev/null
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+ JinYoung Jeon <jy0.jeon@samsung.com>,
+ Taeheon Kim <th908.kim@samsung.com>,
+ YoungJun Cho <yj44.cho@samsung.com>,
+ SooChan Lim <sc1.lim@samsung.com>,
+ Boram Park <sc1.lim@samsung.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/socket.h>
+
+#include "tdm.h"
+#include "tdm_private.h"
+#include "tdm_list.h"
+
+struct _tdm_private_thread {
+ pthread_t event_thread;
+ pthread_mutex_t event_mutex;
+
+ pid_t display_tid;
+ pid_t thread_tid;
+
+ /* 0: read, 1: write */
+ int pipe[2];
+};
+
+static void*
+_tdm_thread_main(void *data)
+{
+ tdm_private_display *private_display = (tdm_private_display*)data;
+ tdm_private_thread *private_thread;
+ int fd;
+ struct pollfd fds;
+ int ret;
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ private_thread = private_display->private_thread;
+ private_thread->thread_tid = syscall(SYS_gettid);
+
+ TDM_INFO("display_tid:%d, thread_tid: %d",
+ private_thread->display_tid, private_thread->thread_tid);
+
+ fd = tdm_event_get_fd(private_display);
+ if (fd < 0) {
+ TDM_ERR("couldn't get fd");
+ goto exit_thread;
+ }
+
+ fds.events = POLLIN;
+ fds.fd = fd;
+ fds.revents = 0;
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ while (1) {
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) polling in", fd);
+
+ ret = poll(&fds, 1, -1);
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) polling out", fd);
+
+ if (ret < 0) {
+ if (errno == EBUSY) /* normal case */
+ continue;
+ else {
+ TDM_ERR("poll failed: %m");
+ goto exit_thread;
+ }
+ }
+
+ if (tdm_debug_thread)
+ TDM_INFO("thread got events");
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ if (tdm_event_dispatch(private_display) < 0)
+ TDM_ERR("dispatch error");
+
+ _pthread_mutex_unlock(&private_display->lock);
+ }
+
+exit_thread:
+ pthread_exit(NULL);
+}
+
+INTERN tdm_error
+tdm_thread_init(tdm_private_display *private_display)
+{
+ tdm_private_thread *private_thread;
+ const char *thread;
+
+ if (private_display->private_thread)
+ return TDM_ERROR_NONE;
+
+ /* enable as default */
+ thread = getenv("TDM_THREAD");
+ if (thread && strstr(thread, "0")) {
+ TDM_INFO("not using a TDM event thread");
+ return TDM_ERROR_NONE;
+ }
+
+ private_thread = calloc(1, sizeof *private_thread);
+ if (!private_thread) {
+ TDM_ERR("alloc failed");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (pipe(private_thread->pipe) != 0) {
+ TDM_ERR("socketpair failed: %m");
+ free(private_thread);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ private_thread->display_tid = syscall(SYS_gettid);
+
+ pthread_mutex_init(&private_thread->event_mutex, NULL);
+ pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
+ private_display);
+
+ private_display->private_thread = private_thread;
+
+ TDM_INFO("using a TDM event thread. pipe(%d,%d)",
+ private_thread->pipe[0], private_thread->pipe[1]);
+
+ return TDM_ERROR_NONE;
+}
+
+INTERN void
+tdm_thread_deinit(tdm_private_display *private_display)
+{
+ if (!private_display->private_thread)
+ return;
+
+ pthread_cancel(private_display->private_thread->event_thread);
+ pthread_join(private_display->private_thread->event_thread, NULL);
+ pthread_mutex_destroy(&private_display->private_thread->event_mutex);
+
+ if (private_display->private_thread->pipe[0] >= 0)
+ close(private_display->private_thread->pipe[0]);
+ if (private_display->private_thread->pipe[1] >= 0)
+ close(private_display->private_thread->pipe[1]);
+
+ free(private_display->private_thread);
+ private_display->private_thread = NULL;
+
+ TDM_INFO("Finish a TDM event thread");
+}
+
+INTERN int
+tdm_thread_get_fd(tdm_private_display *private_display)
+{
+ tdm_private_thread *private_thread;
+
+ TDM_RETURN_VAL_IF_FAIL(private_display, -1);
+ TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, -1);
+
+ private_thread = private_display->private_thread;
+
+ return private_thread->pipe[0];
+}
+
+INTERN tdm_error
+tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base)
+{
+ tdm_private_thread *private_thread;
+ ssize_t len;
+
+ TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER);
+ TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
+ TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
+
+ private_thread = private_display->private_thread;
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) type(%d), length(%d)",
+ private_thread->pipe[1], base->type, base->length);
+
+ len = write(private_thread->pipe[1], base, base->length);
+ if (len != base->length) {
+ TDM_ERR("write failed (%d != %d): %m", len, base->length);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+INTERN tdm_error
+tdm_thread_handle_cb(tdm_private_display *private_display)
+{
+ tdm_private_thread *private_thread;
+ tdm_thread_cb_base *base;
+ char buffer[1024];
+ int len, i;
+
+ TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
+ TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
+
+ private_thread = private_display->private_thread;
+
+ len = read(private_thread->pipe[0], buffer, sizeof buffer);
+
+ if (tdm_debug_thread)
+ TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
+
+ if (len == 0)
+ return TDM_ERROR_NONE;
+
+ if (len < sizeof *base) {
+ TDM_NEVER_GET_HERE();
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ i = 0;
+ while (i < len) {
+ base = (tdm_thread_cb_base*)&buffer[i];
+ if (tdm_debug_thread)
+ TDM_INFO("type(%d), length(%d)", base->type, base->length);
+ switch (base->type) {
+ case TDM_THREAD_CB_OUTPUT_COMMIT:
+ {
+ tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base;
+ tdm_output *output_backend =
+ tdm_display_find_output_stamp(private_display, output_commit->output_stamp);
+ if (!output_backend) {
+ TDM_WRN("no output(%ld)", output_commit->output_stamp);
+ break;
+ }
+ tdm_output_cb_commit(output_backend, output_commit->sequence,
+ output_commit->tv_sec, output_commit->tv_usec,
+ output_commit->user_data);
+ break;
+ }
+ case TDM_THREAD_CB_OUTPUT_VBLANK:
+ {
+ tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base;
+ tdm_output *output_backend =
+ tdm_display_find_output_stamp(private_display, output_vblank->output_stamp);
+ if (!output_backend) {
+ TDM_WRN("no output(%ld)", output_vblank->output_stamp);
+ break;
+ }
+ tdm_output_cb_vblank(output_backend, output_vblank->sequence,
+ output_vblank->tv_sec, output_vblank->tv_usec,
+ output_vblank->user_data);
+ break;
+ }
+ case TDM_THREAD_CB_OUTPUT_STATUS:
+ {
+ tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base;
+ tdm_output *output_backend =
+ tdm_display_find_output_stamp(private_display, output_status->output_stamp);
+ if (!output_backend) {
+ TDM_WRN("no output(%ld)", output_status->output_stamp);
+ break;
+ }
+ tdm_output_cb_status(output_backend, output_status->status,
+ output_status->user_data);
+ break;
+ }
+ case TDM_THREAD_CB_PP_DONE:
+ {
+ tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
+ tdm_pp *pp_backend =
+ tdm_pp_find_stamp(private_display, pp_done->pp_stamp);
+ if (!pp_backend) {
+ TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
+ break;
+ }
+ tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
+ break;
+ }
+ case TDM_THREAD_CB_CAPTURE_DONE:
+ {
+ tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base;
+ tdm_capture *capture_backend =
+ tdm_capture_find_stamp(private_display, capture_done->capture_stamp);
+ if (!capture_backend) {
+ TDM_WRN("no capture(%ld)", capture_done->capture_stamp);
+ break;
+ }
+ tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
+ break;
+ }
+ default:
+ break;
+ }
+ i += base->length;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+INTERN int
+tdm_thread_in_display_thread(tdm_private_display *private_display)
+{
+ tdm_private_thread *private_thread;
+
+ TDM_RETURN_VAL_IF_FAIL(private_display, 1);
+
+ if (!private_display->private_thread)
+ return 1;
+
+ private_thread = private_display->private_thread;
+
+ return (private_thread->display_tid == syscall(SYS_gettid)) ? 1 : 0;
+}