void test_and () { v = init; atomic_fetch_and (&v, 0); if (v != 0) abort (); v = init; atomic_fetch_and_explicit (&v, init, memory_order_consume); if (v != init) abort (); atomic_fetch_and (&v, 0); if (v != 0) abort (); v = ~v; atomic_fetch_and_explicit (&v, init, memory_order_release); if (v != init) abort (); atomic_fetch_and (&v, 0); if (v != 0) abort (); v = ~v; atomic_fetch_and_explicit (&v, 0, memory_order_seq_cst); if (v != 0) abort (); }
void test_fetch_and () { v = init; if (atomic_fetch_and_explicit (&v, 0, memory_order_relaxed) != init) abort (); if (atomic_fetch_and_explicit (&v, init, memory_order_consume) != 0) abort (); if (atomic_fetch_and_explicit (&v, 0, memory_order_acquire) != 0) abort (); v = ~v; if (atomic_fetch_and_explicit (&v, init, memory_order_release) != init) abort (); if (atomic_fetch_and_explicit (&v, 0, memory_order_acq_rel) != init) abort (); if (atomic_fetch_and_explicit (&v, 0, memory_order_seq_cst) != 0) abort (); if (atomic_fetch_and (&v, 0) != 0) abort (); }
static void __icache_sync_action(struct linkedentry *entry) { struct inode *node = entry->obj; if(node->flags & INODE_DIRTY) fs_callback_inode_push(node); linkedlist_do_remove(ic_dirty, &node->dirty_item); atomic_fetch_and(&node->flags, ~INODE_DIRTY); }
bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) { unsigned long *p = map + BIT_WORD(start); const long size = start + nr; int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); unsigned long dirty = 0; unsigned long old_bits; /* First word */ if (nr - bits_to_clear > 0) { old_bits = atomic_fetch_and(p, ~mask_to_clear); dirty |= old_bits & mask_to_clear; nr -= bits_to_clear; bits_to_clear = BITS_PER_LONG; mask_to_clear = ~0UL; p++; } /* Full words */ if (bits_to_clear == BITS_PER_LONG) { while (nr >= BITS_PER_LONG) { if (*p) { old_bits = atomic_xchg(p, 0); dirty |= old_bits; } nr -= BITS_PER_LONG; p++; } } /* Last word */ if (nr) { mask_to_clear &= BITMAP_LAST_WORD_MASK(size); old_bits = atomic_fetch_and(p, ~mask_to_clear); dirty |= old_bits & mask_to_clear; } else { if (!dirty) { smp_mb(); } } return dirty != 0; }
/* read an inode from the filesystem */ int fs_inode_pull(struct inode *node) { int r = 0; if(node->flags & INODE_NEEDREAD) { r = fs_callback_inode_pull(node); if(!r) { atomic_fetch_and(&node->flags, ~INODE_NEEDREAD); } } fs_inode_init_kdev(node); return r; }
/* drop a reference to an inode. */ void vfs_icache_put(struct inode *node) { assert(node->count > 0); mutex_acquire(ic_lock); if(atomic_fetch_sub(&node->count, 1) == 1) { if(node->flags & INODE_PERSIST) { if(node->nlink != 0) { mutex_release(ic_lock); return; } } assert(node->flags & INODE_INUSE); atomic_fetch_and(&node->flags, ~INODE_INUSE); if(node->filesystem) { atomic_fetch_sub(&node->filesystem->usecount, 1); } linkedlist_remove(ic_inuse, &node->inuse_item); queue_enqueue_item(ic_lru, &node->lru_item, node); } mutex_release(ic_lock); }
void atomic_and(volatile T * const dest, const T val) { atomic_fetch_and(dest, val); }
KOKKOS_INLINE_FUNCTION void atomic_and(volatile T * const dest, const T src) { (void)atomic_fetch_and(dest,src); }
TEST(stdatomic, atomic_fetch_and) { atomic_int i = ATOMIC_VAR_INIT(0x123); ASSERT_EQ(0x123, atomic_fetch_and(&i, 0x00f)); ASSERT_EQ(0x003, atomic_fetch_and_explicit(&i, 0x2, memory_order_relaxed)); ASSERT_EQ(0x002, atomic_load(&i)); }
void atomic_clearbits_int(__volatile unsigned int *uip, unsigned int v) { atomic_fetch_and((atomic_uint *)uip, ~v); }
/* indicates that an inode no longer needs to be written to the filesystem */ void vfs_inode_unset_dirty(struct inode *node) { assert(node->flags & INODE_DIRTY); linkedlist_remove(ic_dirty, &node->dirty_item); atomic_fetch_and(&node->flags, ~INODE_DIRTY); }
static bool recreate_dispmanx(struct ra_ctx *ctx) { struct priv *p = ctx->priv; int display_nr = 0; int layer = 0; MP_VERBOSE(ctx, "Recreating DISPMANX state...\n"); destroy_dispmanx(ctx); p->display = vc_dispmanx_display_open(display_nr); p->update = vc_dispmanx_update_start(0); if (!p->display || !p->update) { MP_FATAL(ctx, "Could not get DISPMANX objects.\n"); goto fail; } uint32_t dispw, disph; if (graphics_get_display_size(0, &dispw, &disph) < 0) { MP_FATAL(ctx, "Could not get display size.\n"); goto fail; } p->w = dispw; p->h = disph; if (ctx->vo->opts->fullscreen) { p->x = p->y = 0; } else { struct vo_win_geometry geo; struct mp_rect screenrc = {0, 0, p->w, p->h}; vo_calc_window_geometry(ctx->vo, &screenrc, &geo); mp_rect_intersection(&geo.win, &screenrc); p->x = geo.win.x0; p->y = geo.win.y0; p->w = geo.win.x1 - geo.win.x0; p->h = geo.win.y1 - geo.win.y0; } // dispmanx is like a neanderthal version of Wayland - you can add an // overlay any place on the screen. VC_RECT_T dst = {.x = p->x, .y = p->y, .width = p->w, .height = p->h}; VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16}; VC_DISPMANX_ALPHA_T alpha = { .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE, .opacity = 0xFF, }; p->window = vc_dispmanx_element_add(p->update, p->display, layer, &dst, 0, &src, DISPMANX_PROTECTION_NONE, &alpha, 0, 0); if (!p->window) { MP_FATAL(ctx, "Could not add DISPMANX element.\n"); goto fail; } vc_dispmanx_update_submit_sync(p->update); p->update = vc_dispmanx_update_start(0); p->egl_window = (EGL_DISPMANX_WINDOW_T){ .element = p->window, .width = p->w, .height = p->h, }; p->egl_surface = eglCreateWindowSurface(p->egl_display, p->egl_config, &p->egl_window, NULL); if (p->egl_surface == EGL_NO_SURFACE) { MP_FATAL(ctx, "Could not create EGL surface!\n"); goto fail; } if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, p->egl_context)) { MP_FATAL(ctx, "Failed to set context!\n"); goto fail; } p->display_fps = 0; TV_GET_STATE_RESP_T tvstate; TV_DISPLAY_STATE_T tvstate_disp; if (!vc_tv_get_state(&tvstate) && !vc_tv_get_display_state(&tvstate_disp)) { if (tvstate_disp.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) { p->display_fps = tvstate_disp.display.hdmi.frame_rate; HDMI_PROPERTY_PARAM_T param = { .property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE, }; if (!vc_tv_hdmi_get_property(¶m) && param.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC) p->display_fps = p->display_fps / 1.001; } else { p->display_fps = tvstate_disp.display.sdtv.frame_rate; } } p->win_params[0] = display_nr; p->win_params[1] = layer; p->win_params[2] = p->x; p->win_params[3] = p->y; ctx->vo->dwidth = p->w; ctx->vo->dheight = p->h; ra_gl_ctx_resize(ctx->swapchain, p->w, p->h, 0); ctx->vo->want_redraw = true; vo_event(ctx->vo, VO_EVENT_WIN_STATE); return true; fail: destroy_dispmanx(ctx); return false; } static void rpi_swap_buffers(struct ra_ctx *ctx) { struct priv *p = ctx->priv; eglSwapBuffers(p->egl_display, p->egl_surface); } static bool rpi_init(struct ra_ctx *ctx) { struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); bcm_host_init(); vc_tv_register_callback(tv_callback, ctx); p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!eglInitialize(p->egl_display, NULL, NULL)) { MP_FATAL(ctx, "EGL failed to initialize.\n"); goto fail; } if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context, &p->egl_config)) goto fail; if (recreate_dispmanx(ctx) < 0) goto fail; mpegl_load_functions(&p->gl, ctx->log); struct ra_gl_ctx_params params = { .swap_buffers = rpi_swap_buffers, .native_display_type = "MPV_RPI_WINDOW", .native_display = p->win_params, }; if (!ra_gl_ctx_init(ctx, &p->gl, params)) goto fail; return true; fail: rpi_uninit(ctx); return false; } static bool rpi_reconfig(struct ra_ctx *ctx) { return recreate_dispmanx(ctx); } static struct mp_image *take_screenshot(struct ra_ctx *ctx) { struct priv *p = ctx->priv; if (!p->display) return NULL; struct mp_image *img = mp_image_alloc(IMGFMT_BGR0, p->w, p->h); if (!img) return NULL; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, img->w | ((img->w * 4) << 16), img->h, &(int32_t){0}); if (!resource) goto fail; if (vc_dispmanx_snapshot(p->display, resource, 0)) goto fail; VC_RECT_T rc = {.width = img->w, .height = img->h}; if (vc_dispmanx_resource_read_data(resource, &rc, img->planes[0], img->stride[0])) goto fail; vc_dispmanx_resource_delete(resource); return img; fail: vc_dispmanx_resource_delete(resource); talloc_free(img); return NULL; } static int rpi_control(struct ra_ctx *ctx, int *events, int request, void *arg) { struct priv *p = ctx->priv; switch (request) { case VOCTRL_SCREENSHOT_WIN: *(struct mp_image **)arg = take_screenshot(ctx); return VO_TRUE; case VOCTRL_FULLSCREEN: recreate_dispmanx(ctx); return VO_TRUE; case VOCTRL_CHECK_EVENTS: if (atomic_fetch_and(&p->reload_display, 0)) { MP_WARN(ctx, "Recovering from display mode switch...\n"); recreate_dispmanx(ctx); } return VO_TRUE; case VOCTRL_GET_DISPLAY_FPS: *(double *)arg = p->display_fps; return VO_TRUE; } return VO_NOTIMPL; } const struct ra_ctx_fns ra_ctx_rpi = { .type = "opengl", .name = "rpi", .reconfig = rpi_reconfig, .control = rpi_control, .init = rpi_init, .uninit = rpi_uninit, };