| File: | /shared/playproj/i2c/src/dw/dw_status_events.c |
| Warning: | line 350, column 4 Declared variable-length array (VLA) has zero size |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /** @file dw_status_events.c */ | |||
| 2 | ||||
| 3 | // Copyright (C) 2024-2026 Sanford Rockowitz <rockowitz@minsoft.com> | |||
| 4 | // SPDX-License-Identifier: GPL-2.0-or-later | |||
| 5 | ||||
| 6 | #include "config.h" | |||
| 7 | ||||
| 8 | #include <assert.h> | |||
| 9 | #include <glib-2.0/glib.h> | |||
| 10 | ||||
| 11 | #include "public/ddcutil_types.h" | |||
| 12 | #include "public/ddcutil_c_api.h" | |||
| 13 | #include "public/ddcutil_status_codes.h" | |||
| 14 | ||||
| 15 | #include "util/debug_util.h" | |||
| 16 | #include "util/timestamp.h" | |||
| 17 | #include "util/traced_function_stack.h" | |||
| 18 | ||||
| 19 | #include "base/core.h" | |||
| 20 | #include "base/dw_base.h" | |||
| 21 | #include "base/sleep.h" | |||
| 22 | #include "base/rtti.h" | |||
| 23 | ||||
| 24 | #include "sysfs/sysfs_sys_drm_connector.h" | |||
| 25 | ||||
| 26 | #include "ddc/ddc_display_ref_reports.h" | |||
| 27 | #include "ddc/ddc_packet_io.h" | |||
| 28 | ||||
| 29 | #include "dw_common.h" | |||
| 30 | ||||
| 31 | #include "dw_status_events.h" | |||
| 32 | ||||
| 33 | ||||
| 34 | // Trace class for this file | |||
| 35 | static DDCA_Trace_Group TRACE_GROUP = DDCA_TRC_CONN; | |||
| 36 | ||||
| 37 | ||||
| 38 | /** Use a static_assert() to ensure that the allocated size of | |||
| 39 | * DDCA_Display_Status_Event is unchanged from that in a prior | |||
| 40 | * release. | |||
| 41 | */ | |||
| 42 | void assert_ddca_display_status_event_size_unchanged() { | |||
| 43 | typedef struct { | |||
| 44 | uint64_t timestamp_nanos; | |||
| 45 | DDCA_Display_Event_Type event_type; | |||
| 46 | DDCA_IO_Path io_path; | |||
| 47 | char connector_name[32]; | |||
| 48 | DDCA_Display_Ref dref; | |||
| 49 | void * unused[2]; | |||
| 50 | } DDCA_Display_Status_Event_2_1_4; | |||
| 51 | ||||
| 52 | static_assert_Static_assert(sizeof(DDCA_Display_Status_Event) == | |||
| 53 | sizeof(DDCA_Display_Status_Event_2_1_4), "ABI compatibility"); | |||
| 54 | } | |||
| 55 | ||||
| 56 | ||||
| 57 | // | |||
| 58 | // Thread that performs callbacks | |||
| 59 | // | |||
| 60 | ||||
| 61 | #ifdef USE_CALLBACK_QUEUE | |||
| 62 | GAsyncQueue * callback_queue = NULL((void*)0); | |||
| 63 | GMutex * callback_queue_mutex = NULL((void*)0); | |||
| 64 | ||||
| 65 | void dw_free_callback_queue_entry(Callback_Queue_Entry * entry) { | |||
| 66 | // free_display_status_event(entry->event); // ??? | |||
| 67 | free(entry); | |||
| 68 | } | |||
| 69 | ||||
| 70 | ||||
| 71 | GAsyncQueue * init_callback_queue() { | |||
| 72 | callback_queue = g_async_queue_new(); | |||
| 73 | return callback_queue; | |||
| 74 | } | |||
| 75 | ||||
| 76 | ||||
| 77 | void dw_put_callback_queue(DDCA_Display_Status_Callback_Func func, | |||
| 78 | DDCA_Display_Status_Event event) | |||
| 79 | { | |||
| 80 | bool_Bool debug = true1; | |||
| 81 | DBGTRC_STARTING(debug, DDCA_TRC_CONN, "event=%s, func=%p", display_status_event_repr_t(event), func)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (DDCA_TRC_CONN ), 0x08, __func__, 81, "dw_status_events.c", "Starting ""event=%s, func=%p" , display_status_event_repr_t(event), func); } while(0); | |||
| 82 | ||||
| 83 | Callback_Queue_Entry * entry = calloc(1, sizeof(Callback_Queue_Entry)); | |||
| 84 | entry->func = func; | |||
| 85 | entry->event = event; // or make copy? | |||
| 86 | g_async_queue_push(callback_queue, entry); | |||
| 87 | ||||
| 88 | DBGTRC_DONE(debug, DDCA_TRC_CONN, "")do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_CONN), 0x10, __func__, 88, "dw_status_events.c", "Done """); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 89 | } | |||
| 90 | ||||
| 91 | ||||
| 92 | Callback_Queue_Entry * next_callback_queue_entry() { | |||
| 93 | bool_Bool debug = true1; | |||
| 94 | DBGTRC_STARTING(debug, DDCA_TRC_CONN, "")do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (DDCA_TRC_CONN ), 0x08, __func__, 94, "dw_status_events.c", "Starting """); } while(0); | |||
| 95 | ||||
| 96 | int sleep_interval_millis = 200; // temp | |||
| 97 | int pop_interval_millis = 100; | |||
| 98 | uint64_t pop_interval_micros = MILLIS2MICROS(pop_interval_millis)(pop_interval_millis*(uint64_t)1000); | |||
| 99 | ||||
| 100 | Callback_Queue_Entry* cqe = NULL((void*)0); | |||
| 101 | while (!cqe && !terminate_watch_thread) { | |||
| 102 | cqe = g_async_queue_timeout_pop(callback_queue, pop_interval_micros); | |||
| 103 | sleep_millis(sleep_interval_millis); | |||
| 104 | } | |||
| 105 | ||||
| 106 | DBGTRC_DONE(debug, TRACE_GROUP, "Returning %p", cqe)do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 106, "dw_status_events.c", "Done " "Returning %p", cqe); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 107 | return cqe; | |||
| 108 | } | |||
| 109 | ||||
| 110 | ||||
| 111 | /** Function that runs in a thread to invoke user callback functions | |||
| 112 | * | |||
| 113 | * @param data Callback_Displays_Data struct | |||
| 114 | * @return ?? | |||
| 115 | */ | |||
| 116 | gpointer dw_callback_displays_func(gpointer data) { | |||
| 117 | bool_Bool debug = true1; | |||
| 118 | traced_function_stack_enabled = false0; | |||
| 119 | DBGTRC_STARTING(debug, TRACE_GROUP, "data=%p", data)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 119, "dw_status_events.c", "Starting ""data=%p" , data); } while(0); | |||
| 120 | Callback_Displays_Data* cdd = (Callback_Displays_Data *) data; | |||
| 121 | init_callback_queue(); | |||
| 122 | ||||
| 123 | while (true1) { | |||
| 124 | Callback_Queue_Entry * entry = next_callback_queue_entry(); | |||
| 125 | if (!entry) | |||
| 126 | break; | |||
| 127 | DBGTRC_DONE(debug, TRACE_GROUP, "Invoking callback for event %s",do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 128, "dw_status_events.c", "Done " "Invoking callback for event %s", display_status_event_repr_t (entry->event)); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0) | |||
| 128 | display_status_event_repr_t(entry->event))do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 128, "dw_status_events.c", "Done " "Invoking callback for event %s", display_status_event_repr_t (entry->event)); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 129 | entry->func(entry->event); | |||
| 130 | DBGTRC_DONE(debug, TRACE_GROUP, "Callback function for event %s complete",do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 131, "dw_status_events.c", "Done " "Callback function for event %s complete", display_status_event_repr_t (entry->event)); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0) | |||
| 131 | display_status_event_repr_t(entry->event))do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 131, "dw_status_events.c", "Done " "Callback function for event %s complete", display_status_event_repr_t (entry->event)); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 132 | } | |||
| 133 | ||||
| 134 | //clean up queue | |||
| 135 | dw_free_callback_displays_data(cdd); | |||
| 136 | ||||
| 137 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "terminating callback thread execution")dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 137, "dw_status_events.c" , " ""terminating callback thread execution"); | |||
| 138 | // g_thread_exit(NULL); // not needed | |||
| 139 | return NULL((void*)0); // avoid compiler warning | |||
| 140 | } | |||
| 141 | ||||
| 142 | #endif | |||
| 143 | ||||
| 144 | ||||
| 145 | STATICstatic void | |||
| 146 | free_callback_queue_entry(Callback_Queue_Entry* q) { | |||
| 147 | free(q); | |||
| 148 | } | |||
| 149 | ||||
| 150 | ||||
| 151 | /** Function that runs in a thread to invoke a single user callback function | |||
| 152 | * | |||
| 153 | * @param data Callback_Displays_Data struct | |||
| 154 | * @return NULL | |||
| 155 | */ | |||
| 156 | gpointer dw_execute_callback_func(gpointer data) { | |||
| 157 | bool_Bool debug = false0; | |||
| 158 | DBGTRC_STARTING(debug, TRACE_GROUP, "data=%p", data)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 158, "dw_status_events.c", "Starting ""data=%p" , data); } while(0); | |||
| 159 | ||||
| 160 | // set_debug_thread_tfs(true); // turn on traced function stack debug msgs for current thread | |||
| 161 | Callback_Queue_Entry * cqe = (Callback_Queue_Entry *) data; | |||
| 162 | ||||
| 163 | char * buf = g_strdup_printf("Invoking callback function %p for event %s in this thread "PRItid"[%6jd]", | |||
| 164 | cqe->func, display_status_event_repr_t(cqe->event), TID()(intmax_t) tid()); | |||
| 165 | DBGTRC_NOPREFIX(debug, TRACE_GROUP, "%s", buf)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x00, __func__, 165, "dw_status_events.c", " " "%s", buf); | |||
| 166 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "%s", buf)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("%s", buf); char prefix[100] = {0}; get_msg_decoration(prefix , 100, 1); syslog(syslog_priority, "%s%s%s", prefix, body, (tag_output ) ? " (N)" : "" ); free(body); } } } while(0); | |||
| 167 | free(buf); | |||
| 168 | ||||
| 169 | record_active_callback_thread(g_thread_self()); | |||
| 170 | ||||
| 171 | // in case the callback function calls an API function that resets the traced function stack: | |||
| 172 | GPtrArray* stashed = NULL((void*)0); | |||
| 173 | if (traced_function_stack_enabled) | |||
| 174 | stashed = stash_current_traced_function_stack(); | |||
| 175 | ||||
| 176 | cqe->func(cqe->event); | |||
| 177 | ||||
| 178 | // in case the callback function calls an API function that resets the traced function stack: | |||
| 179 | // if (traced_function_stack_enabled && current_traced_function_stack_size() == 0) | |||
| 180 | // push_traced_function(__func__); | |||
| 181 | if (stashed) | |||
| 182 | restore_current_traced_function_stack(stashed); | |||
| 183 | ||||
| 184 | remove_active_callback_thread(g_thread_self()); | |||
| 185 | ||||
| 186 | buf = g_strdup_printf("Callback function %p for event %s complete", | |||
| 187 | cqe->func, display_status_event_repr_t(cqe->event)); | |||
| 188 | free_callback_queue_entry(cqe); | |||
| 189 | ||||
| 190 | ddc_close_all_displays_for_current_thread(/*error_if_open=*/ true1); // in case client left some open | |||
| 191 | unlock_all_displays_for_current_thread(); // should never be needed | |||
| 192 | ||||
| 193 | DBGTRC_DONE(debug, TRACE_GROUP, "%s", buf)do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 193, "dw_status_events.c", "Done " "%s", buf); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 194 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "%s", buf)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("%s", buf); char prefix[100] = {0}; get_msg_decoration(prefix , 100, 1); syslog(syslog_priority, "%s%s%s", prefix, body, (tag_output ) ? " (N)" : "" ); free(body); } } } while(0); | |||
| 195 | if (traced_function_stack_enabled) | |||
| 196 | free_current_traced_function_stack(); | |||
| 197 | ||||
| 198 | free(buf); | |||
| 199 | return NULL((void*)0); // terminates thread | |||
| 200 | } | |||
| 201 | ||||
| 202 | ||||
| 203 | // | |||
| 204 | // Display Status Events | |||
| 205 | // | |||
| 206 | ||||
| 207 | GPtrArray* display_detection_callbacks = NULL((void*)0); | |||
| 208 | static GMutex callbacks_mutex; | |||
| 209 | ||||
| 210 | /** Registers a display status change event callback | |||
| 211 | * | |||
| 212 | * @param func function to register | |||
| 213 | * @retval DDCRC_OK | |||
| 214 | * @retval DDCRC_INVALID_OPERATION ddcutil not built with UDEV support, | |||
| 215 | * | |||
| 216 | * The function must be of type DDCA_Display_Detection_Callback_Func. | |||
| 217 | * It is not an error if the function is already registered. | |||
| 218 | */ | |||
| 219 | DDCA_Status dw_register_display_status_callback(DDCA_Display_Status_Callback_Func func) { | |||
| 220 | bool_Bool debug = false0; | |||
| 221 | DBGTRC_STARTING(debug, TRACE_GROUP, "func=%p", func)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 221, "dw_status_events.c", "Starting ""func=%p" , func); } while(0); | |||
| 222 | ||||
| 223 | DDCA_Status result = DDCRC_INVALID_OPERATION(-(3000 +14) ); | |||
| 224 | // if (check_all_video_adapters_implement_drm()) { // unnecessary, performed in caller | |||
| 225 | // uint64_t t0 = cur_realtime_nanosec(); | |||
| 226 | g_mutex_lock(&callbacks_mutex); | |||
| 227 | generic_register_callback(&display_detection_callbacks, func); | |||
| 228 | g_mutex_unlock(&callbacks_mutex); | |||
| 229 | // DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "generic_register_callback() took %"PRIu64" micoseconds", | |||
| 230 | // NANOS2MICROS(cur_realtime_nanosec()-t0) ); | |||
| 231 | result = DDCRC_OK0; | |||
| 232 | // } | |||
| 233 | ||||
| 234 | DBGTRC_RET_DDCRC(debug, TRACE_GROUP, result, "")do { dbgtrc_ret_ddcrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 234, "dw_status_events.c" , result, ""); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 235 | return result; | |||
| 236 | } | |||
| 237 | ||||
| 238 | ||||
| 239 | /** Unregisters a detection event callback function | |||
| 240 | * | |||
| 241 | * @param function of type DDCA_Display_Detection_Callback_func | |||
| 242 | * @retval DDCRC_OK normal return | |||
| 243 | * @retval DDCRC_NOT_FOUND function not in list of registered functions | |||
| 244 | * @retval DDCRC_INVALID_OPERATION ddcutil not built with UDEV support, | |||
| 245 | * or not all video devices support DRM | |||
| 246 | */ | |||
| 247 | DDCA_Status dw_unregister_display_status_callback(DDCA_Display_Status_Callback_Func func) { | |||
| 248 | bool_Bool debug = false0; | |||
| 249 | DBGTRC_STARTING(debug, TRACE_GROUP, "func=%p", func)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 249, "dw_status_events.c", "Starting ""func=%p" , func); } while(0); | |||
| 250 | ||||
| 251 | DDCA_Status result = DDCRC_INVALID_OPERATION(-(3000 +14) ); | |||
| 252 | if (check_all_video_adapters_implement_drm()) { | |||
| 253 | g_mutex_lock(&callbacks_mutex); | |||
| 254 | result = generic_unregister_callback(display_detection_callbacks, func); | |||
| 255 | g_mutex_unlock(&callbacks_mutex); | |||
| 256 | } | |||
| 257 | ||||
| 258 | DBGTRC_RET_DDCRC(debug, TRACE_GROUP, result, "")do { dbgtrc_ret_ddcrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 258, "dw_status_events.c" , result, ""); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 259 | return result; | |||
| 260 | } | |||
| 261 | ||||
| 262 | ||||
| 263 | DDCA_Display_Status_Event | |||
| 264 | dw_create_display_status_event( | |||
| 265 | DDCA_Display_Event_Type event_type, | |||
| 266 | const char * connector_name, | |||
| 267 | Display_Ref* dref, | |||
| 268 | DDCA_IO_Path io_path) | |||
| 269 | { | |||
| 270 | bool_Bool debug = false0; | |||
| 271 | DBGTRC_STARTING(debug, DDCA_TRC_NONE, "event_type=%d, connector_name=%s, dref=%p=%s, io_path=%s",do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (DDCA_TRC_NONE ), 0x08, __func__, 272, "dw_status_events.c", "Starting ""event_type=%d, connector_name=%s, dref=%p=%s, io_path=%s" , event_type, connector_name, dref, dref_reprx_t(dref), dpath_short_name_t (&io_path)); } while(0) | |||
| 272 | event_type, connector_name, dref, dref_reprx_t(dref), dpath_short_name_t(&io_path) )do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (DDCA_TRC_NONE ), 0x08, __func__, 272, "dw_status_events.c", "Starting ""event_type=%d, connector_name=%s, dref=%p=%s, io_path=%s" , event_type, connector_name, dref, dref_reprx_t(dref), dpath_short_name_t (&io_path)); } while(0); | |||
| 273 | assert(dref)((dref) ? (void) (0) : __assert_fail ("dref", "dw_status_events.c" , 273, __extension__ __PRETTY_FUNCTION__)); | |||
| 274 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "dref->flags = %s", interpret_dref_flags_t(dref->flags))dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 274, "dw_status_events.c" , " ""dref->flags = %s", interpret_dref_flags_t(dref ->flags)); | |||
| 275 | DDCA_Display_Status_Event evt; | |||
| 276 | memset(&evt, 0, sizeof(evt)); | |||
| 277 | evt.timestamp_nanos = elapsed_time_nanosec(); | |||
| 278 | evt.dref = dref_to_ddca_dref(dref); // 0 if dref == NULL | |||
| 279 | evt.event_type = event_type; | |||
| 280 | if (connector_name) | |||
| 281 | g_snprintf(evt.connector_name, sizeof(evt.connector_name), "%s", connector_name); | |||
| 282 | evt.io_path = (dref) ? dref->io_path : io_path; | |||
| 283 | if (event_type == DDCA_EVENT_DDC_ENABLED) | |||
| 284 | ASSERT_WITH_BACKTRACE(dref->flags&DREF_DDC_COMMUNICATION_WORKING)do { if ( !(dref->flags&0x0002) ) { show_backtrace(0); ((dref->flags&0x0002) ? (void) (0) : __assert_fail ("dref->flags&0x0002" , "dw_status_events.c", 284, __extension__ __PRETTY_FUNCTION__ )); } } while(0); | |||
| 285 | if ((event_type == DDCA_EVENT_DISPLAY_CONNECTED && (dref->flags&DREF_DDC_COMMUNICATION_WORKING0x0002)) | |||
| 286 | || event_type == DDCA_EVENT_DDC_ENABLED) | |||
| 287 | evt.flags |= DDCA_DISPLAY_EVENT_DDC_WORKING0x08; | |||
| 288 | // evt.unused[0] = 0; | |||
| 289 | // evt.unused[1] = 0; | |||
| 290 | ||||
| 291 | DBGTRC_RET_STRING(debug, DDCA_TRC_NONE, display_status_event_repr_t(evt), "")do { dbgtrc_returning_string( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x10, __func__, 291 , "dw_status_events.c", display_status_event_repr_t(evt), "") ; if (traced_function_stack_enabled) pop_traced_function(__func__ ); } while (0); | |||
| 292 | return evt; | |||
| 293 | } | |||
| 294 | ||||
| 295 | ||||
| 296 | /** Performs the actual work of executing the registered callbacks. | |||
| 297 | * | |||
| 298 | * @param evt | |||
| 299 | */ | |||
| 300 | void dw_emit_display_status_record( | |||
| 301 | DDCA_Display_Status_Event evt) | |||
| 302 | { | |||
| 303 | bool_Bool debug = false0; | |||
| 304 | DBGTRC_STARTING(debug, TRACE_GROUP, "evt=%s", display_status_event_repr_t(evt))do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 304, "dw_status_events.c", "Starting ""evt=%s" , display_status_event_repr_t(evt)); } while(0); | |||
| 305 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "Emitting %s", display_status_event_repr_t(evt))do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Emitting %s", display_status_event_repr_t(evt)); char prefix [100] = {0}; get_msg_decoration(prefix, 100, 1); syslog(syslog_priority , "%s%s%s", prefix, body, (tag_output) ? " (N)" : "" ); free( body); } } } while(0); | |||
| 306 | ||||
| 307 | // DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "evet->dref -> ", dref_reprx_t(evt->dref)); | |||
| 308 | if (IS_DBGTRC(debug, DDCA_TRC_NONE)( (debug) || is_tracing((DDCA_TRC_NONE), "dw_status_events.c" , __func__) )) { | |||
| 309 | Display_Ref * dref0 = dref_from_published_ddca_dref(evt.dref); | |||
| 310 | DBGTRC_NOPREFIX(true, DDCA_TRC_NONE, "event->dref -> %s", dref_reprx_t(dref0))dbgtrc( (1) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 310, "dw_status_events.c" , " ""event->dref -> %s", dref_reprx_t(dref0)); | |||
| 311 | } | |||
| 312 | ||||
| 313 | // debug_current_traced_function_stack(false); | |||
| 314 | // show_backtrace(0); | |||
| 315 | // dbgrpt_display_ref(dref0, true, 2); | |||
| 316 | #ifdef OLD | |||
| 317 | if (display_detection_callbacks) { | |||
| 318 | traced_function_stack_suspended = true1; | |||
| 319 | for (int ndx = 0; ndx < display_detection_callbacks->len; ndx++) { | |||
| 320 | DDCA_Display_Status_Callback_Func func = g_ptr_array_index(display_detection_callbacks, ndx)((display_detection_callbacks)->pdata)[ndx]; | |||
| 321 | func(evt); | |||
| 322 | } | |||
| 323 | traced_function_stack_suspended = false0; | |||
| 324 | } | |||
| 325 | #endif | |||
| 326 | ||||
| 327 | #ifdef NEWER | |||
| 328 | int callback_ct = (display_detection_callbacks) ? display_detection_callbacks->len : 0; | |||
| 329 | if (display_detection_callbacks) { | |||
| 330 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE,dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 332, "dw_status_events.c" , " ""Putting %d event notifications on display_detection_callbacks queue" , callback_ct) | |||
| 331 | "Putting %d event notifications on display_detection_callbacks queue",dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 332, "dw_status_events.c" , " ""Putting %d event notifications on display_detection_callbacks queue" , callback_ct) | |||
| 332 | callback_ct)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 332, "dw_status_events.c" , " ""Putting %d event notifications on display_detection_callbacks queue" , callback_ct); | |||
| 333 | for (int ndx = 0; ndx < callback_ct; ndx++) { | |||
| 334 | DDCA_Display_Status_Callback_Func func = g_ptr_array_index(display_detection_callbacks, ndx)((display_detection_callbacks)->pdata)[ndx]; | |||
| 335 | dw_put_callback_queue(func, evt); | |||
| 336 | } | |||
| 337 | } | |||
| 338 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE,do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Put %d event notification callbacks on display detection callbacks queue." , callback_ct); char prefix[100] = {0}; get_msg_decoration(prefix , 100, 1); syslog(syslog_priority, "%s%s%s", prefix, body, (tag_output ) ? " (N)" : "" ); free(body); } } } while(0) | |||
| 339 | "Put %d event notification callbacks on display detection callbacks queue.",do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Put %d event notification callbacks on display detection callbacks queue." , callback_ct); char prefix[100] = {0}; get_msg_decoration(prefix , 100, 1); syslog(syslog_priority, "%s%s%s", prefix, body, (tag_output ) ? " (N)" : "" ); free(body); } } } while(0) | |||
| 340 | callback_ct)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Put %d event notification callbacks on display detection callbacks queue." , callback_ct); char prefix[100] = {0}; get_msg_decoration(prefix , 100, 1); syslog(syslog_priority, "%s%s%s", prefix, body, (tag_output ) ? " (N)" : "" ); free(body); } } } while(0); | |||
| 341 | DBGTRC_DONE(debug, TRACE_GROUP,do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 343, "dw_status_events.c", "Done " "Put %d event notification callbacks on display detection callbacks queue" , callback_ct); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0) | |||
| 342 | "Put %d event notification callbacks on display detection callbacks queue",do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 343, "dw_status_events.c", "Done " "Put %d event notification callbacks on display detection callbacks queue" , callback_ct); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0) | |||
| 343 | callback_ct)do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 343, "dw_status_events.c", "Done " "Put %d event notification callbacks on display detection callbacks queue" , callback_ct); if (traced_function_stack_enabled) pop_traced_function (__func__); } while (0); | |||
| 344 | } | |||
| 345 | #endif | |||
| 346 | ||||
| 347 | // Take snapsnot of display_detection_calbacks | |||
| 348 | g_mutex_lock(&callbacks_mutex); | |||
| 349 | int callback_ct = (display_detection_callbacks) ? display_detection_callbacks->len : 0; | |||
| 350 | DDCA_Display_Status_Callback_Func funcs[callback_ct]; | |||
| ||||
| 351 | for (int ndx = 0; ndx < callback_ct; ndx++) | |||
| 352 | funcs[ndx] = g_ptr_array_index(display_detection_callbacks, ndx)((display_detection_callbacks)->pdata)[ndx]; | |||
| 353 | g_mutex_unlock(&callbacks_mutex); | |||
| 354 | ||||
| 355 | if (callback_ct > 0) { | |||
| 356 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "Starting %d callback threads", callback_ct)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 356, "dw_status_events.c" , " ""Starting %d callback threads", callback_ct); | |||
| 357 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "Starting %d callback threads", callback_ct)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Starting %d callback threads", callback_ct); char prefix[100 ] = {0}; get_msg_decoration(prefix, 100, 1); syslog(syslog_priority , "%s%s%s", prefix, body, (tag_output) ? " (N)" : "" ); free( body); } } } while(0); | |||
| 358 | for (int ndx = 0; ndx < callback_ct; ndx++) { | |||
| 359 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "Calling g_thread_new()...")dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 359, "dw_status_events.c" , " ""Calling g_thread_new()..."); | |||
| 360 | Callback_Queue_Entry * cqe = calloc(1, sizeof (Callback_Queue_Entry)); | |||
| 361 | cqe->event = evt; | |||
| 362 | cqe->func = funcs[ndx]; | |||
| 363 | // traced_function_stack_suspended = true; | |||
| 364 | GThread * callback_thread = g_thread_new( | |||
| 365 | "single_callback_worker", // optional thread name | |||
| 366 | dw_execute_callback_func, | |||
| 367 | cqe); | |||
| 368 | // traced_function_stack_suspended = false; | |||
| 369 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "libddcutil callback thread %p started", callback_thread)dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 369, "dw_status_events.c" , " ""libddcutil callback thread %p started", callback_thread ); | |||
| 370 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "libddcutil callback thread %p started", callback_thread)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("libddcutil callback thread %p started", callback_thread); char prefix[100] = {0}; get_msg_decoration(prefix, 100, 1); syslog (syslog_priority, "%s%s%s", prefix, body, (tag_output) ? " (N)" : "" ); free(body); } } } while(0); | |||
| 371 | g_thread_unref(callback_thread); | |||
| 372 | } | |||
| 373 | } | |||
| 374 | ||||
| 375 | DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "Started %d event callback thread(s)", callback_ct)do { if (test_emit_syslog(DDCA_SYSLOG_NOTICE)) { int syslog_priority = syslog_importance_from_ddcutil_syslog_level(DDCA_SYSLOG_NOTICE ); if (syslog_priority >= 0) { char * body = g_strdup_printf ("Started %d event callback thread(s)", callback_ct); char prefix [100] = {0}; get_msg_decoration(prefix, 100, 1); syslog(syslog_priority , "%s%s%s", prefix, body, (tag_output) ? " (N)" : "" ); free( body); } } } while(0); | |||
| 376 | DBGTRC_DONE(debug, TRACE_GROUP, "Started %d event callback thread(s)", callback_ct)do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 376, "dw_status_events.c", "Done " "Started %d event callback thread(s)", callback_ct); if (traced_function_stack_enabled ) pop_traced_function(__func__); } while (0); | |||
| 377 | } | |||
| 378 | ||||
| 379 | ||||
| 380 | GMutex emit_or_queue_mutex; | |||
| 381 | ||||
| 382 | /** Assembles a #DDCA_Display_Status_Event record and either calls | |||
| 383 | * #ddc_emit_display_status_record to emit it immediately or adds it | |||
| 384 | * to a queue of event records | |||
| 385 | * | |||
| 386 | * @param event_type e.g. DDCA_EVENT_CONNECTED, DDCA_EVENT_AWAKE | |||
| 387 | * @param connector_name | |||
| 388 | * @param dref display reference, NULL if DDCA_EVENT_BUS_ATTACHED | |||
| 389 | * or DDCA_EVENT_BUS_DETACHED | |||
| 390 | * @param io_path for DDCA_EVENT_BUS_ATTACHED or DDCA_EVENT_BUS_DETACHED | |||
| 391 | * @param queue if non-null, append status event record | |||
| 392 | */ | |||
| 393 | void dw_emit_or_queue_display_status_event( | |||
| 394 | DDCA_Display_Event_Type event_type, | |||
| 395 | const char * connector_name, | |||
| 396 | Display_Ref* dref, | |||
| 397 | DDCA_IO_Path io_path, | |||
| 398 | GArray* queue) | |||
| 399 | { | |||
| 400 | bool_Bool debug = false0; | |||
| 401 | if (dref) { | |||
| ||||
| 402 | DBGTRC_STARTING(debug, TRACE_GROUP, "dref=%p->%s, dispno=%d, disconnected=%s, event_type=%d=%s, connector_name=%s",do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 404, "dw_status_events.c", "Starting ""dref=%p->%s, dispno=%d, disconnected=%s, event_type=%d=%s, connector_name=%s" , dref, dref_reprx_t(dref), dref->dispno, sbool(dref->disconnected ), event_type, dw_display_event_type_name(event_type), connector_name ); } while(0) | |||
| 403 | dref, dref_reprx_t(dref), dref->dispno, sbool(dref->disconnected),do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 404, "dw_status_events.c", "Starting ""dref=%p->%s, dispno=%d, disconnected=%s, event_type=%d=%s, connector_name=%s" , dref, dref_reprx_t(dref), dref->dispno, sbool(dref->disconnected ), event_type, dw_display_event_type_name(event_type), connector_name ); } while(0) | |||
| 404 | event_type, dw_display_event_type_name(event_type), connector_name)do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 404, "dw_status_events.c", "Starting ""dref=%p->%s, dispno=%d, disconnected=%s, event_type=%d=%s, connector_name=%s" , dref, dref_reprx_t(dref), dref->dispno, sbool(dref->disconnected ), event_type, dw_display_event_type_name(event_type), connector_name ); } while(0); | |||
| 405 | #ifdef NEW | |||
| 406 | DBGTRC_STARTING(debug, TRACE_GROUP, "dref=%p->%s, event_type=%d=%s",do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 408, "dw_status_events.c", "Starting ""dref=%p->%s, event_type=%d=%s" , dref, dref_reprx_t(dref), event_type, dw_display_event_type_name (event_type)); } while(0) | |||
| 407 | dref, dref_reprx_t(dref),do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 408, "dw_status_events.c", "Starting ""dref=%p->%s, event_type=%d=%s" , dref, dref_reprx_t(dref), event_type, dw_display_event_type_name (event_type)); } while(0) | |||
| 408 | event_type, dw_display_event_type_name(event_type))do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 408, "dw_status_events.c", "Starting ""dref=%p->%s, event_type=%d=%s" , dref, dref_reprx_t(dref), event_type, dw_display_event_type_name (event_type)); } while(0); | |||
| 409 | #endif | |||
| 410 | } | |||
| 411 | else { | |||
| 412 | DBGTRC_STARTING(debug, TRACE_GROUP, "connector_name=%s, io_path=%s, event_type=%d=%s",do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 415, "dw_status_events.c", "Starting ""connector_name=%s, io_path=%s, event_type=%d=%s" , connector_name, dpath_repr_t(&io_path), event_type, dw_display_event_type_name (event_type)); } while(0) | |||
| 413 | connector_name,do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 415, "dw_status_events.c", "Starting ""connector_name=%s, io_path=%s, event_type=%d=%s" , connector_name, dpath_repr_t(&io_path), event_type, dw_display_event_type_name (event_type)); } while(0) | |||
| 414 | dpath_repr_t(&io_path),do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 415, "dw_status_events.c", "Starting ""connector_name=%s, io_path=%s, event_type=%d=%s" , connector_name, dpath_repr_t(&io_path), event_type, dw_display_event_type_name (event_type)); } while(0) | |||
| 415 | event_type, dw_display_event_type_name(event_type))do { if (traced_function_stack_enabled) push_traced_function( __func__); dbgtrc( (debug) || trace_callstack_call_depth > 0 || is_traced_callstack_call(__func__) ? DDCA_TRC_ALL : (TRACE_GROUP ), 0x08, __func__, 415, "dw_status_events.c", "Starting ""connector_name=%s, io_path=%s, event_type=%d=%s" , connector_name, dpath_repr_t(&io_path), event_type, dw_display_event_type_name (event_type)); } while(0); | |||
| 416 | } | |||
| 417 | // debug_current_traced_function_stack(false); // ** TEMP **/ | |||
| 418 | ||||
| 419 | DDCA_Display_Status_Event evt = dw_create_display_status_event( | |||
| 420 | event_type, | |||
| 421 | connector_name, | |||
| 422 | dref, | |||
| 423 | io_path); | |||
| 424 | DBGTRC_NOPREFIX(debug, DDCA_TRC_NONE, "event: %s", display_status_event_repr_t(evt))dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (DDCA_TRC_NONE), 0x00, __func__, 424, "dw_status_events.c" , " ""event: %s", display_status_event_repr_t(evt)); | |||
| 425 | // DECORATED_SYSLOG(DDCA_SYSLOG_NOTICE, "event: %s", display_status_event_repr(evt)); | |||
| 426 | ||||
| 427 | g_mutex_lock(&emit_or_queue_mutex); // or &emit_queue_mutex ??? | |||
| 428 | if (queue) | |||
| 429 | g_array_append_val(queue,evt)g_array_append_vals (queue, &(evt), 1); // TODO also need to lock where queue flushed | |||
| 430 | else | |||
| 431 | dw_emit_display_status_record(evt); | |||
| 432 | g_mutex_unlock(&emit_or_queue_mutex); | |||
| 433 | ||||
| 434 | DBGTRC_DONE(debug, TRACE_GROUP, "")do { dbgtrc( (debug) || trace_callstack_call_depth > 0 ? DDCA_TRC_ALL : (TRACE_GROUP), 0x10, __func__, 434, "dw_status_events.c", "Done " ""); if (traced_function_stack_enabled) pop_traced_function(__func__ ); } while (0); | |||
| 435 | // debug_current_traced_function_stack(false); // ** TEMP **/ | |||
| 436 | } | |||
| 437 | ||||
| 438 | ||||
| 439 | void init_dw_status_events() { | |||
| 440 | RTTI_ADD_FUNC(dw_create_display_status_event)rtti_func_name_table_add(dw_create_display_status_event, "dw_create_display_status_event" );; | |||
| 441 | RTTI_ADD_FUNC(dw_emit_or_queue_display_status_event)rtti_func_name_table_add(dw_emit_or_queue_display_status_event , "dw_emit_or_queue_display_status_event");; | |||
| 442 | RTTI_ADD_FUNC(dw_emit_display_status_record)rtti_func_name_table_add(dw_emit_display_status_record, "dw_emit_display_status_record" );; | |||
| 443 | RTTI_ADD_FUNC(dw_register_display_status_callback)rtti_func_name_table_add(dw_register_display_status_callback, "dw_register_display_status_callback");; | |||
| 444 | RTTI_ADD_FUNC(dw_unregister_display_status_callback)rtti_func_name_table_add(dw_unregister_display_status_callback , "dw_unregister_display_status_callback");; | |||
| 445 | RTTI_ADD_FUNC(dw_execute_callback_func)rtti_func_name_table_add(dw_execute_callback_func, "dw_execute_callback_func" );; | |||
| 446 | } |