_tdm_display_destroy_caps_output(&private_output->caps);
+ if (private_output->dpms_changed_timer)
+ tdm_event_loop_source_remove(private_output->dpms_changed_timer);
+
private_output->stamp = 0;
free(private_output);
}
return;
}
+ /* dont move the position of lock/unlock. all resource should be protected
+ * during destroying. after tdm_event_loop_deinit, we don't worry about thread
+ * things because it's finalized.
+ */
_pthread_mutex_lock(&private_display->lock);
-
tdm_event_loop_deinit(private_display);
+ _pthread_mutex_unlock(&private_display->lock);
_tdm_display_destroy_private_display(private_display);
_tdm_display_unload_module(private_display);
tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
- _pthread_mutex_unlock(&private_display->lock);
-
pthread_mutex_destroy(&private_display->lock);
free(private_display);
g_private_display = NULL;
private_output = private_layer->private_output; \
private_display = private_output->private_display
-INTERN tdm_error
-_tdm_display_lock(tdm_display *dpy, const char *func)
-{
- tdm_private_display *private_display = (tdm_private_display*)dpy;
- int ret;
-
- if (tdm_debug_mutex)
- TDM_INFO("mutex lock: %s", func);
-
- ret = pthread_mutex_trylock(&private_display->lock);
- if (ret < 0) {
- if (ret == EBUSY)
- TDM_ERR("mutex lock busy: %s", func);
- else
- TDM_ERR("mutex lock failed: %s(%m)", func);
- return TDM_ERROR_OPERATION_FAILED;
- }
-
- pthread_mutex_lock(&tdm_mutex_check_lock);
- tdm_mutex_locked = 1;
- pthread_mutex_unlock(&tdm_mutex_check_lock);
-
- return TDM_ERROR_NONE;
-}
-
-INTERN void
-_tdm_display_unlock(tdm_display *dpy, const char *func)
-{
- tdm_private_display *private_display = (tdm_private_display*)dpy;
-
- if (tdm_debug_mutex)
- TDM_INFO("mutex unlock: %s", func);
-
- pthread_mutex_lock(&tdm_mutex_check_lock);
- tdm_mutex_locked = 0;
- pthread_mutex_unlock(&tdm_mutex_check_lock);
-
- pthread_mutex_unlock(&private_display->lock);
-}
-
EXTERN tdm_error
tdm_display_get_capabilities(tdm_display *dpy,
tdm_display_capability *capabilities)
_pthread_mutex_lock(&private_display->lock);
if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
- TDM_ERR("output(%d) dpms: %s", private_output->pipe,
+ TDM_WRN("output(%d) dpms: %s", private_output->pipe,
tdm_dpms_str(private_output->current_dpms_value));
_pthread_mutex_unlock(&private_display->lock);
- return TDM_ERROR_BAD_REQUEST;
+ return TDM_ERROR_DPMS_OFF;
}
func_output = &private_display->func_output;
TDM_ERR("output(%d) dpms: %s", private_output->pipe,
tdm_dpms_str(private_output->current_dpms_value));
_pthread_mutex_unlock(&private_display->lock);
- return TDM_ERROR_BAD_REQUEST;
+ return TDM_ERROR_DPMS_OFF;
}
ret = _tdm_output_commit(output, sync, func, user_data);
return ret;
}
+static tdm_error
+_tdm_output_dpms_changed_timeout(void *user_data)
+{
+ tdm_private_output *private_output = user_data;
+ tdm_value value;
+
+ value.u32 = private_output->current_dpms_value;
+ tdm_output_call_change_handler_internal(private_output,
+ &private_output->change_handler_list_sub,
+ TDM_OUTPUT_CHANGE_DPMS,
+ value, 0);
+
+ return TDM_ERROR_NONE;
+}
+
EXTERN tdm_error
tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
{
return TDM_ERROR_NONE;
}
+ if (!private_output->dpms_changed_timer) {
+ private_output->dpms_changed_timer =
+ tdm_event_loop_add_timer_handler(private_output->private_display,
+ _tdm_output_dpms_changed_timeout, private_output, NULL);
+ if (!private_output->dpms_changed_timer) {
+ TDM_ERR("can't create dpms timer!!");
+ _pthread_mutex_unlock(&private_display->lock);
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
func_output = &private_display->func_output;
if (!func_output->output_set_dpms) {
TDM_OUTPUT_CHANGE_DPMS,
value, 0);
- //TODO: safe? We can't take care of the user_data of callback functions.
- tdm_output_call_change_handler_internal(private_output,
- &private_output->change_handler_list_sub,
- TDM_OUTPUT_CHANGE_DPMS,
- value, 1);
+ if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) {
+ ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1);
+ if (ret != TDM_ERROR_NONE)
+ TDM_NEVER_GET_HERE();
+ }
}
_pthread_mutex_unlock(&private_display->lock);
if (!private_display->private_loop)
return;
+ /* after tdm_thread_deinit, we don't worry about thread things because it's finalized */
tdm_thread_deinit(private_display->private_loop);
+
+
+ _pthread_mutex_unlock(&private_display->lock);
tdm_server_deinit(private_display->private_loop);
if (private_display->private_loop->backend_source)
free(private_display->private_loop);
private_display->private_loop = NULL;
+
+ _pthread_mutex_lock(&private_display->lock);
}
INTERN void
} \
}
-#define TDM_NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **")
+#define TDM_NEVER_GET_HERE() TDM_WRN("** NEVER GET HERE **")
#define TDM_SNPRINTF(p, len, fmt, ARG...) \
do { \
struct list_head change_handler_list_sub;
void **layers_ptr;
+
+ /* TODO: temp solution for handling DPMS things in sub-htread */
+ tdm_event_loop_source *dpms_changed_timer;
};
struct _tdm_private_layer {
static inline int TDM_MUTEX_IS_LOCKED(void)
{
int ret;
+ /* if thread is not running, we don't need to consider mutex things. */
+ if (!tdm_thread_is_running())
+ return 1;
pthread_mutex_lock(&tdm_mutex_check_lock);
ret = (tdm_mutex_locked == 1);
pthread_mutex_unlock(&tdm_mutex_check_lock);
return ret;
}
-tdm_error
-_tdm_display_lock(tdm_display *dpy, const char *func);
-void
-_tdm_display_unlock(tdm_display *dpy, const char *func);
-
-#define tdm_display_lock(dpy) _tdm_display_lock(dpy, __FUNCTION__)
-#define tdm_display_unlock(dpy) _tdm_display_unlock(dpy, __FUNCTION__)
+#define tdm_display_lock(dpy) _pthread_mutex_lock(&((tdm_private_display *)dpy)->lock)
+#define tdm_display_unlock(dpy) _pthread_mutex_unlock(&((tdm_private_display *)dpy)->lock)
tdm_error
tdm_display_update_output(tdm_private_display *private_display,
* However, the internal function which does lock/unlock the mutex of
* private_display in itself can be called.
* - DO NOT use the tdm_private_display structure here.
+ * - The callback function things can be called in main thread.
*/
struct _tdm_private_server {
INTERN void
tdm_thread_deinit(tdm_private_loop *private_loop)
{
+ tdm_private_display *private_display;
+
TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
if (!private_loop->private_thread)
return;
pthread_cancel(private_loop->private_thread->event_thread);
+
+ private_display = private_loop->dpy;
+
+ /* before falling into the block of pthread_join, we have to unlock the mutex
+ * for subthread to use the mutex.
+ */
+ _pthread_mutex_unlock(&private_display->lock);
pthread_join(private_loop->private_thread->event_thread, NULL);
+ _pthread_mutex_lock(&private_display->lock);
if (private_loop->private_thread->pipe[0] >= 0)
close(private_loop->private_thread->pipe[0]);
#include "tdm_list.h"
/* CAUTION:
- * - tdm vblank doesn't care about thread things.
- * - DO NOT use the TDM internal functions here.
- * However, the internal function which does lock/unlock the mutex of
- * private_display in itself can be called.
- * - DO NOT use the tdm_private_display structure here.
+ * tdm vblank doesn't care about thread things.
+ * However, to use tdm_event_loop_xxx functions, have to use the internal function.
+ * So need to lock/unlock the mutex of private_display.
*/
/* TDM vblank
#endif
if (private_vblank->SW_timer) {
- if (tdm_display_lock(private_vblank->dpy) == TDM_ERROR_NONE) {
- tdm_event_loop_source_remove(private_vblank->SW_timer);
- tdm_display_unlock(private_vblank->dpy);
- }
+ tdm_display_lock(private_vblank->dpy);
+ tdm_event_loop_source_remove(private_vblank->SW_timer);
+ tdm_display_unlock(private_vblank->dpy);
}
tdm_output_remove_change_handler(private_vblank->output,
_tdm_vblank_cb_vblank_HW, wait_info);
if (ret != TDM_ERROR_NONE) {
- VER("wait(%p) failed", wait_info);
+ VWR("wait(%p) failed", wait_info);
LIST_DEL(&wait_info->link);
return ret;
}
VDB("wait(%p) curr(%4lu) target(%4lu) ms_delay(%d)",
first_wait_info, curr, target, ms_delay);
- ret = tdm_display_lock(private_vblank->dpy);
- TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
+ tdm_display_lock(private_vblank->dpy);
if (!private_vblank->SW_timer) {
private_vblank->SW_timer =
if (do_wait) {
ret = tdm_output_wait_vblank(private_vblank->output, 1, 0,
_tdm_vblank_cb_vblank_SW_first, wait_info);
+ if (ret == TDM_ERROR_DPMS_OFF) {
+ TDM_WRN("use SW");
+ goto use_sw;
+ }
if (ret != TDM_ERROR_NONE) {
LIST_DEL(&wait_info->link);
return ret;
return TDM_ERROR_NONE;
}
+use_sw:
TDM_RETURN_VAL_IF_FAIL(wait_info->target_sec > 0, TDM_ERROR_OPERATION_FAILED);
_tdm_vblank_insert_wait(wait_info, &private_vblank->SW_wait_list);
_tdm_vblank_calculate_target(wait_info);
- if (private_vblank->HW_enable)
+ if (private_vblank->HW_enable) {
ret = _tdm_vblank_wait_HW(wait_info);
+ if (ret == TDM_ERROR_DPMS_OFF) {
+ TDM_WRN("try to use SW");
+ ret = _tdm_vblank_wait_SW(wait_info);
+ }
+ }
else
ret = _tdm_vblank_wait_SW(wait_info);