XLib Disconnection Callback - xlib

I use XLib and XRand to get some information about the connected displays on an embedded system.
class Foo {
private:
Display *_display{};
public:
Foo() {
_display = XOpenDisplay(":0.0");
}
void getSomeInfo() const {
/* Get some info with _display */
}
~Foo() {
XCloseDisplay(_display);
}
}
The problem is, X server can be shut down (for low power or some other purposes) after the creation of Foo instance and before calling getSomeInfo(), which causes immediate death of my application because XLib tries to exit application in case of errors.
Is there any mechanism, like a callback, which would allow me to understand that X Server went down and I should not use the _display pointer anymore ?

I fear that your only option is to use XSetIOErrorHandler and then do something ugly.
From https://tronche.com/gui/x/xlib/event-handling/protocol-errors/XSetIOErrorHandler.html:
The XSetIOErrorHandler() sets the fatal I/O error handler. Xlib calls the program's supplied error handler if any sort of system call error occurs (for example, the connection to the server was lost). This is assumed to be a fatal condition, and the called routine should not return. If the I/O error handler does return, the client process exits.
The "do something ugly" that I would suggest is to use setjmp and longjmp: Whenever you call any Xlib functions, you setjmp before. Your I/O error handling function then longjmps away to get away from the I/O error without your process exiting.

Related

How to get OUT of an ISR in freertos / esp-idf

I have an ISR that's fired from a button press. The handler looks like this...
void IRAM_ATTR buttonIsrHandler(void *arg) {
xTaskResumeFromISR(buttonTaskHandle);
}
// `buttonTaskHandle` is set up as the handle for this task function...
void buttonTask(void *pvParameter) {
while (1) {
vTaskSuspend(NULL);
// ... my task code goes here...
}
}
When I'm in an ISR, I can't do certain things. For instance, calling ESP_LOGI() results in an error relating to disallowed memory access.
I was expecting those limitations to exist only within the buttonIsrHandler() function, but they also exist within buttonTask() given that I woke it up from an ISR.
How do I get out of an ISR so that I can do all my normal stuff? I could use something like a queue to do this, but that seems heavy weight. Is there an easier way? Would sending a task-notification from the ISR handler be any different? Any other suggestions?
As you can see in the documentation of xTaskResumeFromISR, such a use case is not recommended. Task notifications are designed and optimized for this exact use case. In your case, you'd want to use vTaskNotifyGiveFromISR.
As for "leaving the ISR", FreeRTOS will not call your task function from the ISR context. xTaskResumeFromISR and other functions simply update the state of the task so that it can run when its turn comes.

ReadDirectoryChangesW Asynchronous Completion routine called after I close the handle

I am using ReadDirectoryChangesW to monitor when a file has changed within a directory. I am using the asynchronous version of it with a completion routine function, (as per the docs).
Everything works fine until I wish to stop monitoring the folder.
To stop the monitoring I call the Close function.
The problem is that I still get one last notification, but by then I have destroyed my LPOVERLAPPED value.
How can I stop ReadDirectoryChangesW and prevent my MyCompletionRoutine function from being called.
// get the handle
_handle = CreateFileW( ... )
void Read()
{
...
ReadDirectoryChangesW( _handle, ..., &MyCompletionRoutine );
...
}
void Close()
{
::CancelIo(_handle );
::CloseHandle(_handle );
}
void __stdcall MyCompletionRoutine (
const unsigned long dwErrorCode,
const unsigned long dwNumberOfBytesTransfered,
_OVERLAPPED* lpOverlapped )
{
// ... do stuff and start a read again
Read();
}
In the code above I might have called Read but I want to stop before MyCompletionRoutine is called.
Not sure if that helps, but the error message I get is 317
You are closing your HANDLE and freeing your OVERLAPPED too soon.
CancelIo() (and its cross-thread brother, CancelIoEx()) simply mark active I/O operations as cancelled and then exit, but you still need to actually wait for those operations to fully complete before you can then free their OVERLAPPED.
If an operation notices the cancellation before completing its work, it will stop its work and report a completion with an error code of ERROR_OPERATION_ABORTED, otherwise it will finish its work normally and report a completion with the appropriate error code.
After calling CancelIo/Ex(), you need to continue waiting on and handling completed operations, until there are no more operations left to wait on.
In other words, MyCompletionRoutine() can indeed be called after CancelIo() is called, and it needs to check for ERROR_OPERATION_ABORTED before calling Read() again. And if there is a pending read in progress when CancelIo() is called, you need to wait for that read to complete.

SendMessage - strange return values

