Can't seem to shutdown cef process

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Can't seem to shutdown cef process

Postby aleitner » Mon Sep 18, 2023 12:12 pm

I have been stuck on the strangest issue. I am trying to quit the message loop and shutdown CEF but I am seeing the following errors when either functions are called. [0915/202951.382484:ERROR:(-1)] Check failed: false.

Code: Select all
cef_main_args_t main_args = {argc, argv};
cef_settings_t settings = {0};
guac_http_cef_app_t* app = guac_http_cef_app_init();   
cef_initialize(&main_args, &settings, (cef_app_t *)app, NULL);
/* Start the CEF event loop to handle CEF-related actions and rendering */
cef_run_message_loop();


Description for the cef_run_message_loop function:
Run the CEF message loop. Use this function instead of an application-
provided message loop to get the best balance between performance and CPU
usage. This function should only be called on the main application thread
and only if cef_initialize() is called with a
cef_settings_t.multi_threaded_message_loop value of false (0). This function
will block until a quit message is received by the system.
The cef_run_message_loop just blocks indefinitely until we call the quit function cef_quit_message_loop
Quit the CEF message loop that was started by calling
cef_run_message_loop(). This function should only be called on the main
application thread and only if cef_run_message_loop() was used.


Now I can't figure out how it expects me to call a the cef_quit_message_loop if cef_run_message_loop is blocking. I tried making a separate thread that starts before cef_run_message_loop, waits for a flag indicating we need to shut down CEF, but it just prints an error -1 (really helpful).
Code: Select all
static void* guac_http_cef_termination_thread(void* data) {
    guac_http_cef_shm_event_thread_data_t* thread_data = (guac_http_cef_shm_event_thread_data_t*) data;
    shm_memory* shm = thread_data->shm;

    /* Locking the mutex to prevent race condition while modifying the termination flag. */
    pthread_mutex_lock(&shm->data->termination_mutex);

    /* Waiting for the CEF process to update termination flag indicating it has completed termination. */
    while (shm->data->termination_flag != TERMINATION_START) {
        pthread_cond_wait(&shm->data->cond_termination_flag_updated, &shm->data->termination_mutex);
    }

    /* Release the mutex post-termination */
    pthread_mutex_unlock(&shm->data->termination_mutex);
    cef_quit_message_loop();
    cef_shutdown();

    return NULL;
}


From what I have read online it's because I am calling cef_quit_message_loop in a separate thread instead of the same place that cef_run_message_loop is called.

After doing some reading I decided to try calling cef_do_message_loop_work and to use this I add the following function to my browser_process_handler
Code: Select all
static void on_schedule_message_pump_work(struct _cef_browser_process_handler_t* self,
        int64 delay_ms) {


    if (delay_ms > 0)
        sleep(delay_ms);
       
    cef_do_message_loop_work();
}


And now I just wait for a termination request and call chutdown within the same thread as cef is initialized.

Code: Select all
cef_main_args_t main_args = {argc, argv};
cef_settings_t settings = {0};
guac_http_cef_app_t* app = guac_http_cef_app_init();   
cef_initialize(&main_args, &settings, (cef_app_t *)app, NULL);
/* Start the CEF event loop to handle CEF-related actions and rendering */
cef_run_message_loop();

/* Locking the mutex to prevent race condition while modifying the termination flag. */
pthread_mutex_lock(&shm->data->termination_mutex);
/* Waiting for the CEF process to update termination flag indicating it has completed termination. */
while (shm->data->termination_flag != TERMINATION_START) {
    pthread_cond_wait(&shm->data->cond_termination_flag_updated, &shm->data->termination_mutex);
}

/* Shutdown and clean up resources after CEF has been terminated */
cef_shutdown();


However I am still seeing the Error: -1 and cef is not shutting down. Is there something that I am missing? Thanks
Last edited by aleitner on Mon Sep 18, 2023 1:40 pm, edited 1 time in total.
aleitner
Techie
 
Posts: 49
Joined: Fri Jun 16, 2023 12:05 pm

Re: Can't

Postby magreenblatt » Mon Sep 18, 2023 12:38 pm

I can't figure out how it expects me to call a the cef_quit_message_loop if cef_run_message_loop is blocking.

You should implement CefApp::GetBrowserProcessHandler() and OnContextInitialized and proceed from there. See also https://bitbucket.org/chromiumembedded/ ... ting-tasks
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Can't seem to shutdown cef process

Postby aleitner » Mon Sep 18, 2023 2:36 pm

I have set up the on_context_initialized and the on_schedule_message_pump_work handlers On my cef_browser_process_handler_t.

Now that I have switched to this method the on_paint function is no longer called. Do you know of what I could be missing?

Code for my new browser_process_handler:
Code: Select all
static void on_schedule_message_pump_work(struct _cef_browser_process_handler_t* self,
        int64 delay_ms) {


    if (delay_ms > 0)
        sleep(delay_ms);

    cef_do_message_loop_work();
}

static void on_context_initialized(struct _cef_browser_process_handler_t* self) {
    /* Convert the display handler into our custom display handler */
    guac_http_cef_browser_process_handler_t* custom_self = (guac_http_cef_browser_process_handler_t*)self;

    /* Grab the shared memory object from the custom handler */
    shm_memory* shm = custom_self->shm;
    guac_http_cef_client_t* client = custom_self->client;

    /* Browser settings */
    cef_browser_settings_t browser_settings = {0};
    browser_settings.size = sizeof(cef_browser_settings_t);

    /* Create a browser instance */
    cef_window_info_t window_info = {{0}};
    window_info.windowless_rendering_enabled = 1;

    cef_string_t url = {};
    cef_string_utf8_to_utf16(shm->data->url, strlen(shm->data->url), &url);
    cef_browser_host_create_browser(&window_info, (cef_client_t *)client, &url, &browser_settings, NULL, NULL);
}

