void * run_event_loop(void *thread_arg_struct) { _connection_data *conn_data; xcwm_context_t *context; xcb_connection_t *event_conn; xcb_generic_event_t *evt; xcwm_event_t return_evt; xcwm_event_cb_t callback_ptr; conn_data = thread_arg_struct; context = conn_data->context; event_conn = context->conn; callback_ptr = conn_data->callback; free(thread_arg_struct); _xcwm_windows_adopt(context, callback_ptr); /* Start the event loop, and flush if first */ xcb_flush(event_conn); while ((evt = xcb_wait_for_event(event_conn))) { uint8_t response_type = evt->response_type & ~0x80; if (response_type == context->damage_event_mask) { xcb_damage_notify_event_t *dmgevnt = (xcb_damage_notify_event_t *)evt; /* printf("damage %d,%d @ %d,%d reported against window 0x%08x\n", */ /* dmgevnt->area.width, dmgevnt->area.height, dmgevnt->area.x, dmgevnt->area.y, */ /* dmgevnt->drawable); */ xcwm_window_t *window = _xcwm_get_window_node_by_window_id(dmgevnt->drawable); return_evt.event_type = XCWM_EVENT_WINDOW_DAMAGE; return_evt.window = window; if (!window) { printf("damage reported against unknown window 0x%08x\n", dmgevnt->drawable); continue; } /* Increase the damaged area of window if new damage is * larger than current. */ xcwm_event_get_thread_lock(); /* Initial damage events for override-redirect windows are * reported relative to the root window, subsequent events * are relative to the window itself. We also catch cases * where the damage area is larger than the bounds of the * window. */ if (window->initial_damage == 1 || (dmgevnt->area.width > window->bounds.width) || (dmgevnt->area.height > window->bounds.height) ) { xcb_xfixes_region_t region = xcb_generate_id(window->context->conn); xcb_rectangle_t rect; /* printf("initial damage on window 0x%08x\n", dmgevnt->drawable); */ /* Remove the damage */ xcb_xfixes_create_region(window->context->conn, region, 1, &dmgevnt->area); xcb_damage_subtract(window->context->conn, window->damage, region, XCB_NONE); /* Add new damage area for entire window */ rect.x = 0; rect.y = 0; rect.width = window->bounds.width; rect.height = window->bounds.height; xcb_xfixes_set_region(window->context->conn, region, 1, &rect); xcb_damage_add(window->context->conn, window->window_id, region); window->initial_damage = 0; xcb_xfixes_destroy_region(window->context->conn, region); xcwm_event_release_thread_lock(); continue; } window->dmg_bounds.x = dmgevnt->area.x; window->dmg_bounds.y = dmgevnt->area.y; window->dmg_bounds.width = dmgevnt->area.width; window->dmg_bounds.height = dmgevnt->area.height; xcwm_event_release_thread_lock(); callback_ptr(&return_evt); } else if (response_type == context->shape_event) { xcb_shape_notify_event_t *shapeevnt = (xcb_shape_notify_event_t *)evt; if (shapeevnt->shape_kind == XCB_SHAPE_SK_BOUNDING) { xcwm_window_t *window = _xcwm_get_window_node_by_window_id(shapeevnt->affected_window); _xcwm_window_set_shape(window, shapeevnt->shaped); return_evt.event_type = XCWM_EVENT_WINDOW_SHAPE; return_evt.window = window; callback_ptr(&return_evt); } } else if (response_type == context->fixes_event_base + XCB_XFIXES_CURSOR_NOTIFY) { /* xcb_xfixes_cursor_notify_event_t *cursorevnt = */ /* (xcb_xfixes_cursor_notify_event_t *)evt; */ return_evt.event_type = XCWM_EVENT_CURSOR; return_evt.window = NULL; callback_ptr(&return_evt); } else { switch (response_type) { case 0: { /* Error case. Something very bad has happened. Spit * out some hopefully useful information and then * die. * FIXME: Decide under what circumstances we should * acutally kill the application. */ xcb_generic_error_t *err = (xcb_generic_error_t *)evt; fprintf(stderr, "Error received in event loop.\n" "Error code: %i\n", err->error_code); if ((err->error_code >= XCB_VALUE) && (err->error_code <= XCB_FONT)) { xcb_value_error_t *val_err = (xcb_value_error_t *)evt; fprintf(stderr, "Bad value: %i\n" "Major opcode: %i\n" "Minor opcode: %i\n", val_err->bad_value, val_err->major_opcode, val_err->minor_opcode); } break; } case XCB_EXPOSE: { xcb_expose_event_t *exevnt = (xcb_expose_event_t *)evt; printf( "Window %u exposed. Region to be redrawn at location (%d, %d), ", exevnt->window, exevnt->x, exevnt->y); printf("with dimensions (%d, %d).\n", exevnt->width, exevnt->height); return_evt.event_type = XCWM_EVENT_WINDOW_EXPOSE; callback_ptr(&return_evt); break; } case XCB_CREATE_NOTIFY: { /* We don't actually allow our client to create its * window here, wait until the XCB_MAP_REQUEST */ break; } case XCB_DESTROY_NOTIFY: { // Window destroyed in root window xcb_destroy_notify_event_t *notify = (xcb_destroy_notify_event_t *)evt; xcwm_window_t *window = _xcwm_window_remove(event_conn, notify->window); if (!window) { /* Not a window in the list, don't try and destroy */ break; } return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY; return_evt.window = window; callback_ptr(&return_evt); // Release memory for the window _xcwm_window_release(window); break; } case XCB_MAP_NOTIFY: { xcb_map_notify_event_t *notify = (xcb_map_notify_event_t *)evt; /* notify->event holds parent of the window */ xcwm_window_t *window = _xcwm_get_window_node_by_window_id(notify->window); if (!window) { /* No MAP_REQUEST for override-redirect windows, so need to create the xcwm_window_t for it now */ /* printf("MAP_NOTIFY without MAP_REQUEST\n"); */ window = _xcwm_window_create(context, notify->window, notify->event); if (window) { _xcwm_window_composite_pixmap_update(window); return_evt.window = window; return_evt.event_type = XCWM_EVENT_WINDOW_CREATE; callback_ptr(&return_evt); } } else { _xcwm_window_composite_pixmap_update(window); } break; } case XCB_MAP_REQUEST: { xcb_map_request_event_t *request = (xcb_map_request_event_t *)evt; /* Map the window */ xcb_map_window(context->conn, request->window); xcb_flush(context->conn); return_evt.window = _xcwm_window_create(context, request->window, request->parent); if (!return_evt.window) { break; } return_evt.event_type = XCWM_EVENT_WINDOW_CREATE; callback_ptr(&return_evt); break; } case XCB_UNMAP_NOTIFY: { xcb_unmap_notify_event_t *notify = (xcb_unmap_notify_event_t *)evt; xcwm_window_t *window = _xcwm_window_remove(event_conn, notify->window); if (!window) { /* Not a window in the list, don't try and destroy */ break; } return_evt.event_type = XCWM_EVENT_WINDOW_DESTROY; return_evt.window = window; callback_ptr(&return_evt); _xcwm_window_composite_pixmap_release(window); // Release memory for the window _xcwm_window_release(window); break; } case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t *request = (xcb_configure_notify_event_t *)evt; printf("CONFIGURE_NOTIFY: XID 0x%08x %dx%d @ %d,%d\n", request->window, request->width, request->height, request->x, request->y); xcwm_window_t *window = _xcwm_get_window_node_by_window_id(request->window); if (window) _xcwm_window_composite_pixmap_update(window); break; } case XCB_CONFIGURE_REQUEST: { xcb_configure_request_event_t *request = (xcb_configure_request_event_t *)evt; printf("CONFIGURE_REQUEST: XID 0x%08x %dx%d @ %d,%d mask 0x%04x\n", request->window, request->width, request->height, request->x, request->y, request->value_mask); /* relying on the server's idea of the current values of values not in value_mask is a bad idea, we might have a configure request of our own on this window in flight */ if (request->value_mask & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT)) _xcwm_resize_window(event_conn, request->window, request->x, request->y, request->width, request->height); /* Ignore requests to change stacking ? */ break; } case XCB_PROPERTY_NOTIFY: { xcb_property_notify_event_t *notify = (xcb_property_notify_event_t *)evt; xcwm_window_t *window = _xcwm_get_window_node_by_window_id(notify->window); if (!window) { break; } /* If this is WM_PROTOCOLS, do not send event, just * handle internally */ if (notify->atom == window->context->atoms.ewmh_conn.WM_PROTOCOLS) { _xcwm_atoms_set_wm_delete(window); break; } xcwm_event_type_t event; if (_xcwm_atom_change_to_event(notify->atom, window, &event)) { /* Send the appropriate event */ return_evt.event_type = event; return_evt.window = window; callback_ptr(&return_evt); } else { printf("PROPERTY_NOTIFY for ignored property atom %d\n", notify->atom); /* We need a mechanism to forward properties we don't know about to WM, otherwise everything needs to be in libXcwm ...? */ } break; } case XCB_MAPPING_NOTIFY: break; default: { printf("UNKNOWN EVENT: %i\n", (evt->response_type & ~0x80)); break; } } } /* Free the event */ free(evt); } return NULL; }
std::pair<double, double> run_test(barrier_inserter& insert_barrier, bool prefill, uint64_t tasks_per_queue, unsigned num_queues, unsigned num_threads, uint64_t delay_us, unsigned idle_queues) { EXPECT_LT(0U, tasks_per_queue); EXPECT_LT(0U, num_queues); EXPECT_LE(0U, idle_queues); boost::property_tree::ptree pt; PARAMETER_TYPE(ip::perf_threadpool_test_threads)(num_threads).persist(pt); pt.put("version", 1); std::unique_ptr<threadpool_type> tp(new threadpool_type(pt)); BOOST_SCOPE_EXIT_TPL((&tp)) { EXPECT_NO_THROW(tp->stop()) << "Failed to stop threadpool"; } BOOST_SCOPE_EXIT_END; { blocker_ptr_vec blockers(idle_queues); for (size_t i = 0; i < idle_queues; ++i) { blockers[i] = blocker_ptr(new Blocker(*tp, num_queues + i)); } } callback_ptr_vec callbacks(num_queues); for (size_t i = 0; i < callbacks.size(); ++i) { callbacks[i] = callback_ptr(new Callback(tasks_per_queue, delay_us)); } youtils::wall_timer t; double post_time; if (prefill) { blocker_ptr_vec blockers(num_queues); for (size_t i = 0; i < blockers.size(); ++i) { blockers[i] = blocker_ptr(new Blocker(*tp, i)); } post_time = post_tasks_(insert_barrier, *tp, callbacks, tasks_per_queue); t.restart(); } else { post_time = post_tasks_(insert_barrier, *tp, callbacks, tasks_per_queue); } for (size_t i = 0; i < callbacks.size(); ++i) { callback_ptr cb = callbacks[i]; std::unique_lock<Callback::lock_type> u(cb->lock_); while (cb->count_ > 0) { ASSERT(cb->count_ <= tasks_per_queue); cb->cond_.wait(u); } } const double proc_time = t.elapsed(); std::cout << "# queues: " << num_queues << ", tasks per queue: " << tasks_per_queue << ", # idle queues: " << idle_queues << ", threads in pool: " << tp->getNumThreads() << ", delay per task (us): " << delay_us << ", processing duration (s): " << proc_time << std::endl; return std::make_pair(post_time, proc_time); }