I have an application which uses a three helper threads to read from a database (3 different tables, ~160,000 rows in total), create objects from those rows, then add the objects to one of two lists, depending on what type of object was created. The helper threads add objects to the list through a SendMessage call so that the main thread is the only object adding/removing to/from the list.
The odd thing is that SendMessage doesn't always succeed, I'll frequently get these two errors ERROR_ALREADY_EXISTS (183) and ERROR_TRUSTED_DOMAIN_FAILURE (1788). The function that SendMessage calls just adds an object to the list, and this function always returns success (0). There's no creating files (as ERROR_ALREADY_EXISTS seems to suggest) and there's no network calls so I'm not sure why I'm getting ERROR_TRUSTED_DOMAIN_FAILURE errors.
Any ideas on what might be causing these errors or any way to debug these errors?
As a note, before it was SendMessage I was using PostMessage and would get lots of ERROR_NOT_ENOUGH_QUOTA errors; SendMessage makes the utility work a lot better.
SendMessage() returns the result of the message that is sent. It is up to the message handler to decide what value is actually returned by SendMessage() to the sending code. GetLastError() is only meaningful if SendMessage() itself fails, and you have to use SetLastError() to detect that, eg:
SetLastError(0);
LRESULT res = SendMessage(...);
if ((res == 0) && (GetLastError() != 0))
{
// send failed, for example GetLastError()=ERROR_ACCESS_DENIED if UIPI blocked the message ...
}
else
{
// send succeeded, res is whatever value the message handler returned ...
}
This only works reliably if the target HWND is owned by a different thread than the one that is calling SendMessage(). GetLastError() cannot be influenced across thread boundaries. Any call to SetLastError() within the message handler affects the error code of the HWND's owning thread, not the error code of the sending thread.
However, if the target HWND is owned by the same thread that is calling SendMessage(), and the message handler happens to call SetLastError() (directly, or indirectly via a failed API call) to set a non-zero error code, and happens to return 0 as its result value for SendMessage() to return to the sender, then the only way I can think of for the sender to differentiate whether the error code returned by GetLastError() was set by SendMessage() itself on failure, or set by the message handler, is to use a thread-locale message hook via SetWindowsHookEx() to detect whether the message handler was actually called or not (the only condition I can think of for that happening is if the target HWND is invalid so SendMessage() cannot find its window procedure).
You can use GetWindowThreadProcessId() and GetCurrentThreadId() to check if the target HWND is owned by the calling thread or not.

How does another program/process interrupt the execution of my program?

Lets say I have written a very simple program in an operating system which supports UI. My program looks like below:-
#include <os_specific_ui.h>
int main()
{
// Create a button using os specific API
object my_button = add_button("I am a button");
// Register for a mouse down call back on that button
mouse_down_handler = register_mouse_down_cb(my_button, func_to_be_called_on_mouse_down);
// do something...
// have a lot of functions which keep calling each other for a long period of time
}
void func_to_be_called_on_mouse_down(void)
{
print("my_button got clicked");
}
The program is clearly a single threaded program. When I run it, it keeps on doing something. In the mean time if there is a mouse down event, then callback registered for it will get hit and start executing.
I want to know how can another process (which handles mouse movements) can call a function in my process? And what happens to the state of my process when such a callback is hit. I mean my program was doing something when callback was hit. So it just stops doing that and starts executing callback or what? And what after the callback function finishes executing? Does my program go back to do whatever it was doing before callback was hit?
Pretty much all GUI programs run some form of event/main loop. That is, as the last part in main() it enters a loop, which reads events from the OS, and dispatches those events to your callback handlers and performs other tasks to realize the GUI.
i.e. the code you have in // have a lot of functions which keep calling each other just isn't possible unless you do that in a separate thread. Your own execution flow isn't stopped and taken over by some other process.
A GUI program is more or less done like this:
#include <os_specific_ui.h>
void func_to_be_called_on_mouse_down(void)
{
print("my_button got clicked");
}
int main()
{
// Create a button using os specific API
object my_button = add_button("I am a button");
// Register for a mouse down call back on that button
mouse_down_handler = register_mouse_down_cb(my_button, func_to_be_called_on_mouse_down);
for (;;) {
Event e
read_event_from_OS(&e);
handle_event(&e);
}
}
Where read_event_from_OS() fetches mouse/keyboard/redraw/etc. events from the operating system, and handle_event() figures out what to do with that event, such as redraw a window, or call one of the callback functions that your program has registered.
If the OS you're working on does things differently, you'll have to tell us more about it

NULL pointer dereference in swiotlb_unmap_sg_attrs() on disk IO

I'm getting an error I really don't understand when reading or writing files using a PCIe block device driver. I seem to be hitting an issue in swiotlb_unmap_sg_attrs(), which appears to be doing a NULL dereference of the sg pointer, but I don't know where this is coming from, as the only scatterlist I use myself is allocated as part of the device info structure and persists as long as the driver does.
There is a stacktrace to go with the problem. It tends to vary a bit in exact details, but it always crashes in swiotlb_unmap_sq_attrs().
I think it's likely I have a locking issue, as I am not sure how to handle the locks around the IO functions. The lock is already held when the request function is called, I release it before the IO functions themselves are called, as they need an (MSI) IRQ to complete. The IRQ handler updates a "status" value, which the IO function is waiting for. When the IO function returns, I then take the lock back up and return to request queue handling.
The crash happens in blk_fetch_request() during the following:
if (!__blk_end_request(req, res, bytes)){
printk(KERN_ERR "%s next request\n", DRIVER_NAME);
req = blk_fetch_request(q);
} else {
printk(KERN_ERR "%s same request\n", DRIVER_NAME);
}
where bytes is updated by the request handler to be the total length of IO (summed length of each scatter-gather segment).
It turned out this was due to re-entrancy of the request function. Because I was unlocking in the middle to allow IRQs to come in, the request function could be called again, would take the lock (while the original request handler was waiting on IO) and then the wrong handler would get the IRQ and everything went south with stacks of failed IO.
The way I solved this was to set a "busy" flag at the start of the request function, clear it at the end and return immediately at the start of the function if this is set:
static void mydev_submit_req(struct request_queue *q){
struct mydevice *dev = q->queuedata;
// We are already processing a request
// so reentrant calls can take a hike
// They'll be back
if (dev->has_request)
return;
// We own the IO now, new requests need to wait
// Queue lock is held when this function is called
// so no need for an atomic set
dev->has_request = 1;
// Access request queue here, while queue lock is held
spin_unlock_irq(q->queue_lock);
// Perform IO here, with IRQs enabled
// You can't access the queue or request here, make sure
// you got the info you need out before you release the lock
spin_lock_irq(q->queue_lock);
// you can end the requests as needed here, with the lock held
// allow new requests to be processed after we return
dev->has_request = 0;
// lock is held when the function returns
}
I am still not sure why I consistently got the stacktrace from swiotlb_unmap_sq_attrs(), however.

Resources