guac_http_cef_browser_process_handler_t* guac_http_cef_browser_process_init(
        shm_memory* shm,
        guac_http_cef_client_t* client) {
    guac_http_cef_browser_process_handler_t* handler =
        (guac_http_cef_browser_process_handler_t*)calloc(1, sizeof(guac_http_cef_browser_process_handler_t));

    handler->base.base.size = sizeof(cef_browser_process_handler_t);
    handler->base.on_before_child_process_launch = on_before_child_process_launch;
    handler->base.on_schedule_message_pump_work = on_schedule_message_pump_work;
    handler->base.on_context_initialized = on_context_initialized;

    handler->shm = shm;
    handler->client = client;

    return handler;
}
aleitner
Techie
 
Posts: 49
Joined: Fri Jun 16, 2023 12:05 pm

Re: Can't seem to shutdown cef process

Postby magreenblatt » Mon Sep 18, 2023 2:46 pm

I suggest that you start by looking at a working example, like https://github.com/cztomczak/cefcapi
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Can't seem to shutdown cef process

Postby aleitner » Mon Sep 18, 2023 3:13 pm

Are there any examples using cef_do_message_loop_work() instead of cef_run_message_loop()? I have a working windowless browser when i use cef_run_message_loop(). I just can't cleanly shut that process down which is why I am switching to cef_do_message_loop_work() instead. However now that I have switched, my on_paint callback is no longer being called. I looked through the example you sent and I am not seeing anything that I was not doing before besides me running my application with windowless_rendering_enabled = 1
aleitner
Techie
 
Posts: 49
Joined: Fri Jun 16, 2023 12:05 pm

Re: Can't seem to shutdown cef process

Postby magreenblatt » Mon Sep 18, 2023 3:27 pm

I just can't cleanly shut that process down which is why I am switching to cef_do_message_loop_work() instead.

Don't do that. Use CefRunMessageLoop and the information that I linked above (about posting tasks) to properly shut down by calling CefQuitMessageLoop on the UI thread.
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Can't seem to shutdown cef process

Postby aleitner » Tue Sep 19, 2023 11:06 am

Thanks so much for your help. I was able to write a task to quit the message loop.

Code: Select all
#include "include/capi/cef_task_capi.h"

typedef struct _shutdown_task {
  cef_task_t task;
} shutdown_task_t;

void shutdown_execute(struct _cef_task_t* task) {
    cef_quit_message_loop();
}

shutdown_task_t* create_shutdown_task() {
    shutdown_task_t* task = (shutdown_task_t*)calloc(1, sizeof(shutdown_task_t));

    task->task.base.size = sizeof(shutdown_task_t);
    task->task.execute = shutdown_execute;

    return task;
}

// Create a new shutdown_task_t.
shutdown_task_t* task = create_shutdown_task();

// Post this task to be executed on the UI thread.
cef_post_task(TID_UI, &task->task);

free(task);
aleitner
Techie
 
Posts: 49
Joined: Fri Jun 16, 2023 12:05 pm

Re: Can't seem to shutdown cef process

Postby magreenblatt » Tue Sep 19, 2023 12:20 pm

Keep in mind that your current implementation will leak memory. You should implement the reference counting as shown here (but actually freeing the memory that you calloc'd).
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Re: Can't seem to shutdown cef process

Postby aleitner » Tue Sep 19, 2023 3:53 pm

I'm trying to implement the reference counting based on what I have read in your link, but I am encountering an issue with free(): invalid pointer.

Is my implementation not as expected?

Code: Select all
// add_ref
static void CEF_CALLBACK add_ref_shutdown_task(struct _cef_base_ref_counted_t* base) {

    shutdown_task_t* task = (shutdown_task_t*)base;

    fprintf(stderr, "add_ref_shutdown_task.\n");

    ++task->ref_count;
}

// release
static int CEF_CALLBACK release_shutdown_task(struct _cef_base_ref_counted_t* base) {

    shutdown_task_t* task = (shutdown_task_t*)base;

    fprintf(stderr, "release_shutdown_task.\n");

    --task->ref_count;
   
    if (task->ref_count == 0) {
        if (task)
            free(task);       
        return 1;
    }
   
    return 0;
}

// execute
static void CEF_CALLBACK shutdown_execute(struct _cef_task_t* task) {
    fprintf(stderr, "shutdown.\n");
    cef_quit_message_loop();
}

// create
shutdown_task_t* create_shutdown_task() {
    shutdown_task_t* task = (shutdown_task_t*)calloc(1, sizeof(shutdown_task_t));

    task->task.base.size = sizeof(shutdown_task_t);
    task->task.base.add_ref = add_ref_shutdown_task;
    task->task.base.release = release_shutdown_task;
    task->task.execute = shutdown_execute;
    task->ref_count = 1;

    return task;
}



I usually see
add_ref_shutdown_task.
release_shutdown_task.
free(): invalid pointer
aleitner
Techie
 
Posts: 49
Joined: Fri Jun 16, 2023 12:05 pm

Re: Can't seem to shutdown cef process

Postby magreenblatt » Tue Sep 19, 2023 5:49 pm

How did you define shutdown_task_t with the updated code?
magreenblatt
Site Admin
 
Posts: 12409
Joined: Fri May 29, 2009 6:57 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: No registered users and 215 guests