Bug Summary

File:/shared/playproj/i2c/src/dw/dw_status_events.c
Warning:line 350, column 4
Declared variable-length array (VLA) has zero size

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dw_status_events.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/shared/playproj/i2c/src/dw -fcoverage-compilation-dir=/shared/playproj/i2c/src/dw -resource-dir /usr/lib/llvm-20/lib/clang/20 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/libdrm -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I ../../src -I ../../src/public -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D PIC -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib64/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-compound-token-split-by-macro -std=c11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o dw_status_events.plist -x c dw_status_events.c
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
35static 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 */
42void 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
62GAsyncQueue * callback_queue = NULL((void*)0);
63GMutex * callback_queue_mutex = NULL((void*)0);
64
65void dw_free_callback_queue_entry(Callback_Queue_Entry * entry) {
66 // free_display_status_event(entry->event); // ???
67 free(entry);
68}
69
70
71GAsyncQueue * init_callback_queue() {
72 callback_queue = g_async_queue_new();
73 return callback_queue;
74}
75
76
77void 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
92Callback_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 */
116gpointer 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
145STATICstatic void
146free_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 */
156gpointer 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
207GPtrArray* display_detection_callbacks = NULL((void*)0);
208static 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 */
219DDCA_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 */
247DDCA_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
263DDCA_Display_Status_Event
264dw_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 */
300void 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)
;
14
Assuming 'traced_function_stack_enabled' is false
15
Taking false branch
16
Assuming 'trace_callstack_call_depth' is > 0
17
Loop condition is false. Exiting loop
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)
;
18
Assuming the condition is false
19
Taking false branch
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__) )
) {
20
Loop condition is false. Exiting loop
21
Assuming the condition is false
22
Taking false branch
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;
23
Assuming 'display_detection_callbacks' is null
24
'?' condition is false
25
'callback_ct' initialized to 0
350 DDCA_Display_Status_Callback_Func funcs[callback_ct];
26
Declared variable-length array (VLA) has zero size
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
380GMutex 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 */
393void 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) {
1
Assuming 'dref' is non-null
2
Taking true branch
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)
3
Assuming 'traced_function_stack_enabled' is false
4
Taking false branch
5
Assuming 'trace_callstack_call_depth' is <= 0
6
Assuming the condition is true
7
'?' condition is true
8
Loop condition is false. Exiting loop
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))
;
9
Assuming 'trace_callstack_call_depth' is <= 0
10
'?' condition is false
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)
11
Assuming 'queue' is null
12
Taking false branch
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);
13
Calling 'dw_emit_display_status_record'
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
439void 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}