trunk/src/emu/luaengine.c
| r242708 | r242709 | |
| 17 | 17 | #include "emuopts.h" |
| 18 | 18 | #include "osdepend.h" |
| 19 | 19 | #include "drivenum.h" |
| 20 | | #include "ui/ui.h" |
| 21 | 20 | #include "web/mongoose.h" |
| 22 | 21 | |
| 23 | 22 | //************************************************************************** |
| r242708 | r242709 | |
| 337 | 336 | return 0; |
| 338 | 337 | } |
| 339 | 338 | |
| 340 | | int lua_engine::l_emu_set_hook(lua_State *L) |
| 341 | | { |
| 342 | | luaThis->emu_set_hook(L); |
| 343 | | return 0; |
| 344 | | } |
| 345 | | |
| 346 | | void lua_engine::emu_set_hook(lua_State *L) |
| 347 | | { |
| 348 | | luaL_argcheck(L, lua_isfunction(L, 1) || lua_isnil(L, 1), 1, "callback function expected"); |
| 349 | | luaL_argcheck(L, lua_isstring(L, 2), 2, "message (string) expected"); |
| 350 | | const char *hookname = luaL_checkstring(L,2); |
| 351 | | |
| 352 | | if (strcmp(hookname, "output") == 0) { |
| 353 | | hook_output_cb.set(L, 1); |
| 354 | | if (!output_notifier_set) { |
| 355 | | output_set_notifier(NULL, s_output_notifier, this); |
| 356 | | output_notifier_set = true; |
| 357 | | } |
| 358 | | } else if (strcmp(hookname, "frame") == 0) { |
| 359 | | hook_frame_cb.set(L, 1); |
| 360 | | } else { |
| 361 | | luai_writestringerror("%s", "Unknown hook name, aborting.\n"); |
| 362 | | } |
| 363 | | } |
| 364 | | |
| 365 | 339 | //------------------------------------------------- |
| 366 | | // machine_get_screens - return table of available screens userdata |
| 367 | | // -> manager:machine().screens[":screen"] |
| 368 | | //------------------------------------------------- |
| 369 | | |
| 370 | | luabridge::LuaRef lua_engine::l_machine_get_screens(const running_machine *r) |
| 371 | | { |
| 372 | | lua_State *L = luaThis->m_lua_state; |
| 373 | | luabridge::LuaRef screens_table = luabridge::LuaRef::newTable(L); |
| 374 | | |
| 375 | | for (device_t *dev = r->first_screen(); dev != NULL; dev = dev->next()) { |
| 376 | | screen_device *sc = dynamic_cast<screen_device *>(dev); |
| 377 | | if (sc && sc->configured() && sc->started() && sc->type()) { |
| 378 | | screens_table[sc->tag()] = sc; |
| 379 | | } |
| 380 | | } |
| 381 | | |
| 382 | | return screens_table; |
| 383 | | } |
| 384 | | |
| 385 | | //------------------------------------------------- |
| 386 | 340 | // machine_get_devices - return table of available devices userdata |
| 387 | 341 | // -> manager:machine().devices[":maincpu"] |
| 388 | 342 | //------------------------------------------------- |
| r242708 | r242709 | |
| 484 | 438 | |
| 485 | 439 | } |
| 486 | 440 | |
| 487 | | //------------------------------------------------- |
| 488 | | // draw_box - draw a box on a screen container |
| 489 | | // -> manager:machine().screens[":screen"]:draw_box(x1, y1, x2, y2, bgcolor, linecolor) |
| 490 | | //------------------------------------------------- |
| 491 | | |
| 492 | | int lua_engine::lua_screen::l_draw_box(lua_State *L) |
| 493 | | { |
| 494 | | screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1); |
| 495 | | if(!sc) { |
| 496 | | return 0; |
| 497 | | } |
| 498 | | |
| 499 | | // ensure that we got 6 numerical parameters |
| 500 | | luaL_argcheck(L, lua_isnumber(L, 2), 2, "x1 (integer) expected"); |
| 501 | | luaL_argcheck(L, lua_isnumber(L, 3), 3, "y1 (integer) expected"); |
| 502 | | luaL_argcheck(L, lua_isnumber(L, 4), 4, "x2 (integer) expected"); |
| 503 | | luaL_argcheck(L, lua_isnumber(L, 5), 5, "y2 (integer) expected"); |
| 504 | | luaL_argcheck(L, lua_isnumber(L, 6), 6, "background color (integer) expected"); |
| 505 | | luaL_argcheck(L, lua_isnumber(L, 7), 7, "outline color (integer) expected"); |
| 506 | | |
| 507 | | // retrieve all parameters |
| 508 | | float x1, y1, x2, y2; |
| 509 | | x1 = MIN(lua_tounsigned(L, 2) / static_cast<float>(sc->width()) , 1.0f); |
| 510 | | y1 = MIN(lua_tounsigned(L, 3) / static_cast<float>(sc->height()), 1.0f); |
| 511 | | x2 = MIN(lua_tounsigned(L, 4) / static_cast<float>(sc->width()) , 1.0f); |
| 512 | | y2 = MIN(lua_tounsigned(L, 5) / static_cast<float>(sc->height()), 1.0f); |
| 513 | | UINT32 bgcolor = lua_tounsigned(L, 6); |
| 514 | | UINT32 fgcolor = lua_tounsigned(L, 7); |
| 515 | | |
| 516 | | // draw the box |
| 517 | | render_container &rc = sc->container(); |
| 518 | | ui_manager &ui = sc->machine().ui(); |
| 519 | | ui.draw_outlined_box(&rc, x1, y1, x2, y2, fgcolor, bgcolor); |
| 520 | | |
| 521 | | return 0; |
| 522 | | } |
| 523 | | |
| 524 | | //------------------------------------------------- |
| 525 | | // draw_line - draw a line on a screen container |
| 526 | | // -> manager:machine().screens[":screen"]:draw_line(x1, y1, x2, y2, linecolor) |
| 527 | | //------------------------------------------------- |
| 528 | | |
| 529 | | int lua_engine::lua_screen::l_draw_line(lua_State *L) |
| 530 | | { |
| 531 | | screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1); |
| 532 | | if(!sc) { |
| 533 | | return 0; |
| 534 | | } |
| 535 | | |
| 536 | | // ensure that we got 5 numerical parameters |
| 537 | | luaL_argcheck(L, lua_isnumber(L, 2), 2, "x1 (integer) expected"); |
| 538 | | luaL_argcheck(L, lua_isnumber(L, 3), 3, "y1 (integer) expected"); |
| 539 | | luaL_argcheck(L, lua_isnumber(L, 4), 4, "x2 (integer) expected"); |
| 540 | | luaL_argcheck(L, lua_isnumber(L, 5), 5, "y2 (integer) expected"); |
| 541 | | luaL_argcheck(L, lua_isnumber(L, 6), 6, "color (integer) expected"); |
| 542 | | |
| 543 | | // retrieve all parameters |
| 544 | | float x1, y1, x2, y2; |
| 545 | | x1 = MIN(lua_tounsigned(L, 2) / static_cast<float>(sc->width()) , 1.0f); |
| 546 | | y1 = MIN(lua_tounsigned(L, 3) / static_cast<float>(sc->height()), 1.0f); |
| 547 | | x2 = MIN(lua_tounsigned(L, 4) / static_cast<float>(sc->width()) , 1.0f); |
| 548 | | y2 = MIN(lua_tounsigned(L, 5) / static_cast<float>(sc->height()), 1.0f); |
| 549 | | UINT32 color = lua_tounsigned(L, 6); |
| 550 | | |
| 551 | | // draw the line |
| 552 | | sc->container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); |
| 553 | | return 0; |
| 554 | | } |
| 555 | | |
| 556 | | //------------------------------------------------- |
| 557 | | // draw_text - draw text on a screen container |
| 558 | | // -> manager:machine().screens[":screen"]:draw_text(x, y, message) |
| 559 | | //------------------------------------------------- |
| 560 | | |
| 561 | | int lua_engine::lua_screen::l_draw_text(lua_State *L) |
| 562 | | { |
| 563 | | screen_device *sc = luabridge::Stack<screen_device *>::get(L, 1); |
| 564 | | if(!sc) { |
| 565 | | return 0; |
| 566 | | } |
| 567 | | |
| 568 | | // ensure that we got proper parameters |
| 569 | | luaL_argcheck(L, lua_isnumber(L, 2), 2, "x (integer) expected"); |
| 570 | | luaL_argcheck(L, lua_isnumber(L, 3), 3, "y (integer) expected"); |
| 571 | | luaL_argcheck(L, lua_isstring(L, 4), 4, "message (string) expected"); |
| 572 | | |
| 573 | | // retrieve all parameters |
| 574 | | float x = MIN(lua_tounsigned(L, 2) / static_cast<float>(sc->width()) , 1.0f); |
| 575 | | float y = MIN(lua_tounsigned(L, 3) / static_cast<float>(sc->height()), 1.0f); |
| 576 | | const char *msg = luaL_checkstring(L,4); |
| 577 | | // TODO: add optional parameters (colors, etc.) |
| 578 | | |
| 579 | | // draw the text |
| 580 | | render_container &rc = sc->container(); |
| 581 | | ui_manager &ui = sc->machine().ui(); |
| 582 | | ui.draw_text_full(&rc, msg, x, y , (1.0f - x), |
| 583 | | JUSTIFY_LEFT, WRAP_WORD, DRAW_NORMAL, UI_TEXT_COLOR, |
| 584 | | UI_TEXT_BG_COLOR, NULL, NULL); |
| 585 | | |
| 586 | | return 0; |
| 587 | | } |
| 588 | | |
| 589 | 441 | void *lua_engine::checkparam(lua_State *L, int idx, const char *tname) |
| 590 | 442 | { |
| 591 | 443 | const char *name; |
| r242708 | r242709 | |
| 798 | 650 | .addCFunction ("romname", l_emu_romname ) |
| 799 | 651 | .addCFunction ("keypost", l_emu_keypost ) |
| 800 | 652 | .addCFunction ("hook_output", l_emu_hook_output ) |
| 801 | | .addCFunction ("sethook", l_emu_set_hook ) |
| 802 | 653 | .addCFunction ("time", l_emu_time ) |
| 803 | 654 | .addCFunction ("wait", l_emu_wait ) |
| 804 | 655 | .addCFunction ("after", l_emu_after ) |
| r242708 | r242709 | |
| 816 | 667 | .addFunction ("soft_reset", &running_machine::schedule_soft_reset) |
| 817 | 668 | .addFunction ("system", &running_machine::system) |
| 818 | 669 | .addProperty <luabridge::LuaRef, void> ("devices", &lua_engine::l_machine_get_devices) |
| 819 | | .addProperty <luabridge::LuaRef, void> ("screens", &lua_engine::l_machine_get_screens) |
| 820 | 670 | .endClass () |
| 821 | 671 | .beginClass <game_driver> ("game_driver") |
| 822 | 672 | .addData ("name", &game_driver::name) |
| r242708 | r242709 | |
| 841 | 691 | .deriveClass <address_space, lua_addr_space> ("addr_space") |
| 842 | 692 | .addFunction("name", &address_space::name) |
| 843 | 693 | .endClass() |
| 844 | | .beginClass <lua_screen> ("lua_screen_dev") |
| 845 | | .addCFunction ("draw_box", &lua_screen::l_draw_box) |
| 846 | | .addCFunction ("draw_line", &lua_screen::l_draw_line) |
| 847 | | .addCFunction ("draw_text", &lua_screen::l_draw_text) |
| 848 | | .endClass() |
| 849 | | .deriveClass <screen_device, lua_screen> ("screen_dev") |
| 850 | | .addFunction ("name", &screen_device::name) |
| 851 | | .addFunction ("height", &screen_device::height) |
| 852 | | .addFunction ("width", &screen_device::width) |
| 853 | | .endClass() |
| 854 | | .endNamespace(); |
| 694 | .endNamespace (); |
| 855 | 695 | |
| 856 | 696 | luabridge::push (m_lua_state, machine_manager::instance()); |
| 857 | 697 | lua_setglobal(m_lua_state, "manager"); |
| r242708 | r242709 | |
| 862 | 702 | mg_start_thread(::serve_lua, this); |
| 863 | 703 | } |
| 864 | 704 | |
| 865 | | //------------------------------------------------- |
| 866 | | // frame_hook - called at each frame refresh, used to draw a HUD |
| 867 | | //------------------------------------------------- |
| 868 | | bool lua_engine::frame_hook() |
| 869 | | { |
| 870 | | bool is_cb_hooked = false; |
| 871 | | if (m_machine != NULL) { |
| 872 | | // invoke registered callback (if any) |
| 873 | | is_cb_hooked = hook_frame_cb.active(); |
| 874 | | if (is_cb_hooked) { |
| 875 | | lua_State *L = hook_frame_cb.precall(); |
| 876 | | hook_frame_cb.call(this, L, 0); |
| 877 | | } |
| 878 | | } |
| 879 | | return is_cb_hooked; |
| 880 | | } |
| 881 | | |
| 882 | 705 | void lua_engine::periodic_check() |
| 883 | 706 | { |
| 884 | 707 | osd_lock_acquire(lock); |
trunk/src/mame/drivers/gts80a.c
| r242708 | r242709 | |
| 15 | 15 | #include "audio/gottlieb.h" |
| 16 | 16 | #include "cpu/i86/i86.h" |
| 17 | 17 | #include "gts80a.lh" |
| 18 | | #include "gts80a_caveman.lh" |
| 19 | 18 | |
| 20 | 19 | class gts80a_state : public genpin_class |
| 21 | 20 | { |
| r242708 | r242709 | |
| 385 | 384 | caveman_state(const machine_config &mconfig, device_type type, const char *tag) |
| 386 | 385 | : gts80a_state(mconfig, type, tag) |
| 387 | 386 | , m_videocpu(*this, "video_cpu") |
| 388 | | , m_vram(*this, "vram") |
| 389 | | |
| 390 | 387 | { } |
| 391 | 388 | |
| 392 | | |
| 393 | | UINT32 screen_update_caveman(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
| 394 | | |
| 395 | 389 | private: |
| 396 | 390 | required_device<cpu_device> m_videocpu; |
| 397 | | required_shared_ptr<UINT8> m_vram; |
| 398 | 391 | }; |
| 399 | 392 | |
| 400 | | UINT32 caveman_state::screen_update_caveman(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) |
| 401 | | { |
| 402 | | int count = 0; |
| 403 | | for (int y = 0; y < 256; y++) |
| 404 | | { |
| 405 | | for (int x = 0; x < 256; x += 4) |
| 406 | | { |
| 407 | | UINT8 pix = m_vram[count]; |
| 408 | | |
| 409 | | bitmap.pix16(y, x+0) = (pix >> 6)&0x3; |
| 410 | | bitmap.pix16(y, x+1) = (pix >> 4)&0x3; |
| 411 | | bitmap.pix16(y, x+2) = (pix >> 2)&0x3; |
| 412 | | bitmap.pix16(y, x+3) = (pix >> 0)&0x3; |
| 413 | | |
| 414 | | count++; |
| 415 | | } |
| 416 | | } |
| 417 | | |
| 418 | | return 0; |
| 419 | | } |
| 420 | | |
| 421 | | |
| 422 | 393 | static ADDRESS_MAP_START( video_map, AS_PROGRAM, 8, caveman_state ) |
| 423 | 394 | ADDRESS_MAP_GLOBAL_MASK(0xffff) |
| 424 | | AM_RANGE(0x0000, 0x07ff) AM_RAM |
| 425 | | AM_RANGE(0x2000, 0x5fff) AM_RAM AM_SHARE("vram") |
| 395 | AM_RANGE(0x0000, 0x5fff) AM_RAM |
| 426 | 396 | AM_RANGE(0x8000, 0xffff) AM_ROM |
| 427 | 397 | ADDRESS_MAP_END |
| 428 | 398 | |
| 429 | 399 | static ADDRESS_MAP_START( video_io_map, AS_IO, 8, caveman_state ) |
| 430 | | // AM_RANGE(0x000, 0x002) AM_READWRITE() // 8259 irq controller |
| 431 | | // AM_RANGE(0x100, 0x102) AM_READWRITE() // HD46505 |
| 432 | | // AM_RANGE(0x200, 0x200) AM_READWRITE() // 8212 in, ?? out |
| 433 | | // AM_RANGE(0x300, 0x300) AM_READWRITE() // soundlatch (command?) in, ?? out |
| 434 | | |
| 435 | | // AM_RANGE(0x400, 0x400) AM_READ() // joystick inputs |
| 436 | | // AM_RANGE(0x500, 0x506) AM_WRITE() // palette |
| 437 | | |
| 438 | 400 | ADDRESS_MAP_END |
| 439 | 401 | |
| 440 | | static MACHINE_CONFIG_DERIVED_CLASS( caveman, gts80a_ss, caveman_state ) |
| 402 | static MACHINE_CONFIG_DERIVED( caveman, gts80a_ss ) |
| 441 | 403 | MCFG_CPU_ADD("video_cpu", I8088, 5000000) |
| 442 | 404 | MCFG_CPU_PROGRAM_MAP(video_map) |
| 443 | 405 | MCFG_CPU_IO_MAP(video_io_map) |
| 444 | | |
| 445 | | MCFG_SCREEN_ADD("screen", RASTER) |
| 446 | | MCFG_SCREEN_REFRESH_RATE(60) |
| 447 | | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0)) |
| 448 | | MCFG_SCREEN_SIZE(256, 256) |
| 449 | | MCFG_SCREEN_VISIBLE_AREA(0, 256-1, 0, 248-1) |
| 450 | | MCFG_SCREEN_UPDATE_DRIVER(caveman_state, screen_update_caveman) |
| 451 | | MCFG_SCREEN_PALETTE("palette") |
| 452 | | |
| 453 | | MCFG_PALETTE_ADD("palette", 16) |
| 454 | | |
| 455 | | MCFG_DEFAULT_LAYOUT(layout_gts80a_caveman) |
| 456 | | |
| 457 | 406 | MACHINE_CONFIG_END |
| 458 | 407 | |
| 459 | 408 | static INPUT_PORTS_START( caveman ) |
trunk/src/mame/layout/gts80a_caveman.lay
| r242708 | r242709 | |
| 1 | | <!-- GTS80A copied from gts80.lay --> |
| 2 | | |
| 3 | | <!-- 2014-10-10: Initial version. [Robbbert] --> |
| 4 | | |
| 5 | | <mamelayout version="2"> |
| 6 | | |
| 7 | | <element name="digit" defstate="0"> |
| 8 | | <led14seg> |
| 9 | | <color red="0.0" green="0.75" blue="1.0" /> |
| 10 | | </led14seg> |
| 11 | | </element> |
| 12 | | <element name="digit7" defstate="0"> |
| 13 | | <led7seg> |
| 14 | | <color red="0.0" green="0.75" blue="1.0" /> |
| 15 | | </led7seg> |
| 16 | | </element> |
| 17 | | <element name="red_led"> |
| 18 | | <disk><color red="1.0" green="0.0" blue="0.0" /></disk> |
| 19 | | </element> |
| 20 | | <element name="background"> |
| 21 | | <rect> |
| 22 | | <bounds left="0" top="0" right="1" bottom="1" /> |
| 23 | | <color red="0.0" green="0.0" blue="0.0" /> |
| 24 | | </rect> |
| 25 | | </element> |
| 26 | | <element name="P0"><text string="Ball / Match"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 27 | | <element name="P1"><text string="Credits"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 28 | | <element name="P3"><text string="Player 1"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 29 | | <element name="P4"><text string="Player 2"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 30 | | <element name="P5"><text string="Player 3"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 31 | | <element name="P6"><text string="Player 4"><color red="1.0" green="1.0" blue="1.0" /></text></element> |
| 32 | | |
| 33 | | <view name="Default Layout"> |
| 34 | | |
| 35 | | <!-- Background --> |
| 36 | | <backdrop element="background"> |
| 37 | | <bounds left="0" top="20" right="318" bottom="394" /> |
| 38 | | </backdrop> |
| 39 | | |
| 40 | | <!-- LEDs --> |
| 41 | | |
| 42 | | <!-- Player 1 Score --> |
| 43 | | |
| 44 | | <bezel name="digit15" element="digit"> |
| 45 | | <bounds left="10" top="45" right="44" bottom="84" /> |
| 46 | | </bezel> |
| 47 | | <bezel name="digit5" element="digit"> |
| 48 | | <bounds left="54" top="45" right="88" bottom="84" /> |
| 49 | | </bezel> |
| 50 | | <bezel name="digit4" element="digit"> |
| 51 | | <bounds left="98" top="45" right="132" bottom="84" /> |
| 52 | | </bezel> |
| 53 | | <bezel name="digit3" element="digit"> |
| 54 | | <bounds left="142" top="45" right="176" bottom="84" /> |
| 55 | | </bezel> |
| 56 | | <bezel name="digit2" element="digit"> |
| 57 | | <bounds left="186" top="45" right="220" bottom="84" /> |
| 58 | | </bezel> |
| 59 | | <bezel name="digit1" element="digit"> |
| 60 | | <bounds left="230" top="45" right="264" bottom="84" /> |
| 61 | | </bezel> |
| 62 | | <bezel name="digit0" element="digit"> |
| 63 | | <bounds left="274" top="45" right="308" bottom="84" /> |
| 64 | | </bezel> |
| 65 | | |
| 66 | | <!-- Player 2 Score --> |
| 67 | | <bezel name="digit12" element="digit"> |
| 68 | | <bounds left="10" top="105" right="44" bottom="144" /> |
| 69 | | </bezel> |
| 70 | | <bezel name="digit11" element="digit"> |
| 71 | | <bounds left="54" top="105" right="88" bottom="144" /> |
| 72 | | </bezel> |
| 73 | | <bezel name="digit10" element="digit"> |
| 74 | | <bounds left="98" top="105" right="132" bottom="144" /> |
| 75 | | </bezel> |
| 76 | | <bezel name="digit9" element="digit"> |
| 77 | | <bounds left="142" top="105" right="176" bottom="144" /> |
| 78 | | </bezel> |
| 79 | | <bezel name="digit8" element="digit"> |
| 80 | | <bounds left="186" top="105" right="220" bottom="144" /> |
| 81 | | </bezel> |
| 82 | | <bezel name="digit7" element="digit"> |
| 83 | | <bounds left="230" top="105" right="264" bottom="144" /> |
| 84 | | </bezel> |
| 85 | | <bezel name="digit6" element="digit"> |
| 86 | | <bounds left="274" top="105" right="308" bottom="144" /> |
| 87 | | </bezel> |
| 88 | | |
| 89 | | <!-- Player 3 Score --> |
| 90 | | <bezel name="digit35" element="digit"> |
| 91 | | <bounds left="10" top="165" right="44" bottom="204" /> |
| 92 | | </bezel> |
| 93 | | <bezel name="digit25" element="digit"> |
| 94 | | <bounds left="54" top="165" right="88" bottom="204" /> |
| 95 | | </bezel> |
| 96 | | <bezel name="digit24" element="digit"> |
| 97 | | <bounds left="98" top="165" right="132" bottom="204" /> |
| 98 | | </bezel> |
| 99 | | <bezel name="digit23" element="digit"> |
| 100 | | <bounds left="142" top="165" right="176" bottom="204" /> |
| 101 | | </bezel> |
| 102 | | <bezel name="digit22" element="digit"> |
| 103 | | <bounds left="186" top="165" right="220" bottom="204" /> |
| 104 | | </bezel> |
| 105 | | <bezel name="digit21" element="digit"> |
| 106 | | <bounds left="230" top="165" right="264" bottom="204" /> |
| 107 | | </bezel> |
| 108 | | <bezel name="digit20" element="digit"> |
| 109 | | <bounds left="274" top="165" right="308" bottom="204" /> |
| 110 | | </bezel> |
| 111 | | |
| 112 | | <!-- Player 4 Score --> |
| 113 | | <bezel name="digit32" element="digit"> |
| 114 | | <bounds left="10" top="225" right="44" bottom="264" /> |
| 115 | | </bezel> |
| 116 | | <bezel name="digit31" element="digit"> |
| 117 | | <bounds left="54" top="225" right="88" bottom="264" /> |
| 118 | | </bezel> |
| 119 | | <bezel name="digit30" element="digit"> |
| 120 | | <bounds left="98" top="225" right="132" bottom="264" /> |
| 121 | | </bezel> |
| 122 | | <bezel name="digit29" element="digit"> |
| 123 | | <bounds left="142" top="225" right="176" bottom="264" /> |
| 124 | | </bezel> |
| 125 | | <bezel name="digit28" element="digit"> |
| 126 | | <bounds left="186" top="225" right="220" bottom="264" /> |
| 127 | | </bezel> |
| 128 | | <bezel name="digit27" element="digit"> |
| 129 | | <bounds left="230" top="225" right="264" bottom="264" /> |
| 130 | | </bezel> |
| 131 | | <bezel name="digit26" element="digit"> |
| 132 | | <bounds left="274" top="225" right="308" bottom="264" /> |
| 133 | | </bezel> |
| 134 | | |
| 135 | | <!-- Credits and Balls --> |
| 136 | | <bezel name="digit55" element="digit7"> |
| 137 | | <bounds left="30" top="345" right="64" bottom="384" /> |
| 138 | | </bezel> |
| 139 | | <bezel name="digit54" element="digit7"> |
| 140 | | <bounds left="69" top="345" right="103" bottom="384" /> |
| 141 | | </bezel> |
| 142 | | <bezel name="digit53" element="digit7"> |
| 143 | | <bounds left="171" top="345" right="205" bottom="384" /> |
| 144 | | </bezel> |
| 145 | | <bezel name="digit52" element="digit7"> |
| 146 | | <bounds left="210" top="345" right="244" bottom="384" /> |
| 147 | | </bezel> |
| 148 | | <bezel element="P0"><bounds left="200" right="258" top="330" bottom="342" /></bezel> |
| 149 | | <bezel element="P1"><bounds left="50" right="108" top="330" bottom="342" /></bezel> |
| 150 | | <bezel name="text3" element="P3"><bounds left="100" right="180" top="30" bottom="42" /></bezel> |
| 151 | | <bezel name="text2" element="P4"><bounds left="100" right="180" top="90" bottom="102" /></bezel> |
| 152 | | <bezel name="text1" element="P5"><bounds left="100" right="180" top="150" bottom="162" /></bezel> |
| 153 | | <bezel name="text0" element="P6"><bounds left="100" right="180" top="210" bottom="222" /></bezel> |
| 154 | | |
| 155 | | <screen index="0"> |
| 156 | | <bounds x="320" y="0" width="320" height="240" /> |
| 157 | | </screen> |
| 158 | | </view> |
| 159 | | </mamelayout> |
trunk/src/osd/modules/sync/osdsync.h
| r0 | r242709 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // winsync.h - Windows core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2014, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | //============================================================ |
| 9 | |
| 10 | #ifndef __OSDSYNC__ |
| 11 | #define __OSDSYNC__ |
| 12 | |
| 13 | /*************************************************************************** |
| 14 | SYNCHRONIZATION INTERFACES - Events |
| 15 | ***************************************************************************/ |
| 16 | |
| 17 | /* osd_event is an opaque type which represents a setable/resetable event */ |
| 18 | |
| 19 | struct osd_event; |
| 20 | |
| 21 | |
| 22 | /*----------------------------------------------------------------------------- |
| 23 | osd_lock_event_alloc: allocate a new event |
| 24 | |
| 25 | Parameters: |
| 26 | |
| 27 | manualreset - boolean. If true, the event will be automatically set |
| 28 | to non-signalled after a thread successfully waited for |
| 29 | it. |
| 30 | initialstate - boolean. If true, the event is signalled initially. |
| 31 | |
| 32 | Return value: |
| 33 | |
| 34 | A pointer to the allocated event. |
| 35 | -----------------------------------------------------------------------------*/ |
| 36 | osd_event *osd_event_alloc(int manualreset, int initialstate); |
| 37 | |
| 38 | |
| 39 | /*----------------------------------------------------------------------------- |
| 40 | osd_event_wait: wait for an event to be signalled |
| 41 | |
| 42 | Parameters: |
| 43 | |
| 44 | event - The event to wait for. If the event is in signalled state, the |
| 45 | function returns immediately. If not it will wait for the event |
| 46 | to become signalled. |
| 47 | timeout - timeout in osd_ticks |
| 48 | |
| 49 | Return value: |
| 50 | |
| 51 | TRUE: The event was signalled |
| 52 | FALSE: A timeout occurred |
| 53 | -----------------------------------------------------------------------------*/ |
| 54 | int osd_event_wait(osd_event *event, osd_ticks_t timeout); |
| 55 | |
| 56 | |
| 57 | /*----------------------------------------------------------------------------- |
| 58 | osd_event_reset: reset an event to non-signalled state |
| 59 | |
| 60 | Parameters: |
| 61 | |
| 62 | event - The event to set to non-signalled state |
| 63 | |
| 64 | Return value: |
| 65 | |
| 66 | None |
| 67 | -----------------------------------------------------------------------------*/ |
| 68 | void osd_event_reset(osd_event *event); |
| 69 | |
| 70 | |
| 71 | /*----------------------------------------------------------------------------- |
| 72 | osd_event_set: set an event to signalled state |
| 73 | |
| 74 | Parameters: |
| 75 | |
| 76 | event - The event to set to signalled state |
| 77 | |
| 78 | Return value: |
| 79 | |
| 80 | None |
| 81 | |
| 82 | Notes: |
| 83 | |
| 84 | All threads waiting for the event will be signalled. |
| 85 | -----------------------------------------------------------------------------*/ |
| 86 | void osd_event_set(osd_event *event); |
| 87 | |
| 88 | |
| 89 | /*----------------------------------------------------------------------------- |
| 90 | osd_event_free: free the memory and resources associated with an osd_event |
| 91 | |
| 92 | Parameters: |
| 93 | |
| 94 | event - a pointer to a previously allocated osd_event. |
| 95 | |
| 96 | Return value: |
| 97 | |
| 98 | None. |
| 99 | -----------------------------------------------------------------------------*/ |
| 100 | void osd_event_free(osd_event *event); |
| 101 | |
| 102 | /*************************************************************************** |
| 103 | SYNCHRONIZATION INTERFACES - Threads |
| 104 | ***************************************************************************/ |
| 105 | |
| 106 | /* osd_thread is an opaque type which represents a thread */ |
| 107 | struct osd_thread; |
| 108 | |
| 109 | |
| 110 | /* osd_thread_callback is a callback function that will be called from the thread */ |
| 111 | typedef void *(*osd_thread_callback)(void *param); |
| 112 | |
| 113 | |
| 114 | /*----------------------------------------------------------------------------- |
| 115 | osd_thread_create: create a new thread |
| 116 | |
| 117 | Parameters: |
| 118 | |
| 119 | callback - The callback function to be called once the thread is up |
| 120 | cbparam - The parameter to pass to the callback function. |
| 121 | |
| 122 | Return value: |
| 123 | |
| 124 | A pointer to the created thread. |
| 125 | -----------------------------------------------------------------------------*/ |
| 126 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam); |
| 127 | |
| 128 | /*----------------------------------------------------------------------------- |
| 129 | osd_thread_adjust_priority: adjust priority of a thread |
| 130 | |
| 131 | Parameters: |
| 132 | |
| 133 | thread - A pointer to a previously created thread. |
| 134 | adjust - signed integer to add to the thread priority |
| 135 | |
| 136 | Return value: |
| 137 | |
| 138 | TRUE on success, FALSE on failure |
| 139 | -----------------------------------------------------------------------------*/ |
| 140 | int osd_thread_adjust_priority(osd_thread *thread, int adjust); |
| 141 | |
| 142 | |
| 143 | /*----------------------------------------------------------------------------- |
| 144 | osd_thread_cpu_affinity: change cpu affinity of a thread |
| 145 | |
| 146 | Parameters: |
| 147 | |
| 148 | thread - A pointer to a previously created thread |
| 149 | or NULL for main thread |
| 150 | mask - bitmask to which cpus to bind |
| 151 | i.e. 0x01 1st cpu, 0x02, 2nd cpu, 0x04 3rd cpu |
| 152 | |
| 153 | Return value: |
| 154 | |
| 155 | TRUE on success, FALSE on failure |
| 156 | -----------------------------------------------------------------------------*/ |
| 157 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask); |
| 158 | |
| 159 | |
| 160 | /*----------------------------------------------------------------------------- |
| 161 | osd_thread_wait_free: wait for thread to finish and free resources |
| 162 | |
| 163 | Parameters: |
| 164 | |
| 165 | thread - A pointer to a previously created thread. |
| 166 | |
| 167 | Return value: |
| 168 | |
| 169 | None. |
| 170 | -----------------------------------------------------------------------------*/ |
| 171 | void osd_thread_wait_free(osd_thread *thread); |
| 172 | |
| 173 | /*----------------------------------------------------------------------------- |
| 174 | osd_process_kill: kill the current process |
| 175 | |
| 176 | Parameters: |
| 177 | |
| 178 | None. |
| 179 | |
| 180 | Return value: |
| 181 | |
| 182 | None. |
| 183 | -----------------------------------------------------------------------------*/ |
| 184 | void osd_process_kill(void); |
| 185 | |
| 186 | //============================================================ |
| 187 | // Scalable Locks |
| 188 | //============================================================ |
| 189 | |
| 190 | struct osd_scalable_lock; |
| 191 | |
| 192 | osd_scalable_lock *osd_scalable_lock_alloc(void); |
| 193 | |
| 194 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock); |
| 195 | |
| 196 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot); |
| 197 | |
| 198 | void osd_scalable_lock_free(osd_scalable_lock *lock); |
| 199 | |
| 200 | #endif /* __OSDSYNC__ */ |
trunk/src/osd/modules/sync/sync_mini.c
| r0 | r242709 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Aaron Giles |
| 3 | //============================================================ |
| 4 | // |
| 5 | // sdlsync_mini.c - Minimal core synchronization functions |
| 6 | // |
| 7 | //============================================================ |
| 8 | |
| 9 | #include "osdcore.h" |
| 10 | #include "osdsync.h" |
| 11 | |
| 12 | struct _osd_event |
| 13 | { |
| 14 | void * ptr; |
| 15 | }; |
| 16 | |
| 17 | struct _osd_thread { |
| 18 | void * ptr; |
| 19 | }; |
| 20 | |
| 21 | |
| 22 | //============================================================ |
| 23 | // osd_lock_alloc |
| 24 | //============================================================ |
| 25 | |
| 26 | osd_lock *osd_lock_alloc(void) |
| 27 | { |
| 28 | // the minimal implementation does not support threading |
| 29 | // just return a dummy value here |
| 30 | return (osd_lock *)1; |
| 31 | } |
| 32 | |
| 33 | |
| 34 | //============================================================ |
| 35 | // osd_lock_acquire |
| 36 | //============================================================ |
| 37 | |
| 38 | void osd_lock_acquire(osd_lock *lock) |
| 39 | { |
| 40 | // the minimal implementation does not support threading |
| 41 | // the acquire always "succeeds" |
| 42 | } |
| 43 | |
| 44 | |
| 45 | //============================================================ |
| 46 | // osd_lock_try |
| 47 | //============================================================ |
| 48 | |
| 49 | int osd_lock_try(osd_lock *lock) |
| 50 | { |
| 51 | // the minimal implementation does not support threading |
| 52 | // the acquire always "succeeds" |
| 53 | return TRUE; |
| 54 | } |
| 55 | |
| 56 | |
| 57 | //============================================================ |
| 58 | // osd_lock_release |
| 59 | //============================================================ |
| 60 | |
| 61 | void osd_lock_release(osd_lock *lock) |
| 62 | { |
| 63 | // the minimal implementation does not support threading |
| 64 | // do nothing here |
| 65 | } |
| 66 | |
| 67 | |
| 68 | //============================================================ |
| 69 | // osd_lock_free |
| 70 | //============================================================ |
| 71 | |
| 72 | void osd_lock_free(osd_lock *lock) |
| 73 | { |
| 74 | // the minimal implementation does not support threading |
| 75 | // do nothing here |
| 76 | } |
| 77 | |
| 78 | |
| 79 | //============================================================ |
| 80 | // osd_event_alloc |
| 81 | //============================================================ |
| 82 | |
| 83 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 84 | { |
| 85 | return NULL; |
| 86 | } |
| 87 | |
| 88 | |
| 89 | //============================================================ |
| 90 | // osd_event_free |
| 91 | //============================================================ |
| 92 | |
| 93 | void osd_event_free(osd_event *event) |
| 94 | { |
| 95 | } |
| 96 | |
| 97 | |
| 98 | //============================================================ |
| 99 | // osd_event_set |
| 100 | //============================================================ |
| 101 | |
| 102 | void osd_event_set(osd_event *event) |
| 103 | { |
| 104 | } |
| 105 | |
| 106 | |
| 107 | //============================================================ |
| 108 | // osd_event_reset |
| 109 | //============================================================ |
| 110 | |
| 111 | void osd_event_reset(osd_event *event) |
| 112 | { |
| 113 | } |
| 114 | |
| 115 | |
| 116 | //============================================================ |
| 117 | // osd_event_wait |
| 118 | //============================================================ |
| 119 | |
| 120 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 121 | { |
| 122 | return TRUE; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | //============================================================ |
| 127 | // osd_thread_create |
| 128 | //============================================================ |
| 129 | |
| 130 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 131 | { |
| 132 | return NULL; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | //============================================================ |
| 137 | // osd_thread_adjust_priority |
| 138 | //============================================================ |
| 139 | |
| 140 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 141 | { |
| 142 | return FALSE; |
| 143 | } |
| 144 | |
| 145 | |
| 146 | //============================================================ |
| 147 | // osd_thread_cpu_affinity |
| 148 | //============================================================ |
| 149 | |
| 150 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 151 | { |
| 152 | return TRUE; |
| 153 | } |
| 154 | |
| 155 | |
| 156 | //============================================================ |
| 157 | // osd_thread_wait_free |
| 158 | //============================================================ |
| 159 | |
| 160 | void osd_thread_wait_free(osd_thread *thread) |
| 161 | { |
| 162 | } |
| 163 | |
| 164 | |
| 165 | //============================================================ |
| 166 | // osd_process_kill |
| 167 | //============================================================ |
| 168 | |
| 169 | void osd_process_kill(void) |
| 170 | { |
| 171 | } |
trunk/src/osd/modules/sync/sync_ntc.c
| r0 | r242709 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // sdlsync.c - SDL core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2011, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #ifndef _GNU_SOURCE |
| 13 | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | #endif |
| 15 | |
| 16 | #include "sdlinc.h" |
| 17 | |
| 18 | #ifdef SDLMAME_MACOSX |
| 19 | #include <mach/mach.h> |
| 20 | #include <signal.h> |
| 21 | #endif |
| 22 | |
| 23 | #if defined(SDLMAME_NETBSD) || defined(SDLMAME_OPENBSD) |
| 24 | /* for SIGKILL */ |
| 25 | #include <signal.h> |
| 26 | #endif |
| 27 | |
| 28 | // standard C headers |
| 29 | #include <math.h> |
| 30 | #include <unistd.h> |
| 31 | |
| 32 | // MAME headers |
| 33 | #include "osdcore.h" |
| 34 | #include "osinline.h" |
| 35 | #include "osdsync.h" |
| 36 | |
| 37 | #include "eminline.h" |
| 38 | |
| 39 | #include <pthread.h> |
| 40 | #include <errno.h> |
| 41 | #include <sys/time.h> |
| 42 | |
| 43 | struct osd_lock { |
| 44 | volatile pthread_t holder; |
| 45 | INT32 count; |
| 46 | #ifdef PTR64 |
| 47 | INT8 padding[52]; // Fill a 64-byte cache line |
| 48 | #else |
| 49 | INT8 padding[56]; // A bit more padding |
| 50 | #endif |
| 51 | }; |
| 52 | |
| 53 | struct osd_event { |
| 54 | pthread_mutex_t mutex; |
| 55 | pthread_cond_t cond; |
| 56 | volatile INT32 autoreset; |
| 57 | volatile INT32 signalled; |
| 58 | #ifdef PTR64 |
| 59 | INT8 padding[40]; // Fill a 64-byte cache line |
| 60 | #else |
| 61 | INT8 padding[48]; // A bit more padding |
| 62 | #endif |
| 63 | }; |
| 64 | |
| 65 | |
| 66 | //============================================================ |
| 67 | // TYPE DEFINITIONS |
| 68 | //============================================================ |
| 69 | |
| 70 | struct osd_thread { |
| 71 | pthread_t thread; |
| 72 | }; |
| 73 | |
| 74 | struct osd_scalable_lock |
| 75 | { |
| 76 | struct |
| 77 | { |
| 78 | volatile INT32 haslock; // do we have the lock? |
| 79 | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 80 | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 81 | volatile INT32 nextindex; // index of next slot to use |
| 82 | }; |
| 83 | |
| 84 | |
| 85 | //============================================================ |
| 86 | // Scalable Locks |
| 87 | //============================================================ |
| 88 | |
| 89 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 90 | { |
| 91 | osd_scalable_lock *lock; |
| 92 | |
| 93 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 94 | |
| 95 | memset(lock, 0, sizeof(*lock)); |
| 96 | lock->slot[0].haslock = TRUE; |
| 97 | return lock; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 102 | { |
| 103 | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 104 | |
| 105 | #if defined(__i386__) || defined(__x86_64__) |
| 106 | register INT32 tmp; |
| 107 | __asm__ __volatile__ ( |
| 108 | "1: clr %[tmp] ;" |
| 109 | " xchg %[haslock], %[tmp] ;" |
| 110 | " test %[tmp], %[tmp] ;" |
| 111 | " jne 3f ;" |
| 112 | "2: mov %[haslock], %[tmp] ;" |
| 113 | " test %[tmp], %[tmp] ;" |
| 114 | " jne 1b ;" |
| 115 | " pause ;" |
| 116 | " jmp 2b ;" |
| 117 | "3: " |
| 118 | : [haslock] "+m" (lock->slot[myslot].haslock) |
| 119 | , [tmp] "=&r" (tmp) |
| 120 | : |
| 121 | : "cc" |
| 122 | ); |
| 123 | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 124 | register INT32 tmp; |
| 125 | __asm__ __volatile__ ( |
| 126 | "1: lwarx %[tmp], 0, %[haslock] \n" |
| 127 | " cmpwi %[tmp], 0 \n" |
| 128 | " bne 3f \n" |
| 129 | "2: lwzx %[tmp], 0, %[haslock] \n" |
| 130 | " cmpwi %[tmp], 0 \n" |
| 131 | " bne 1b \n" |
| 132 | " nop \n" |
| 133 | " nop \n" |
| 134 | " b 2b \n" |
| 135 | "3: li %[tmp], 0 \n" |
| 136 | " sync \n" |
| 137 | " stwcx. %[tmp], 0, %[haslock] \n" |
| 138 | " bne- 1b \n" |
| 139 | " eieio \n" |
| 140 | : [tmp] "=&r" (tmp) |
| 141 | : [haslock] "r" (&lock->slot[myslot].haslock) |
| 142 | : "cr0" |
| 143 | ); |
| 144 | #else |
| 145 | INT32 backoff = 1; |
| 146 | while (!osd_compare_exchange32(&lock->slot[myslot].haslock, TRUE, FALSE)) |
| 147 | { |
| 148 | INT32 backcount; |
| 149 | for (backcount = 0; backcount < backoff; backcount++) |
| 150 | osd_yield_processor(); |
| 151 | backoff <<= 1; |
| 152 | } |
| 153 | #endif |
| 154 | return myslot; |
| 155 | } |
| 156 | |
| 157 | |
| 158 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 159 | { |
| 160 | #if defined(__i386__) || defined(__x86_64__) |
| 161 | register INT32 tmp = TRUE; |
| 162 | __asm__ __volatile__ ( |
| 163 | " xchg %[haslock], %[tmp] ;" |
| 164 | : [haslock] "+m" (lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock) |
| 165 | , [tmp] "+r" (tmp) |
| 166 | : |
| 167 | ); |
| 168 | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 169 | lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock = TRUE; |
| 170 | __asm__ __volatile__ ( " eieio " : : ); |
| 171 | #else |
| 172 | osd_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 173 | #endif |
| 174 | } |
| 175 | |
| 176 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 177 | { |
| 178 | free(lock); |
| 179 | } |
| 180 | |
| 181 | INLINE pthread_t osd_compare_exchange_pthread_t(pthread_t volatile *ptr, pthread_t compare, pthread_t exchange) |
| 182 | { |
| 183 | #ifdef PTR64 |
| 184 | INT64 result = compare_exchange64((INT64 volatile *)ptr, (INT64)compare, (INT64)exchange); |
| 185 | #else |
| 186 | INT32 result = compare_exchange32((INT32 volatile *)ptr, (INT32)compare, (INT32)exchange); |
| 187 | #endif |
| 188 | return (pthread_t)result; |
| 189 | } |
| 190 | |
| 191 | INLINE pthread_t osd_exchange_pthread_t(pthread_t volatile *ptr, pthread_t exchange) |
| 192 | { |
| 193 | #ifdef PTR64 |
| 194 | INT64 result = osd_exchange64((INT64 volatile *)ptr, (INT64)exchange); |
| 195 | #else |
| 196 | INT32 result = atomic_exchange32((INT32 volatile *)ptr, (INT32)exchange); |
| 197 | #endif |
| 198 | return (pthread_t)result; |
| 199 | } |
| 200 | |
| 201 | |
| 202 | //============================================================ |
| 203 | // osd_lock_alloc |
| 204 | //============================================================ |
| 205 | |
| 206 | osd_lock *osd_lock_alloc(void) |
| 207 | { |
| 208 | osd_lock *lock; |
| 209 | |
| 210 | lock = (osd_lock *)calloc(1, sizeof(osd_lock)); |
| 211 | |
| 212 | lock->holder = 0; |
| 213 | lock->count = 0; |
| 214 | |
| 215 | return lock; |
| 216 | } |
| 217 | |
| 218 | //============================================================ |
| 219 | // osd_lock_acquire |
| 220 | //============================================================ |
| 221 | |
| 222 | void osd_lock_acquire(osd_lock *lock) |
| 223 | { |
| 224 | pthread_t current, prev; |
| 225 | |
| 226 | current = pthread_self(); |
| 227 | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 228 | if (prev != (size_t)NULL && prev != current) |
| 229 | { |
| 230 | do { |
| 231 | register INT32 spin = 10000; // Convenient spin count |
| 232 | register pthread_t tmp; |
| 233 | #if defined(__i386__) || defined(__x86_64__) |
| 234 | __asm__ __volatile__ ( |
| 235 | "1: pause ;" |
| 236 | " mov %[holder], %[tmp] ;" |
| 237 | " test %[tmp], %[tmp] ;" |
| 238 | " loopne 1b ;" |
| 239 | : [spin] "+c" (spin) |
| 240 | , [tmp] "=&r" (tmp) |
| 241 | : [holder] "m" (lock->holder) |
| 242 | : "cc" |
| 243 | ); |
| 244 | #elif defined(__ppc__) || defined(__PPC__) |
| 245 | __asm__ __volatile__ ( |
| 246 | "1: nop \n" |
| 247 | " nop \n" |
| 248 | " lwzx %[tmp], 0, %[holder] \n" |
| 249 | " cmpwi %[tmp], 0 \n" |
| 250 | " bdnzt eq, 1b \n" |
| 251 | : [spin] "+c" (spin) |
| 252 | , [tmp] "=&r" (tmp) |
| 253 | : [holder] "r" (&lock->holder) |
| 254 | : "cr0" |
| 255 | ); |
| 256 | #elif defined(__ppc64__) || defined(__PPC64__) |
| 257 | __asm__ __volatile__ ( |
| 258 | "1: nop \n" |
| 259 | " nop \n" |
| 260 | " ldx %[tmp], 0, %[holder] \n" |
| 261 | " cmpdi %[tmp], 0 \n" |
| 262 | " bdnzt eq, 1b \n" |
| 263 | : [spin] "+c" (spin) |
| 264 | , [tmp] "=&r" (tmp) |
| 265 | : [holder] "r" (&lock->holder) |
| 266 | : "cr0" |
| 267 | ); |
| 268 | #else |
| 269 | while (--spin > 0 && lock->holder != NULL) |
| 270 | osd_yield_processor(); |
| 271 | #endif |
| 272 | #if 0 |
| 273 | /* If you mean to use locks as a blocking mechanism for extended |
| 274 | * periods of time, you should do something like this. However, |
| 275 | * it kills the performance of gaelco3d. |
| 276 | */ |
| 277 | if (spin == 0) |
| 278 | { |
| 279 | struct timespec sleep = { 0, 100000 }, remaining; |
| 280 | nanosleep(&sleep, &remaining); // sleep for 100us |
| 281 | } |
| 282 | #endif |
| 283 | } while (osd_compare_exchange_pthread_t(&lock->holder, 0, current) != (size_t)NULL); |
| 284 | } |
| 285 | lock->count++; |
| 286 | } |
| 287 | |
| 288 | //============================================================ |
| 289 | // osd_lock_try |
| 290 | //============================================================ |
| 291 | |
| 292 | int osd_lock_try(osd_lock *lock) |
| 293 | { |
| 294 | pthread_t current, prev; |
| 295 | |
| 296 | current = pthread_self(); |
| 297 | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 298 | if (prev == (size_t)NULL || prev == current) |
| 299 | { |
| 300 | lock->count++; |
| 301 | return 1; |
| 302 | } |
| 303 | return 0; |
| 304 | } |
| 305 | |
| 306 | //============================================================ |
| 307 | // osd_lock_release |
| 308 | //============================================================ |
| 309 | |
| 310 | void osd_lock_release(osd_lock *lock) |
| 311 | { |
| 312 | pthread_t current; |
| 313 | |
| 314 | current = pthread_self(); |
| 315 | if (lock->holder == current) |
| 316 | { |
| 317 | if (--lock->count == 0) |
| 318 | #if defined(__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 319 | lock->holder = 0; |
| 320 | __asm__ __volatile__( " eieio " : : ); |
| 321 | #else |
| 322 | osd_exchange_pthread_t(&lock->holder, 0); |
| 323 | #endif |
| 324 | return; |
| 325 | } |
| 326 | |
| 327 | // trying to release a lock you don't hold is bad! |
| 328 | // assert(lock->holder == pthread_self()); |
| 329 | } |
| 330 | |
| 331 | //============================================================ |
| 332 | // osd_lock_free |
| 333 | //============================================================ |
| 334 | |
| 335 | void osd_lock_free(osd_lock *lock) |
| 336 | { |
| 337 | free(lock); |
| 338 | } |
| 339 | |
| 340 | //============================================================ |
| 341 | // osd_event_alloc |
| 342 | //============================================================ |
| 343 | |
| 344 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 345 | { |
| 346 | osd_event *ev; |
| 347 | pthread_mutexattr_t mtxattr; |
| 348 | |
| 349 | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 350 | |
| 351 | pthread_mutexattr_init(&mtxattr); |
| 352 | pthread_mutex_init(&ev->mutex, &mtxattr); |
| 353 | pthread_cond_init(&ev->cond, NULL); |
| 354 | ev->signalled = initialstate; |
| 355 | ev->autoreset = !manualreset; |
| 356 | |
| 357 | return ev; |
| 358 | } |
| 359 | |
| 360 | //============================================================ |
| 361 | // osd_event_free |
| 362 | //============================================================ |
| 363 | |
| 364 | void osd_event_free(osd_event *event) |
| 365 | { |
| 366 | pthread_mutex_destroy(&event->mutex); |
| 367 | pthread_cond_destroy(&event->cond); |
| 368 | free(event); |
| 369 | } |
| 370 | |
| 371 | //============================================================ |
| 372 | // osd_event_set |
| 373 | //============================================================ |
| 374 | |
| 375 | void osd_event_set(osd_event *event) |
| 376 | { |
| 377 | pthread_mutex_lock(&event->mutex); |
| 378 | if (event->signalled == FALSE) |
| 379 | { |
| 380 | event->signalled = TRUE; |
| 381 | if (event->autoreset) |
| 382 | pthread_cond_signal(&event->cond); |
| 383 | else |
| 384 | pthread_cond_broadcast(&event->cond); |
| 385 | } |
| 386 | pthread_mutex_unlock(&event->mutex); |
| 387 | } |
| 388 | |
| 389 | //============================================================ |
| 390 | // osd_event_reset |
| 391 | //============================================================ |
| 392 | |
| 393 | void osd_event_reset(osd_event *event) |
| 394 | { |
| 395 | pthread_mutex_lock(&event->mutex); |
| 396 | event->signalled = FALSE; |
| 397 | pthread_mutex_unlock(&event->mutex); |
| 398 | } |
| 399 | |
| 400 | //============================================================ |
| 401 | // osd_event_wait |
| 402 | //============================================================ |
| 403 | |
| 404 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 405 | { |
| 406 | pthread_mutex_lock(&event->mutex); |
| 407 | if (!timeout) |
| 408 | { |
| 409 | if (!event->signalled) |
| 410 | { |
| 411 | pthread_mutex_unlock(&event->mutex); |
| 412 | return FALSE; |
| 413 | } |
| 414 | } |
| 415 | else |
| 416 | { |
| 417 | if (!event->signalled) |
| 418 | { |
| 419 | struct timespec ts; |
| 420 | struct timeval tp; |
| 421 | UINT64 msec = timeout * 1000 / osd_ticks_per_second(); |
| 422 | UINT64 nsec; |
| 423 | |
| 424 | gettimeofday(&tp, NULL); |
| 425 | |
| 426 | ts.tv_sec = tp.tv_sec; |
| 427 | nsec = (UINT64) tp.tv_usec * (UINT64) 1000 + (msec * (UINT64) 1000000); |
| 428 | ts.tv_nsec = nsec % (UINT64) 1000000000; |
| 429 | ts.tv_sec += nsec / (UINT64) 1000000000; |
| 430 | |
| 431 | do { |
| 432 | int ret = pthread_cond_timedwait(&event->cond, &event->mutex, &ts); |
| 433 | if ( ret == ETIMEDOUT ) |
| 434 | { |
| 435 | if (!event->signalled) |
| 436 | { |
| 437 | pthread_mutex_unlock(&event->mutex); |
| 438 | return FALSE; |
| 439 | } |
| 440 | else |
| 441 | break; |
| 442 | } |
| 443 | if (ret == 0) |
| 444 | break; |
| 445 | if ( ret != EINTR) |
| 446 | { |
| 447 | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 448 | } |
| 449 | |
| 450 | } while (TRUE); |
| 451 | } |
| 452 | } |
| 453 | |
| 454 | if (event->autoreset) |
| 455 | event->signalled = 0; |
| 456 | |
| 457 | pthread_mutex_unlock(&event->mutex); |
| 458 | |
| 459 | return TRUE; |
| 460 | } |
| 461 | |
| 462 | //============================================================ |
| 463 | // osd_thread_create |
| 464 | //============================================================ |
| 465 | |
| 466 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 467 | { |
| 468 | osd_thread *thread; |
| 469 | pthread_attr_t attr; |
| 470 | |
| 471 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 472 | pthread_attr_init(&attr); |
| 473 | #ifndef SDLMAME_HAIKU |
| 474 | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
| 475 | #endif |
| 476 | if ( pthread_create(&thread->thread, &attr, callback, cbparam) != 0 ) |
| 477 | { |
| 478 | free(thread); |
| 479 | return NULL; |
| 480 | } |
| 481 | return thread; |
| 482 | } |
| 483 | |
| 484 | //============================================================ |
| 485 | // osd_thread_adjust_priority |
| 486 | //============================================================ |
| 487 | |
| 488 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 489 | { |
| 490 | struct sched_param sched; |
| 491 | int policy; |
| 492 | |
| 493 | if ( pthread_getschedparam( thread->thread, &policy, &sched ) == 0 ) |
| 494 | { |
| 495 | sched.sched_priority += adjust; |
| 496 | if ( pthread_setschedparam(thread->thread, policy, &sched ) == 0) |
| 497 | return TRUE; |
| 498 | else |
| 499 | return FALSE; |
| 500 | } |
| 501 | else |
| 502 | return FALSE; |
| 503 | } |
| 504 | |
| 505 | //============================================================ |
| 506 | // osd_thread_cpu_affinity |
| 507 | //============================================================ |
| 508 | |
| 509 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 510 | { |
| 511 | return TRUE; |
| 512 | } |
| 513 | |
| 514 | //============================================================ |
| 515 | // osd_thread_wait_free |
| 516 | //============================================================ |
| 517 | |
| 518 | void osd_thread_wait_free(osd_thread *thread) |
| 519 | { |
| 520 | pthread_join(thread->thread, NULL); |
| 521 | free(thread); |
| 522 | } |
| 523 | |
| 524 | //============================================================ |
| 525 | // osd_process_kill |
| 526 | //============================================================ |
| 527 | |
| 528 | void osd_process_kill(void) |
| 529 | { |
| 530 | kill(getpid(), SIGKILL); |
| 531 | } |
trunk/src/osd/modules/sync/sync_os2.c
| r0 | r242709 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // sdlsync.c - SDL core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #ifndef _GNU_SOURCE |
| 13 | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | #endif |
| 15 | |
| 16 | #include "sdlinc.h" |
| 17 | |
| 18 | // standard C headers |
| 19 | #include <math.h> |
| 20 | #include <unistd.h> |
| 21 | |
| 22 | // MAME headers |
| 23 | #include "osdcore.h" |
| 24 | #include "osinline.h" |
| 25 | #include "osdsync.h" |
| 26 | |
| 27 | #include "eminline.h" |
| 28 | |
| 29 | #define INCL_DOS |
| 30 | #include <os2.h> |
| 31 | |
| 32 | #include <stdlib.h> |
| 33 | #define pthread_t int |
| 34 | #define pthread_self _gettid |
| 35 | |
| 36 | struct osd_lock { |
| 37 | volatile pthread_t holder; |
| 38 | INT32 count; |
| 39 | #ifdef PTR64 |
| 40 | INT8 padding[52]; // Fill a 64-byte cache line |
| 41 | #else |
| 42 | INT8 padding[56]; // A bit more padding |
| 43 | #endif |
| 44 | }; |
| 45 | |
| 46 | struct osd_event { |
| 47 | HMTX hmtx; |
| 48 | HEV hev; |
| 49 | volatile INT32 autoreset; |
| 50 | INT8 padding[52]; // Fill a 64-byte cache line |
| 51 | }; |
| 52 | |
| 53 | //============================================================ |
| 54 | // TYPE DEFINITIONS |
| 55 | //============================================================ |
| 56 | |
| 57 | struct osd_thread { |
| 58 | pthread_t thread; |
| 59 | osd_thread_callback callback; |
| 60 | void *param; |
| 61 | }; |
| 62 | |
| 63 | struct osd_scalable_lock |
| 64 | { |
| 65 | struct |
| 66 | { |
| 67 | volatile INT32 haslock; // do we have the lock? |
| 68 | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 69 | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 70 | volatile INT32 nextindex; // index of next slot to use |
| 71 | }; |
| 72 | |
| 73 | |
| 74 | //============================================================ |
| 75 | // Scalable Locks |
| 76 | //============================================================ |
| 77 | |
| 78 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 79 | { |
| 80 | osd_scalable_lock *lock; |
| 81 | |
| 82 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 83 | |
| 84 | memset(lock, 0, sizeof(*lock)); |
| 85 | lock->slot[0].haslock = TRUE; |
| 86 | return lock; |
| 87 | } |
| 88 | |
| 89 | |
| 90 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 91 | { |
| 92 | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 93 | |
| 94 | #if defined(__i386__) || defined(__x86_64__) |
| 95 | register INT32 tmp; |
| 96 | __asm__ __volatile__ ( |
| 97 | "1: clr %[tmp] ;" |
| 98 | " xchg %[haslock], %[tmp] ;" |
| 99 | " test %[tmp], %[tmp] ;" |
| 100 | " jne 3f ;" |
| 101 | "2: mov %[haslock], %[tmp] ;" |
| 102 | " test %[tmp], %[tmp] ;" |
| 103 | " jne 1b ;" |
| 104 | " pause ;" |
| 105 | " jmp 2b ;" |
| 106 | "3: " |
| 107 | : [haslock] "+m" (lock->slot[myslot].haslock) |
| 108 | , [tmp] "=&r" (tmp) |
| 109 | : |
| 110 | : "%cc" |
| 111 | ); |
| 112 | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 113 | register INT32 tmp; |
| 114 | __asm__ __volatile__ ( |
| 115 | "1: lwarx %[tmp], 0, %[haslock] \n" |
| 116 | " cmpwi %[tmp], 0 \n" |
| 117 | " bne 3f \n" |
| 118 | "2: lwzx %[tmp], 0, %[haslock] \n" |
| 119 | " cmpwi %[tmp], 0 \n" |
| 120 | " bne 1b \n" |
| 121 | " nop \n" |
| 122 | " nop \n" |
| 123 | " b 2b \n" |
| 124 | "3: li %[tmp], 0 \n" |
| 125 | " sync \n" |
| 126 | " stwcx. %[tmp], 0, %[haslock] \n" |
| 127 | " bne- 1b \n" |
| 128 | " eieio \n" |
| 129 | : [tmp] "=&r" (tmp) |
| 130 | : [haslock] "r" (&lock->slot[myslot].haslock) |
| 131 | : "cr0" |
| 132 | ); |
| 133 | #else |
| 134 | INT32 backoff = 1; |
| 135 | while (!osd_compare_exchange32(&lock->slot[myslot].haslock, TRUE, FALSE)) |
| 136 | { |
| 137 | INT32 backcount; |
| 138 | for (backcount = 0; backcount < backoff; backcount++) |
| 139 | osd_yield_processor(); |
| 140 | backoff <<= 1; |
| 141 | } |
| 142 | #endif |
| 143 | return myslot; |
| 144 | } |
| 145 | |
| 146 | |
| 147 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 148 | { |
| 149 | #if defined(__i386__) || defined(__x86_64__) |
| 150 | register INT32 tmp = TRUE; |
| 151 | __asm__ __volatile__ ( |
| 152 | " xchg %[haslock], %[tmp] ;" |
| 153 | : [haslock] "+m" (lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock) |
| 154 | , [tmp] "+r" (tmp) |
| 155 | : |
| 156 | ); |
| 157 | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 158 | lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock = TRUE; |
| 159 | __asm__ __volatile__ ( " eieio " : : ); |
| 160 | #else |
| 161 | osd_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 162 | #endif |
| 163 | } |
| 164 | |
| 165 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 166 | { |
| 167 | free(lock); |
| 168 | } |
| 169 | |
| 170 | INLINE pthread_t osd_compare_exchange_pthread_t(pthread_t volatile *ptr, pthread_t compare, pthread_t exchange) |
| 171 | { |
| 172 | #ifdef PTR64 |
| 173 | INT64 result = compare_exchange64((INT64 volatile *)ptr, (INT64)compare, (INT64)exchange); |
| 174 | #else |
| 175 | INT32 result = compare_exchange32((INT32 volatile *)ptr, (INT32)compare, (INT32)exchange); |
| 176 | #endif |
| 177 | return (pthread_t)result; |
| 178 | } |
| 179 | |
| 180 | INLINE pthread_t osd_exchange_pthread_t(pthread_t volatile *ptr, pthread_t exchange) |
| 181 | { |
| 182 | #ifdef PTR64 |
| 183 | INT64 result = osd_exchange64((INT64 volatile *)ptr, (INT64)exchange); |
| 184 | #else |
| 185 | INT32 result = atomic_exchange32((INT32 volatile *)ptr, (INT32)exchange); |
| 186 | #endif |
| 187 | return (pthread_t)result; |
| 188 | } |
| 189 | |
| 190 | |
| 191 | //============================================================ |
| 192 | // osd_lock_alloc |
| 193 | //============================================================ |
| 194 | |
| 195 | osd_lock *osd_lock_alloc(void) |
| 196 | { |
| 197 | osd_lock *lock; |
| 198 | |
| 199 | lock = (osd_lock *)calloc(1, sizeof(osd_lock)); |
| 200 | |
| 201 | lock->holder = 0; |
| 202 | lock->count = 0; |
| 203 | |
| 204 | return lock; |
| 205 | } |
| 206 | |
| 207 | //============================================================ |
| 208 | // osd_lock_acquire |
| 209 | //============================================================ |
| 210 | |
| 211 | void osd_lock_acquire(osd_lock *lock) |
| 212 | { |
| 213 | pthread_t current, prev; |
| 214 | |
| 215 | current = pthread_self(); |
| 216 | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 217 | if (prev != (size_t)NULL && prev != current) |
| 218 | { |
| 219 | do { |
| 220 | register INT32 spin = 10000; // Convenient spin count |
| 221 | register pthread_t tmp; |
| 222 | #if defined(__i386__) || defined(__x86_64__) |
| 223 | __asm__ __volatile__ ( |
| 224 | "1: pause ;" |
| 225 | " mov %[holder], %[tmp] ;" |
| 226 | " test %[tmp], %[tmp] ;" |
| 227 | " loopne 1b ;" |
| 228 | : [spin] "+c" (spin) |
| 229 | , [tmp] "=&r" (tmp) |
| 230 | : [holder] "m" (lock->holder) |
| 231 | : "%cc" |
| 232 | ); |
| 233 | #elif defined(__ppc__) || defined(__PPC__) |
| 234 | __asm__ __volatile__ ( |
| 235 | "1: nop \n" |
| 236 | " nop \n" |
| 237 | " lwzx %[tmp], 0, %[holder] \n" |
| 238 | " cmpwi %[tmp], 0 \n" |
| 239 | " bdnzt eq, 1b \n" |
| 240 | : [spin] "+c" (spin) |
| 241 | , [tmp] "=&r" (tmp) |
| 242 | : [holder] "r" (&lock->holder) |
| 243 | : "cr0" |
| 244 | ); |
| 245 | #elif defined(__ppc64__) || defined(__PPC64__) |
| 246 | __asm__ __volatile__ ( |
| 247 | "1: nop \n" |
| 248 | " nop \n" |
| 249 | " ldx %[tmp], 0, %[holder] \n" |
| 250 | " cmpdi %[tmp], 0 \n" |
| 251 | " bdnzt eq, 1b \n" |
| 252 | : [spin] "+c" (spin) |
| 253 | , [tmp] "=&r" (tmp) |
| 254 | : [holder] "r" (&lock->holder) |
| 255 | : "cr0" |
| 256 | ); |
| 257 | #else |
| 258 | while (--spin > 0 && lock->holder != NULL) |
| 259 | osd_yield_processor(); |
| 260 | #endif |
| 261 | #if 0 |
| 262 | /* If you mean to use locks as a blocking mechanism for extended |
| 263 | * periods of time, you should do something like this. However, |
| 264 | * it kills the performance of gaelco3d. |
| 265 | */ |
| 266 | if (spin == 0) |
| 267 | { |
| 268 | struct timespec sleep = { 0, 100000 }, remaining; |
| 269 | nanosleep(&sleep, &remaining); // sleep for 100us |
| 270 | } |
| 271 | #endif |
| 272 | } while (osd_compare_exchange_pthread_t(&lock->holder, 0, current) != (size_t)NULL); |
| 273 | } |
| 274 | lock->count++; |
| 275 | } |
| 276 | |
| 277 | //============================================================ |
| 278 | // osd_lock_try |
| 279 | //============================================================ |
| 280 | |
| 281 | int osd_lock_try(osd_lock *lock) |
| 282 | { |
| 283 | pthread_t current, prev; |
| 284 | |
| 285 | current = pthread_self(); |
| 286 | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 287 | if (prev == (size_t)NULL || prev == current) |
| 288 | { |
| 289 | lock->count++; |
| 290 | return 1; |
| 291 | } |
| 292 | return 0; |
| 293 | } |
| 294 | |
| 295 | //============================================================ |
| 296 | // osd_lock_release |
| 297 | //============================================================ |
| 298 | |
| 299 | void osd_lock_release(osd_lock *lock) |
| 300 | { |
| 301 | pthread_t current; |
| 302 | |
| 303 | current = pthread_self(); |
| 304 | if (lock->holder == current) |
| 305 | { |
| 306 | if (--lock->count == 0) |
| 307 | #if defined(__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 308 | lock->holder = 0; |
| 309 | __asm__ __volatile__( " eieio " : : ); |
| 310 | #else |
| 311 | osd_exchange_pthread_t(&lock->holder, 0); |
| 312 | #endif |
| 313 | return; |
| 314 | } |
| 315 | |
| 316 | // trying to release a lock you don't hold is bad! |
| 317 | // assert(lock->holder == pthread_self()); |
| 318 | } |
| 319 | |
| 320 | //============================================================ |
| 321 | // osd_lock_free |
| 322 | //============================================================ |
| 323 | |
| 324 | void osd_lock_free(osd_lock *lock) |
| 325 | { |
| 326 | free(lock); |
| 327 | } |
| 328 | |
| 329 | //============================================================ |
| 330 | // osd_event_alloc |
| 331 | //============================================================ |
| 332 | |
| 333 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 334 | { |
| 335 | osd_event *ev; |
| 336 | |
| 337 | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 338 | |
| 339 | DosCreateMutexSem(NULL, &ev->hmtx, 0, FALSE); |
| 340 | DosCreateEventSem(NULL, &ev->hev, 0, initialstate); |
| 341 | ev->autoreset = !manualreset; |
| 342 | |
| 343 | return ev; |
| 344 | } |
| 345 | |
| 346 | //============================================================ |
| 347 | // osd_event_free |
| 348 | //============================================================ |
| 349 | |
| 350 | void osd_event_free(osd_event *event) |
| 351 | { |
| 352 | DosCloseMutexSem(event->hmtx); |
| 353 | DosCloseEventSem(event->hev); |
| 354 | free(event); |
| 355 | } |
| 356 | |
| 357 | //============================================================ |
| 358 | // osd_event_set |
| 359 | //============================================================ |
| 360 | |
| 361 | void osd_event_set(osd_event *event) |
| 362 | { |
| 363 | DosPostEventSem(event->hev); |
| 364 | } |
| 365 | |
| 366 | //============================================================ |
| 367 | // osd_event_reset |
| 368 | //============================================================ |
| 369 | |
| 370 | void osd_event_reset(osd_event *event) |
| 371 | { |
| 372 | ULONG ulCount; |
| 373 | |
| 374 | DosResetEventSem(event->hev, &ulCount); |
| 375 | } |
| 376 | |
| 377 | //============================================================ |
| 378 | // osd_event_wait |
| 379 | //============================================================ |
| 380 | |
| 381 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 382 | { |
| 383 | ULONG rc; |
| 384 | |
| 385 | if(event->autoreset) |
| 386 | DosRequestMutexSem(event->hmtx, -1); |
| 387 | |
| 388 | rc = DosWaitEventSem(event->hev, timeout * 1000 / osd_ticks_per_second()); |
| 389 | |
| 390 | if(event->autoreset) |
| 391 | { |
| 392 | ULONG ulCount; |
| 393 | |
| 394 | if(rc == 0) |
| 395 | DosResetEventSem(event->hev, &ulCount); |
| 396 | |
| 397 | DosReleaseMutexSem(event->hmtx); |
| 398 | } |
| 399 | |
| 400 | return (rc == 0); |
| 401 | } |
| 402 | |
| 403 | //============================================================ |
| 404 | // osd_thread_create |
| 405 | //============================================================ |
| 406 | |
| 407 | static void worker_thread_entry(void *param) |
| 408 | { |
| 409 | osd_thread *thread = (osd_thread *) param; |
| 410 | |
| 411 | thread->callback(thread->param); |
| 412 | } |
| 413 | |
| 414 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 415 | { |
| 416 | osd_thread *thread; |
| 417 | |
| 418 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 419 | thread->callback = callback; |
| 420 | thread->param = cbparam; |
| 421 | thread->thread = _beginthread(worker_thread_entry, NULL, 65535, thread); |
| 422 | if ( thread->thread == -1 ) |
| 423 | { |
| 424 | free(thread); |
| 425 | return NULL; |
| 426 | } |
| 427 | return thread; |
| 428 | } |
| 429 | |
| 430 | //============================================================ |
| 431 | // osd_thread_adjust_priority |
| 432 | //============================================================ |
| 433 | |
| 434 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 435 | { |
| 436 | PTIB ptib; |
| 437 | |
| 438 | DosGetInfoBlocks(&ptib, NULL); |
| 439 | |
| 440 | if ( DosSetPriority(PRTYS_THREAD, PRTYC_NOCHANGE, |
| 441 | ((BYTE)ptib->tib_ptib2->tib2_ulpri) + adjust, thread->thread )) |
| 442 | return FALSE; |
| 443 | |
| 444 | |
| 445 | return TRUE; |
| 446 | } |
| 447 | |
| 448 | //============================================================ |
| 449 | // osd_thread_cpu_affinity |
| 450 | //============================================================ |
| 451 | |
| 452 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 453 | { |
| 454 | return TRUE; |
| 455 | } |
| 456 | |
| 457 | //============================================================ |
| 458 | // osd_thread_wait_free |
| 459 | //============================================================ |
| 460 | |
| 461 | void osd_thread_wait_free(osd_thread *thread) |
| 462 | { |
| 463 | TID tid = thread->thread; |
| 464 | |
| 465 | DosWaitThread(&tid, 0); |
| 466 | free(thread); |
| 467 | } |
| 468 | |
| 469 | //============================================================ |
| 470 | // osd_process_kill |
| 471 | //============================================================ |
| 472 | |
| 473 | void osd_process_kill(void) |
| 474 | { |
| 475 | PPIB ppib; |
| 476 | |
| 477 | DosGetInfoBlocks(NULL, &ppib); |
| 478 | DosKillProcess(DKP_PROCESSTREE, ppib->pib_ulpid); |
| 479 | } |
trunk/src/osd/modules/sync/sync_sdl.c
| r0 | r242709 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // sdlsync.c - SDL core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #include "sdlinc.h" |
| 13 | |
| 14 | // standard C headers |
| 15 | #include <unistd.h> |
| 16 | |
| 17 | // MAME headers |
| 18 | #include "osdcore.h" |
| 19 | #include "osinline.h" |
| 20 | #include "osdsync.h" |
| 21 | |
| 22 | #include "eminline.h" |
| 23 | |
| 24 | #define VERBOSE (0) |
| 25 | |
| 26 | #if VERBOSE |
| 27 | #define LOG( x ) do { printf x; printf("\n"); } while (0) |
| 28 | #else |
| 29 | #define LOG( x ) |
| 30 | #endif |
| 31 | struct hidden_mutex_t { |
| 32 | SDL_mutex * id; |
| 33 | volatile INT32 locked; |
| 34 | volatile INT32 threadid; |
| 35 | }; |
| 36 | |
| 37 | struct osd_event { |
| 38 | SDL_mutex * mutex; |
| 39 | SDL_cond * cond; |
| 40 | volatile INT32 autoreset; |
| 41 | volatile INT32 signalled; |
| 42 | }; |
| 43 | |
| 44 | //============================================================ |
| 45 | // TYPE DEFINITIONS |
| 46 | //============================================================ |
| 47 | |
| 48 | struct osd_thread { |
| 49 | SDL_Thread * thread; |
| 50 | osd_thread_callback callback; |
| 51 | void *param; |
| 52 | }; |
| 53 | |
| 54 | struct osd_scalable_lock |
| 55 | { |
| 56 | SDL_mutex * mutex; |
| 57 | }; |
| 58 | |
| 59 | //============================================================ |
| 60 | // Scalable Locks |
| 61 | //============================================================ |
| 62 | |
| 63 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 64 | { |
| 65 | osd_scalable_lock *lock; |
| 66 | |
| 67 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 68 | |
| 69 | lock->mutex = SDL_CreateMutex(); |
| 70 | return lock; |
| 71 | } |
| 72 | |
| 73 | |
| 74 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 75 | { |
| 76 | SDL_mutexP(lock->mutex); |
| 77 | return 0; |
| 78 | } |
| 79 | |
| 80 | |
| 81 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 82 | { |
| 83 | SDL_mutexV(lock->mutex); |
| 84 | } |
| 85 | |
| 86 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 87 | { |
| 88 | SDL_DestroyMutex(lock->mutex); |
| 89 | free(lock); |
| 90 | } |
| 91 | |
| 92 | //============================================================ |
| 93 | // osd_lock_alloc |
| 94 | //============================================================ |
| 95 | |
| 96 | osd_lock *osd_lock_alloc(void) |
| 97 | { |
| 98 | hidden_mutex_t *mutex; |
| 99 | |
| 100 | mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); |
| 101 | |
| 102 | mutex->id = SDL_CreateMutex(); |
| 103 | |
| 104 | return (osd_lock *)mutex; |
| 105 | } |
| 106 | |
| 107 | //============================================================ |
| 108 | // osd_lock_acquire |
| 109 | //============================================================ |
| 110 | |
| 111 | void osd_lock_acquire(osd_lock *lock) |
| 112 | { |
| 113 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 114 | |
| 115 | LOG(("osd_lock_acquire")); |
| 116 | /* get the lock */ |
| 117 | mutex->locked++; /* signal that we are *about* to lock - prevent osd_lock_try */ |
| 118 | SDL_mutexP(mutex->id); |
| 119 | mutex->threadid = SDL_ThreadID(); |
| 120 | } |
| 121 | |
| 122 | //============================================================ |
| 123 | // osd_lock_try |
| 124 | //============================================================ |
| 125 | |
| 126 | int osd_lock_try(osd_lock *lock) |
| 127 | { |
| 128 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 129 | |
| 130 | LOG(("osd_lock_try")); |
| 131 | if (mutex->locked && mutex->threadid == SDL_ThreadID()) |
| 132 | { |
| 133 | /* get the lock */ |
| 134 | SDL_mutexP(mutex->id); |
| 135 | mutex->locked++; |
| 136 | mutex->threadid = SDL_ThreadID(); |
| 137 | return 1; |
| 138 | } |
| 139 | else if ((mutex->locked == 0)) |
| 140 | { |
| 141 | /* get the lock */ |
| 142 | mutex->locked++; |
| 143 | SDL_mutexP(mutex->id); |
| 144 | mutex->threadid = SDL_ThreadID(); |
| 145 | return 1; |
| 146 | } |
| 147 | else |
| 148 | { |
| 149 | /* fail */ |
| 150 | return 0; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | //============================================================ |
| 155 | // osd_lock_release |
| 156 | //============================================================ |
| 157 | |
| 158 | void osd_lock_release(osd_lock *lock) |
| 159 | { |
| 160 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 161 | |
| 162 | LOG(("osd_lock_release")); |
| 163 | mutex->locked--; |
| 164 | if (mutex->locked == 0) |
| 165 | mutex->threadid = -1; |
| 166 | SDL_mutexV(mutex->id); |
| 167 | } |
| 168 | |
| 169 | //============================================================ |
| 170 | // osd_lock_free |
| 171 | //============================================================ |
| 172 | |
| 173 | void osd_lock_free(osd_lock *lock) |
| 174 | { |
| 175 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 176 | |
| 177 | LOG(("osd_lock_free")); |
| 178 | //osd_lock_release(lock); |
| 179 | SDL_DestroyMutex(mutex->id); |
| 180 | free(mutex); |
| 181 | } |
| 182 | |
| 183 | //============================================================ |
| 184 | // osd_event_alloc |
| 185 | //============================================================ |
| 186 | |
| 187 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 188 | { |
| 189 | osd_event *ev; |
| 190 | |
| 191 | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 192 | |
| 193 | ev->mutex = SDL_CreateMutex(); |
| 194 | ev->cond = SDL_CreateCond(); |
| 195 | ev->signalled = initialstate; |
| 196 | ev->autoreset = !manualreset; |
| 197 | |
| 198 | return ev; |
| 199 | } |
| 200 | |
| 201 | //============================================================ |
| 202 | // osd_event_free |
| 203 | //============================================================ |
| 204 | |
| 205 | void osd_event_free(osd_event *event) |
| 206 | { |
| 207 | SDL_DestroyMutex(event->mutex); |
| 208 | SDL_DestroyCond(event->cond); |
| 209 | free(event); |
| 210 | } |
| 211 | |
| 212 | //============================================================ |
| 213 | // osd_event_set |
| 214 | //============================================================ |
| 215 | |
| 216 | void osd_event_set(osd_event *event) |
| 217 | { |
| 218 | LOG(("osd_event_set")); |
| 219 | SDL_mutexP(event->mutex); |
| 220 | if (event->signalled == FALSE) |
| 221 | { |
| 222 | event->signalled = TRUE; |
| 223 | if (event->autoreset) |
| 224 | SDL_CondSignal(event->cond); |
| 225 | else |
| 226 | SDL_CondBroadcast(event->cond); |
| 227 | } |
| 228 | SDL_mutexV(event->mutex); |
| 229 | } |
| 230 | |
| 231 | //============================================================ |
| 232 | // osd_event_reset |
| 233 | //============================================================ |
| 234 | |
| 235 | void osd_event_reset(osd_event *event) |
| 236 | { |
| 237 | LOG(("osd_event_reset")); |
| 238 | SDL_mutexP(event->mutex); |
| 239 | event->signalled = FALSE; |
| 240 | SDL_mutexV(event->mutex); |
| 241 | } |
| 242 | |
| 243 | //============================================================ |
| 244 | // osd_event_wait |
| 245 | //============================================================ |
| 246 | |
| 247 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 248 | { |
| 249 | LOG(("osd_event_wait")); |
| 250 | SDL_mutexP(event->mutex); |
| 251 | if (!timeout) |
| 252 | { |
| 253 | if (!event->signalled) |
| 254 | { |
| 255 | SDL_mutexV(event->mutex); |
| 256 | return FALSE; |
| 257 | } |
| 258 | } |
| 259 | else |
| 260 | { |
| 261 | if (!event->signalled) |
| 262 | { |
| 263 | UINT64 msec = (timeout * 1000) / osd_ticks_per_second(); |
| 264 | |
| 265 | do { |
| 266 | int ret = SDL_CondWaitTimeout(event->cond, event->mutex, msec); |
| 267 | if ( ret == SDL_MUTEX_TIMEDOUT ) |
| 268 | { |
| 269 | if (!event->signalled) |
| 270 | { |
| 271 | SDL_mutexV(event->mutex); |
| 272 | return FALSE; |
| 273 | } |
| 274 | else |
| 275 | break; |
| 276 | } |
| 277 | if (ret == 0) |
| 278 | break; |
| 279 | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 280 | } while (TRUE); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | if (event->autoreset) |
| 285 | event->signalled = 0; |
| 286 | |
| 287 | SDL_mutexV(event->mutex); |
| 288 | |
| 289 | return TRUE; |
| 290 | } |
| 291 | |
| 292 | //============================================================ |
| 293 | // osd_thread_create |
| 294 | //============================================================ |
| 295 | |
| 296 | static int worker_thread_entry(void *param) |
| 297 | { |
| 298 | osd_thread *thread = (osd_thread *) param; |
| 299 | void *res; |
| 300 | |
| 301 | res = thread->callback(thread->param); |
| 302 | #ifdef PTR64 |
| 303 | return (int) (INT64) res; |
| 304 | #else |
| 305 | return (int) res; |
| 306 | #endif |
| 307 | } |
| 308 | |
| 309 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 310 | { |
| 311 | osd_thread *thread; |
| 312 | |
| 313 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 314 | thread->callback = callback; |
| 315 | thread->param = cbparam; |
| 316 | thread->thread = SDL_CreateThread(worker_thread_entry, thread); |
| 317 | if ( thread->thread == NULL ) |
| 318 | { |
| 319 | free(thread); |
| 320 | return NULL; |
| 321 | } |
| 322 | return thread; |
| 323 | } |
| 324 | |
| 325 | //============================================================ |
| 326 | // osd_thread_adjust_priority |
| 327 | //============================================================ |
| 328 | |
| 329 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 330 | { |
| 331 | return TRUE; |
| 332 | } |
| 333 | |
| 334 | //============================================================ |
| 335 | // osd_thread_cpu_affinity |
| 336 | //============================================================ |
| 337 | |
| 338 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 339 | { |
| 340 | return TRUE; |
| 341 | } |
| 342 | |
| 343 | //============================================================ |
| 344 | // osd_thread_wait_free |
| 345 | //============================================================ |
| 346 | |
| 347 | void osd_thread_wait_free(osd_thread *thread) |
| 348 | { |
| 349 | int status; |
| 350 | SDL_WaitThread(thread->thread, &status); |
| 351 | free(thread); |
| 352 | } |
trunk/src/osd/modules/sync/sync_tc.c
| r0 | r242709 | |
| 1 | //============================================================ |
| 2 | // |
| 3 | // sdlsync.c - SDL core synchronization functions |
| 4 | // |
| 5 | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | // |
| 8 | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #ifndef _GNU_SOURCE |
| 13 | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | #endif |
| 15 | |
| 16 | #include "sdlinc.h" |
| 17 | |
| 18 | #ifdef SDLMAME_MACOSX |
| 19 | #include <mach/mach.h> |
| 20 | #endif |
| 21 | |
| 22 | // standard C headers |
| 23 | #include <math.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <unistd.h> |
| 26 | |
| 27 | // MAME headers |
| 28 | #include "osdcomm.h" |
| 29 | #include "osdcore.h" |
| 30 | |
| 31 | #include "osdsync.h" |
| 32 | |
| 33 | #include <pthread.h> |
| 34 | #include <errno.h> |
| 35 | #include <signal.h> |
| 36 | #include <sys/time.h> |
| 37 | |
| 38 | struct hidden_mutex_t { |
| 39 | pthread_mutex_t id; |
| 40 | }; |
| 41 | |
| 42 | struct osd_event { |
| 43 | pthread_mutex_t mutex; |
| 44 | pthread_cond_t cond; |
| 45 | volatile INT32 autoreset; |
| 46 | volatile INT32 signalled; |
| 47 | #ifdef PTR64 |
| 48 | INT8 padding[40]; // Fill a 64-byte cache line |
| 49 | #else |
| 50 | INT8 padding[48]; // A bit more padding |
| 51 | #endif |
| 52 | }; |
| 53 | |
| 54 | //============================================================ |
| 55 | // TYPE DEFINITIONS |
| 56 | //============================================================ |
| 57 | |
| 58 | struct osd_thread { |
| 59 | pthread_t thread; |
| 60 | }; |
| 61 | |
| 62 | struct osd_scalable_lock |
| 63 | { |
| 64 | osd_lock *lock; |
| 65 | }; |
| 66 | |
| 67 | //============================================================ |
| 68 | // Scalable Locks |
| 69 | //============================================================ |
| 70 | |
| 71 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 72 | { |
| 73 | osd_scalable_lock *lock; |
| 74 | |
| 75 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 76 | |
| 77 | lock->lock = osd_lock_alloc(); |
| 78 | return lock; |
| 79 | } |
| 80 | |
| 81 | |
| 82 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 83 | { |
| 84 | osd_lock_acquire(lock->lock); |
| 85 | return 0; |
| 86 | } |
| 87 | |
| 88 | |
| 89 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 90 | { |
| 91 | osd_lock_release(lock->lock); |
| 92 | } |
| 93 | |
| 94 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 95 | { |
| 96 | osd_lock_free(lock->lock); |
| 97 | free(lock); |
| 98 | } |
| 99 | |
| 100 | |
| 101 | //============================================================ |
| 102 | // osd_lock_alloc |
| 103 | //============================================================ |
| 104 | |
| 105 | osd_lock *osd_lock_alloc(void) |
| 106 | { |
| 107 | hidden_mutex_t *mutex; |
| 108 | pthread_mutexattr_t mtxattr; |
| 109 | |
| 110 | mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); |
| 111 | |
| 112 | pthread_mutexattr_init(&mtxattr); |
| 113 | pthread_mutexattr_settype(&mtxattr, PTHREAD_MUTEX_RECURSIVE); |
| 114 | pthread_mutex_init(&mutex->id, &mtxattr); |
| 115 | |
| 116 | return (osd_lock *)mutex; |
| 117 | } |
| 118 | |
| 119 | //============================================================ |
| 120 | // osd_lock_acquire |
| 121 | //============================================================ |
| 122 | |
| 123 | void osd_lock_acquire(osd_lock *lock) |
| 124 | { |
| 125 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 126 | int r; |
| 127 | |
| 128 | r = pthread_mutex_lock(&mutex->id); |
| 129 | if (r==0) |
| 130 | return; |
| 131 | //osd_printf_error("Error on lock: %d: %s\n", r, strerror(r)); |
| 132 | } |
| 133 | |
| 134 | //============================================================ |
| 135 | // osd_lock_try |
| 136 | //============================================================ |
| 137 | |
| 138 | int osd_lock_try(osd_lock *lock) |
| 139 | { |
| 140 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 141 | int r; |
| 142 | |
| 143 | r = pthread_mutex_trylock(&mutex->id); |
| 144 | if (r==0) |
| 145 | return 1; |
| 146 | //if (r!=EBUSY) |
| 147 | // osd_printf_error("Error on trylock: %d: %s\n", r, strerror(r)); |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | //============================================================ |
| 152 | // osd_lock_release |
| 153 | //============================================================ |
| 154 | |
| 155 | void osd_lock_release(osd_lock *lock) |
| 156 | { |
| 157 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 158 | |
| 159 | pthread_mutex_unlock(&mutex->id); |
| 160 | } |
| 161 | |
| 162 | //============================================================ |
| 163 | // osd_lock_free |
| 164 | //============================================================ |
| 165 | |
| 166 | void osd_lock_free(osd_lock *lock) |
| 167 | { |
| 168 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 169 | |
| 170 | //pthread_mutex_unlock(&mutex->id); |
| 171 | pthread_mutex_destroy(&mutex->id); |
| 172 | free(mutex); |
| 173 | } |
| 174 | |
| 175 | //============================================================ |
| 176 | // osd_event_alloc |
| 177 | //============================================================ |
| 178 | |
| 179 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 180 | { |
| 181 | osd_event *ev; |
| 182 | pthread_mutexattr_t mtxattr; |
| 183 | |
| 184 | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 185 | |
| 186 | pthread_mutexattr_init(&mtxattr); |
| 187 | pthread_mutex_init(&ev->mutex, &mtxattr); |
| 188 | pthread_cond_init(&ev->cond, NULL); |
| 189 | ev->signalled = initialstate; |
| 190 | ev->autoreset = !manualreset; |
| 191 | |
| 192 | return ev; |
| 193 | } |
| 194 | |
| 195 | //============================================================ |
| 196 | // osd_event_free |
| 197 | //============================================================ |
| 198 | |
| 199 | void osd_event_free(osd_event *event) |
| 200 | { |
| 201 | pthread_mutex_destroy(&event->mutex); |
| 202 | pthread_cond_destroy(&event->cond); |
| 203 | free(event); |
| 204 | } |
| 205 | |
| 206 | //============================================================ |
| 207 | // osd_event_set |
| 208 | //============================================================ |
| 209 | |
| 210 | void osd_event_set(osd_event *event) |
| 211 | { |
| 212 | pthread_mutex_lock(&event->mutex); |
| 213 | if (event->signalled == FALSE) |
| 214 | { |
| 215 | event->signalled = TRUE; |
| 216 | if (event->autoreset) |
| 217 | pthread_cond_signal(&event->cond); |
| 218 | else |
| 219 | pthread_cond_broadcast(&event->cond); |
| 220 | } |
| 221 | pthread_mutex_unlock(&event->mutex); |
| 222 | } |
| 223 | |
| 224 | //============================================================ |
| 225 | // osd_event_reset |
| 226 | //============================================================ |
| 227 | |
| 228 | void osd_event_reset(osd_event *event) |
| 229 | { |
| 230 | pthread_mutex_lock(&event->mutex); |
| 231 | event->signalled = FALSE; |
| 232 | pthread_mutex_unlock(&event->mutex); |
| 233 | } |
| 234 | |
| 235 | //============================================================ |
| 236 | // osd_event_wait |
| 237 | //============================================================ |
| 238 | |
| 239 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 240 | { |
| 241 | pthread_mutex_lock(&event->mutex); |
| 242 | if (!timeout) |
| 243 | { |
| 244 | if (!event->signalled) |
| 245 | { |
| 246 | pthread_mutex_unlock(&event->mutex); |
| 247 | return FALSE; |
| 248 | } |
| 249 | } |
| 250 | else |
| 251 | { |
| 252 | if (!event->signalled) |
| 253 | { |
| 254 | struct timespec ts; |
| 255 | struct timeval tp; |
| 256 | UINT64 msec = timeout * 1000 / osd_ticks_per_second(); |
| 257 | UINT64 nsec; |
| 258 | |
| 259 | gettimeofday(&tp, NULL); |
| 260 | |
| 261 | ts.tv_sec = tp.tv_sec; |
| 262 | nsec = (UINT64) tp.tv_usec * (UINT64) 1000 + (msec * (UINT64) 1000000); |
| 263 | ts.tv_nsec = nsec % (UINT64) 1000000000; |
| 264 | ts.tv_sec += nsec / (UINT64) 1000000000; |
| 265 | |
| 266 | do { |
| 267 | int ret = pthread_cond_timedwait(&event->cond, &event->mutex, &ts); |
| 268 | if ( ret == ETIMEDOUT ) |
| 269 | { |
| 270 | if (!event->signalled) |
| 271 | { |
| 272 | pthread_mutex_unlock(&event->mutex); |
| 273 | return FALSE; |
| 274 | } |
| 275 | else |
| 276 | break; |
| 277 | } |
| 278 | if (ret == 0) |
| 279 | break; |
| 280 | if ( ret != EINTR) |
| 281 | { |
| 282 | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 283 | } |
| 284 | |
| 285 | } while (TRUE); |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | if (event->autoreset) |
| 290 | event->signalled = 0; |
| 291 | |
| 292 | pthread_mutex_unlock(&event->mutex); |
| 293 | |
| 294 | return TRUE; |
| 295 | } |
| 296 | |
| 297 | //============================================================ |
| 298 | // osd_thread_create |
| 299 | //============================================================ |
| 300 | |
| 301 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 302 | { |
| 303 | osd_thread *thread; |
| 304 | pthread_attr_t attr; |
| 305 | |
| 306 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 307 | pthread_attr_init(&attr); |
| 308 | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
| 309 | if ( pthread_create(&thread->thread, &attr, callback, cbparam) != 0 ) |
| 310 | { |
| 311 | free(thread); |
| 312 | return NULL; |
| 313 | } |
| 314 | return thread; |
| 315 | } |
| 316 | |
| 317 | //============================================================ |
| 318 | // osd_thread_adjust_priority |
| 319 | //============================================================ |
| 320 | |
| 321 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 322 | { |
| 323 | struct sched_param sched; |
| 324 | int policy; |
| 325 | |
| 326 | if ( pthread_getschedparam( thread->thread, &policy, &sched ) == 0 ) |
| 327 | { |
| 328 | sched.sched_priority += adjust; |
| 329 | if ( pthread_setschedparam(thread->thread, policy, &sched ) == 0) |
| 330 | return TRUE; |
| 331 | else |
| 332 | return FALSE; |
| 333 | } |
| 334 | else |
| 335 | return FALSE; |
| 336 | } |
| 337 | |
| 338 | //============================================================ |
| 339 | // osd_thread_cpu_affinity |
| 340 | //============================================================ |
| 341 | |
| 342 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 343 | { |
| 344 | #if !defined(NO_AFFINITY_NP) |
| 345 | cpu_set_t cmask; |
| 346 | pthread_t lthread; |
| 347 | int bitnum; |
| 348 | |
| 349 | CPU_ZERO(&cmask); |
| 350 | for (bitnum=0; bitnum<32; bitnum++) |
| 351 | if (mask & (1<<bitnum)) |
| 352 | CPU_SET(bitnum, &cmask); |
| 353 | |
| 354 | if (thread == NULL) |
| 355 | lthread = pthread_self(); |
| 356 | else |
| 357 | lthread = thread->thread; |
| 358 | |
| 359 | if (pthread_setaffinity_np(lthread, sizeof(cmask), &cmask) <0) |
| 360 | { |
| 361 | /* Not available during link in all targets */ |
| 362 | fprintf(stderr, "error %d setting cpu affinity to mask %08x", errno, mask); |
| 363 | return FALSE; |
| 364 | } |
| 365 | else |
| 366 | return TRUE; |
| 367 | #else |
| 368 | return TRUE; |
| 369 | #endif |
| 370 | } |
| 371 | |
| 372 | //============================================================ |
| 373 | // osd_thread_wait_free |
| 374 | //============================================================ |
| 375 | |
| 376 | void osd_thread_wait_free(osd_thread *thread) |
| 377 | { |
| 378 | pthread_join(thread->thread, NULL); |
| 379 | free(thread); |
| 380 | } |
| 381 | |
| 382 | //============================================================ |
| 383 | // osd_process_kill |
| 384 | //============================================================ |
| 385 | |
| 386 | void osd_process_kill(void) |
| 387 | { |
| 388 | kill(getpid(), SIGKILL); |
| 389 | } |
trunk/src/osd/modules/sync/sync_windows.c
| r0 | r242709 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Aaron Giles |
| 3 | //============================================================ |
| 4 | // |
| 5 | // winsync.c - Win32 OSD core synchronization functions |
| 6 | // |
| 7 | //============================================================ |
| 8 | |
| 9 | // standard windows headers |
| 10 | #define WIN32_LEAN_AND_MEAN |
| 11 | #include <windows.h> |
| 12 | #include <stdlib.h> |
| 13 | #include <process.h> |
| 14 | |
| 15 | // MAME headers |
| 16 | #include "osdcore.h" |
| 17 | #include "osinline.h" |
| 18 | #include "osdsync.h" |
| 19 | |
| 20 | |
| 21 | //============================================================ |
| 22 | // DEBUGGING |
| 23 | //============================================================ |
| 24 | |
| 25 | #define DEBUG_SLOW_LOCKS 0 |
| 26 | #define USE_SCALABLE_LOCKS (0) |
| 27 | |
| 28 | |
| 29 | |
| 30 | //============================================================ |
| 31 | // TYPE DEFINITIONS |
| 32 | //============================================================ |
| 33 | |
| 34 | typedef BOOL (WINAPI *try_enter_critical_section_ptr)(LPCRITICAL_SECTION lpCriticalSection); |
| 35 | |
| 36 | struct osd_lock |
| 37 | { |
| 38 | CRITICAL_SECTION critsect; |
| 39 | }; |
| 40 | |
| 41 | struct osd_event |
| 42 | { |
| 43 | void * ptr; |
| 44 | }; |
| 45 | |
| 46 | struct osd_thread { |
| 47 | HANDLE handle; |
| 48 | osd_thread_callback callback; |
| 49 | void *param; |
| 50 | }; |
| 51 | |
| 52 | struct osd_scalable_lock |
| 53 | { |
| 54 | #if USE_SCALABLE_LOCKS |
| 55 | struct |
| 56 | { |
| 57 | volatile INT32 haslock; // do we have the lock? |
| 58 | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 59 | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 60 | volatile INT32 nextindex; // index of next slot to use |
| 61 | #else |
| 62 | CRITICAL_SECTION section; |
| 63 | #endif |
| 64 | }; |
| 65 | |
| 66 | |
| 67 | //============================================================ |
| 68 | // GLOBAL VARIABLES |
| 69 | //============================================================ |
| 70 | |
| 71 | static try_enter_critical_section_ptr try_enter_critical_section = NULL; |
| 72 | static int checked_for_try_enter = FALSE; |
| 73 | |
| 74 | |
| 75 | |
| 76 | //============================================================ |
| 77 | // osd_lock_alloc |
| 78 | //============================================================ |
| 79 | |
| 80 | osd_lock *osd_lock_alloc(void) |
| 81 | { |
| 82 | osd_lock *lock = (osd_lock *)malloc(sizeof(*lock)); |
| 83 | if (lock == NULL) |
| 84 | return NULL; |
| 85 | InitializeCriticalSection(&lock->critsect); |
| 86 | return lock; |
| 87 | } |
| 88 | |
| 89 | |
| 90 | //============================================================ |
| 91 | // osd_lock_acquire |
| 92 | //============================================================ |
| 93 | |
| 94 | void osd_lock_acquire(osd_lock *lock) |
| 95 | { |
| 96 | #if DEBUG_SLOW_LOCKS |
| 97 | osd_ticks_t ticks = osd_ticks(); |
| 98 | #endif |
| 99 | |
| 100 | // block until we can acquire the lock |
| 101 | EnterCriticalSection(&lock->critsect); |
| 102 | |
| 103 | #if DEBUG_SLOW_LOCKS |
| 104 | // log any locks that take more than 1ms |
| 105 | ticks = osd_ticks() - ticks; |
| 106 | if (ticks > osd_ticks_per_second() / 1000) osd_printf_debug("Blocked %d ticks on lock acquire\n", (int)ticks); |
| 107 | #endif |
| 108 | } |
| 109 | |
| 110 | |
| 111 | //============================================================ |
| 112 | // osd_lock_try |
| 113 | //============================================================ |
| 114 | |
| 115 | int osd_lock_try(osd_lock *lock) |
| 116 | { |
| 117 | int result = TRUE; |
| 118 | |
| 119 | // if we haven't yet checked for the TryEnter API, do it now |
| 120 | if (!checked_for_try_enter) |
| 121 | { |
| 122 | // see if we can use TryEnterCriticalSection |
| 123 | HMODULE library = LoadLibrary(TEXT("kernel32.dll")); |
| 124 | if (library != NULL) |
| 125 | try_enter_critical_section = (try_enter_critical_section_ptr)GetProcAddress(library, "TryEnterCriticalSection"); |
| 126 | checked_for_try_enter = TRUE; |
| 127 | } |
| 128 | |
| 129 | // if we have it, use it, otherwise just block |
| 130 | if (try_enter_critical_section != NULL) |
| 131 | result = (*try_enter_critical_section)(&lock->critsect); |
| 132 | else |
| 133 | EnterCriticalSection(&lock->critsect); |
| 134 | return result; |
| 135 | } |
| 136 | |
| 137 | |
| 138 | //============================================================ |
| 139 | // osd_lock_release |
| 140 | //============================================================ |
| 141 | |
| 142 | void osd_lock_release(osd_lock *lock) |
| 143 | { |
| 144 | LeaveCriticalSection(&lock->critsect); |
| 145 | } |
| 146 | |
| 147 | |
| 148 | //============================================================ |
| 149 | // osd_lock_free |
| 150 | //============================================================ |
| 151 | |
| 152 | void osd_lock_free(osd_lock *lock) |
| 153 | { |
| 154 | DeleteCriticalSection(&lock->critsect); |
| 155 | free(lock); |
| 156 | } |
| 157 | |
| 158 | |
| 159 | //============================================================ |
| 160 | // win_compare_exchange32 |
| 161 | //============================================================ |
| 162 | |
| 163 | INT32 win_compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange) |
| 164 | { |
| 165 | return InterlockedCompareExchange((LPLONG)ptr, (LONG)exchange, (LONG)compare); |
| 166 | } |
| 167 | |
| 168 | |
| 169 | //============================================================ |
| 170 | // win_compare_exchange64 |
| 171 | //============================================================ |
| 172 | |
| 173 | #ifdef PTR64 |
| 174 | INT64 win_compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange) |
| 175 | { |
| 176 | return InterlockedCompareExchange64((LONGLONG*)ptr, (LONGLONG)exchange, (LONGLONG)compare); |
| 177 | } |
| 178 | #endif |
| 179 | |
| 180 | |
| 181 | //============================================================ |
| 182 | // win_atomic_exchange32 |
| 183 | //============================================================ |
| 184 | |
| 185 | INT32 win_atomic_exchange32(INT32 volatile *ptr, INT32 exchange) |
| 186 | { |
| 187 | return InterlockedExchange((LONG *) ptr, exchange); |
| 188 | } |
| 189 | |
| 190 | |
| 191 | //============================================================ |
| 192 | // win_atomic_add32 |
| 193 | //============================================================ |
| 194 | |
| 195 | INT32 win_atomic_add32(INT32 volatile *ptr, INT32 delta) |
| 196 | { |
| 197 | return InterlockedExchangeAdd((LONG *) ptr, delta) + delta; |
| 198 | } |
| 199 | |
| 200 | //============================================================ |
| 201 | // osd_event_alloc |
| 202 | //============================================================ |
| 203 | |
| 204 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 205 | { |
| 206 | return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL); |
| 207 | } |
| 208 | |
| 209 | //============================================================ |
| 210 | // osd_event_free |
| 211 | //============================================================ |
| 212 | |
| 213 | void osd_event_free(osd_event *event) |
| 214 | { |
| 215 | CloseHandle((HANDLE) event); |
| 216 | } |
| 217 | |
| 218 | //============================================================ |
| 219 | // osd_event_set |
| 220 | //============================================================ |
| 221 | |
| 222 | void osd_event_set(osd_event *event) |
| 223 | { |
| 224 | SetEvent((HANDLE) event); |
| 225 | } |
| 226 | |
| 227 | //============================================================ |
| 228 | // osd_event_reset |
| 229 | //============================================================ |
| 230 | |
| 231 | void osd_event_reset(osd_event *event) |
| 232 | { |
| 233 | ResetEvent((HANDLE) event); |
| 234 | } |
| 235 | |
| 236 | //============================================================ |
| 237 | // osd_event_wait |
| 238 | //============================================================ |
| 239 | |
| 240 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 241 | { |
| 242 | int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second()); |
| 243 | return ( ret == WAIT_OBJECT_0); |
| 244 | } |
| 245 | |
| 246 | //============================================================ |
| 247 | // osd_thread_create |
| 248 | //============================================================ |
| 249 | |
| 250 | static unsigned __stdcall worker_thread_entry(void *param) |
| 251 | { |
| 252 | osd_thread *thread = (osd_thread *) param; |
| 253 | void *res; |
| 254 | res = thread->callback(thread->param); |
| 255 | #ifdef PTR64 |
| 256 | return (unsigned) (long long) res; |
| 257 | #else |
| 258 | return (unsigned) res; |
| 259 | #endif |
| 260 | } |
| 261 | |
| 262 | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 263 | { |
| 264 | osd_thread *thread; |
| 265 | uintptr_t handle; |
| 266 | |
| 267 | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 268 | thread->callback = callback; |
| 269 | thread->param = cbparam; |
| 270 | handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL); |
| 271 | thread->handle = (HANDLE) handle; |
| 272 | return thread; |
| 273 | } |
| 274 | |
| 275 | //============================================================ |
| 276 | // osd_thread_wait_free |
| 277 | //============================================================ |
| 278 | |
| 279 | void osd_thread_wait_free(osd_thread *thread) |
| 280 | { |
| 281 | WaitForSingleObject(thread->handle, INFINITE); |
| 282 | CloseHandle(thread->handle); |
| 283 | free(thread); |
| 284 | } |
| 285 | |
| 286 | //============================================================ |
| 287 | // osd_thread_adjust_priority |
| 288 | //============================================================ |
| 289 | |
| 290 | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 291 | { |
| 292 | if (adjust) |
| 293 | SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); |
| 294 | else |
| 295 | SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread())); |
| 296 | return TRUE; |
| 297 | } |
| 298 | |
| 299 | //============================================================ |
| 300 | // osd_thread_cpu_affinity |
| 301 | //============================================================ |
| 302 | |
| 303 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 304 | { |
| 305 | return TRUE; |
| 306 | } |
| 307 | |
| 308 | //============================================================ |
| 309 | // osd_process_kill |
| 310 | //============================================================ |
| 311 | |
| 312 | void osd_process_kill(void) |
| 313 | { |
| 314 | TerminateProcess(GetCurrentProcess(), -1); |
| 315 | } |
| 316 | |
| 317 | //============================================================ |
| 318 | // Scalable Locks |
| 319 | //============================================================ |
| 320 | |
| 321 | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 322 | { |
| 323 | osd_scalable_lock *lock; |
| 324 | |
| 325 | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 326 | |
| 327 | memset(lock, 0, sizeof(*lock)); |
| 328 | #if USE_SCALABLE_LOCKS |
| 329 | lock->slot[0].haslock = TRUE; |
| 330 | #else |
| 331 | InitializeCriticalSection(&lock->section); |
| 332 | #endif |
| 333 | return lock; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 338 | { |
| 339 | #if USE_SCALABLE_LOCKS |
| 340 | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 341 | INT32 backoff = 1; |
| 342 | |
| 343 | while (!lock->slot[myslot].haslock) |
| 344 | { |
| 345 | INT32 backcount; |
| 346 | for (backcount = 0; backcount < backoff; backcount++) |
| 347 | osd_yield_processor(); |
| 348 | backoff <<= 1; |
| 349 | } |
| 350 | lock->slot[myslot].haslock = FALSE; |
| 351 | return myslot; |
| 352 | #else |
| 353 | EnterCriticalSection(&lock->section); |
| 354 | return 0; |
| 355 | #endif |
| 356 | } |
| 357 | |
| 358 | |
| 359 | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 360 | { |
| 361 | #if USE_SCALABLE_LOCKS |
| 362 | atomic_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 363 | #else |
| 364 | LeaveCriticalSection(&lock->section); |
| 365 | #endif |
| 366 | } |
| 367 | |
| 368 | |
| 369 | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 370 | { |
| 371 | #if USE_SCALABLE_LOCKS |
| 372 | #else |
| 373 | DeleteCriticalSection(&lock->section); |
| 374 | #endif |
| 375 | free(lock); |
| 376 | } |
trunk/src/osd/sdl/sdlsync.h
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // sdlsync.h - SDL core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #ifndef __SDLSYNC__ |
| 13 | | #define __SDLSYNC__ |
| 14 | | |
| 15 | | /*************************************************************************** |
| 16 | | SYNCHRONIZATION INTERFACES - Events |
| 17 | | ***************************************************************************/ |
| 18 | | |
| 19 | | /* osd_event is an opaque type which represents a setable/resetable event */ |
| 20 | | |
| 21 | | struct osd_event; |
| 22 | | |
| 23 | | |
| 24 | | /*----------------------------------------------------------------------------- |
| 25 | | osd_lock_event_alloc: allocate a new event |
| 26 | | |
| 27 | | Parameters: |
| 28 | | |
| 29 | | manualreset - boolean. If true, the event will be automatically set |
| 30 | | to non-signalled after a thread successfully waited for |
| 31 | | it. |
| 32 | | initialstate - boolean. If true, the event is signalled initially. |
| 33 | | |
| 34 | | Return value: |
| 35 | | |
| 36 | | A pointer to the allocated event. |
| 37 | | -----------------------------------------------------------------------------*/ |
| 38 | | osd_event *osd_event_alloc(int manualreset, int initialstate); |
| 39 | | |
| 40 | | |
| 41 | | /*----------------------------------------------------------------------------- |
| 42 | | osd_event_wait: wait for an event to be signalled |
| 43 | | |
| 44 | | Parameters: |
| 45 | | |
| 46 | | event - The event to wait for. If the event is in signalled state, the |
| 47 | | function returns immediately. If not it will wait for the event |
| 48 | | to become signalled. |
| 49 | | timeout - timeout in osd_ticks |
| 50 | | |
| 51 | | Return value: |
| 52 | | |
| 53 | | TRUE: The event was signalled |
| 54 | | FALSE: A timeout occurred |
| 55 | | -----------------------------------------------------------------------------*/ |
| 56 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout); |
| 57 | | |
| 58 | | |
| 59 | | /*----------------------------------------------------------------------------- |
| 60 | | osd_event_reset: reset an event to non-signalled state |
| 61 | | |
| 62 | | Parameters: |
| 63 | | |
| 64 | | event - The event to set to non-signalled state |
| 65 | | |
| 66 | | Return value: |
| 67 | | |
| 68 | | None |
| 69 | | -----------------------------------------------------------------------------*/ |
| 70 | | void osd_event_reset(osd_event *event); |
| 71 | | |
| 72 | | |
| 73 | | /*----------------------------------------------------------------------------- |
| 74 | | osd_event_set: set an event to signalled state |
| 75 | | |
| 76 | | Parameters: |
| 77 | | |
| 78 | | event - The event to set to signalled state |
| 79 | | |
| 80 | | Return value: |
| 81 | | |
| 82 | | None |
| 83 | | |
| 84 | | Notes: |
| 85 | | |
| 86 | | All threads waiting for the event will be signalled. |
| 87 | | -----------------------------------------------------------------------------*/ |
| 88 | | void osd_event_set(osd_event *event); |
| 89 | | |
| 90 | | |
| 91 | | /*----------------------------------------------------------------------------- |
| 92 | | osd_event_free: free the memory and resources associated with an osd_event |
| 93 | | |
| 94 | | Parameters: |
| 95 | | |
| 96 | | event - a pointer to a previously allocated osd_event. |
| 97 | | |
| 98 | | Return value: |
| 99 | | |
| 100 | | None. |
| 101 | | -----------------------------------------------------------------------------*/ |
| 102 | | void osd_event_free(osd_event *event); |
| 103 | | |
| 104 | | |
| 105 | | /*************************************************************************** |
| 106 | | SYNCHRONIZATION INTERFACES - Threads |
| 107 | | ***************************************************************************/ |
| 108 | | |
| 109 | | /* osd_thread is an opaque type which represents a thread */ |
| 110 | | struct osd_thread; |
| 111 | | |
| 112 | | |
| 113 | | /* osd_thread_callback is a callback function that will be called from the thread */ |
| 114 | | typedef void *(*osd_thread_callback)(void *param); |
| 115 | | |
| 116 | | |
| 117 | | /*----------------------------------------------------------------------------- |
| 118 | | osd_thread_create: create a new thread |
| 119 | | |
| 120 | | Parameters: |
| 121 | | |
| 122 | | callback - The callback function to be called once the thread is up |
| 123 | | cbparam - The parameter to pass to the callback function. |
| 124 | | |
| 125 | | Return value: |
| 126 | | |
| 127 | | A pointer to the created thread. |
| 128 | | -----------------------------------------------------------------------------*/ |
| 129 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam); |
| 130 | | |
| 131 | | |
| 132 | | /*----------------------------------------------------------------------------- |
| 133 | | osd_thread_adjust_priority: adjust priority of a thread |
| 134 | | |
| 135 | | Parameters: |
| 136 | | |
| 137 | | thread - A pointer to a previously created thread. |
| 138 | | adjust - signed integer to add to the thread priority |
| 139 | | |
| 140 | | Return value: |
| 141 | | |
| 142 | | TRUE on success, FALSE on failure |
| 143 | | -----------------------------------------------------------------------------*/ |
| 144 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust); |
| 145 | | |
| 146 | | |
| 147 | | /*----------------------------------------------------------------------------- |
| 148 | | osd_thread_cpu_affinity: change cpu affinity of a thread |
| 149 | | |
| 150 | | Parameters: |
| 151 | | |
| 152 | | thread - A pointer to a previously created thread |
| 153 | | or NULL for main thread |
| 154 | | mask - bitmask to which cpus to bind |
| 155 | | i.e. 0x01 1st cpu, 0x02, 2nd cpu, 0x04 3rd cpu |
| 156 | | |
| 157 | | Return value: |
| 158 | | |
| 159 | | TRUE on success, FALSE on failure |
| 160 | | -----------------------------------------------------------------------------*/ |
| 161 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask); |
| 162 | | |
| 163 | | |
| 164 | | /*----------------------------------------------------------------------------- |
| 165 | | osd_thread_wait_free: wait for thread to finish and free resources |
| 166 | | |
| 167 | | Parameters: |
| 168 | | |
| 169 | | thread - A pointer to a previously created thread. |
| 170 | | |
| 171 | | Return value: |
| 172 | | |
| 173 | | None. |
| 174 | | -----------------------------------------------------------------------------*/ |
| 175 | | void osd_thread_wait_free(osd_thread *thread); |
| 176 | | |
| 177 | | /*----------------------------------------------------------------------------- |
| 178 | | osd_process_kill: kill the current process |
| 179 | | |
| 180 | | Parameters: |
| 181 | | |
| 182 | | None. |
| 183 | | |
| 184 | | Return value: |
| 185 | | |
| 186 | | None. |
| 187 | | -----------------------------------------------------------------------------*/ |
| 188 | | void osd_process_kill(void); |
| 189 | | |
| 190 | | //============================================================ |
| 191 | | // Scalable Locks |
| 192 | | //============================================================ |
| 193 | | |
| 194 | | struct osd_scalable_lock; |
| 195 | | |
| 196 | | osd_scalable_lock *osd_scalable_lock_alloc(void); |
| 197 | | |
| 198 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock); |
| 199 | | |
| 200 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot); |
| 201 | | |
| 202 | | void osd_scalable_lock_free(osd_scalable_lock *lock); |
| 203 | | |
| 204 | | #endif /* __SDLSYNC__ */ |
trunk/src/osd/sdl/sdlsync_mini.c
| r242708 | r242709 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Aaron Giles |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // sdlsync_mini.c - Minimal core synchronization functions |
| 6 | | // |
| 7 | | //============================================================ |
| 8 | | |
| 9 | | #include "osdcore.h" |
| 10 | | #include "sdlsync.h" |
| 11 | | |
| 12 | | #define USE_SCALABLE_LOCKS (0) |
| 13 | | |
| 14 | | struct _osd_event |
| 15 | | { |
| 16 | | void * ptr; |
| 17 | | }; |
| 18 | | |
| 19 | | struct _osd_thread { |
| 20 | | void * ptr; |
| 21 | | }; |
| 22 | | |
| 23 | | |
| 24 | | //============================================================ |
| 25 | | // osd_lock_alloc |
| 26 | | //============================================================ |
| 27 | | |
| 28 | | osd_lock *osd_lock_alloc(void) |
| 29 | | { |
| 30 | | // the minimal implementation does not support threading |
| 31 | | // just return a dummy value here |
| 32 | | return (osd_lock *)1; |
| 33 | | } |
| 34 | | |
| 35 | | |
| 36 | | //============================================================ |
| 37 | | // osd_lock_acquire |
| 38 | | //============================================================ |
| 39 | | |
| 40 | | void osd_lock_acquire(osd_lock *lock) |
| 41 | | { |
| 42 | | // the minimal implementation does not support threading |
| 43 | | // the acquire always "succeeds" |
| 44 | | } |
| 45 | | |
| 46 | | |
| 47 | | //============================================================ |
| 48 | | // osd_lock_try |
| 49 | | //============================================================ |
| 50 | | |
| 51 | | int osd_lock_try(osd_lock *lock) |
| 52 | | { |
| 53 | | // the minimal implementation does not support threading |
| 54 | | // the acquire always "succeeds" |
| 55 | | return TRUE; |
| 56 | | } |
| 57 | | |
| 58 | | |
| 59 | | //============================================================ |
| 60 | | // osd_lock_release |
| 61 | | //============================================================ |
| 62 | | |
| 63 | | void osd_lock_release(osd_lock *lock) |
| 64 | | { |
| 65 | | // the minimal implementation does not support threading |
| 66 | | // do nothing here |
| 67 | | } |
| 68 | | |
| 69 | | |
| 70 | | //============================================================ |
| 71 | | // osd_lock_free |
| 72 | | //============================================================ |
| 73 | | |
| 74 | | void osd_lock_free(osd_lock *lock) |
| 75 | | { |
| 76 | | // the minimal implementation does not support threading |
| 77 | | // do nothing here |
| 78 | | } |
| 79 | | |
| 80 | | |
| 81 | | //============================================================ |
| 82 | | // osd_event_alloc |
| 83 | | //============================================================ |
| 84 | | |
| 85 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 86 | | { |
| 87 | | return NULL; |
| 88 | | } |
| 89 | | |
| 90 | | |
| 91 | | //============================================================ |
| 92 | | // osd_event_free |
| 93 | | //============================================================ |
| 94 | | |
| 95 | | void osd_event_free(osd_event *event) |
| 96 | | { |
| 97 | | } |
| 98 | | |
| 99 | | |
| 100 | | //============================================================ |
| 101 | | // osd_event_set |
| 102 | | //============================================================ |
| 103 | | |
| 104 | | void osd_event_set(osd_event *event) |
| 105 | | { |
| 106 | | } |
| 107 | | |
| 108 | | |
| 109 | | //============================================================ |
| 110 | | // osd_event_reset |
| 111 | | //============================================================ |
| 112 | | |
| 113 | | void osd_event_reset(osd_event *event) |
| 114 | | { |
| 115 | | } |
| 116 | | |
| 117 | | |
| 118 | | //============================================================ |
| 119 | | // osd_event_wait |
| 120 | | //============================================================ |
| 121 | | |
| 122 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 123 | | { |
| 124 | | return TRUE; |
| 125 | | } |
| 126 | | |
| 127 | | |
| 128 | | //============================================================ |
| 129 | | // osd_thread_create |
| 130 | | //============================================================ |
| 131 | | |
| 132 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 133 | | { |
| 134 | | return NULL; |
| 135 | | } |
| 136 | | |
| 137 | | |
| 138 | | //============================================================ |
| 139 | | // osd_thread_adjust_priority |
| 140 | | //============================================================ |
| 141 | | |
| 142 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 143 | | { |
| 144 | | return FALSE; |
| 145 | | } |
| 146 | | |
| 147 | | |
| 148 | | //============================================================ |
| 149 | | // osd_thread_cpu_affinity |
| 150 | | //============================================================ |
| 151 | | |
| 152 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 153 | | { |
| 154 | | return TRUE; |
| 155 | | } |
| 156 | | |
| 157 | | |
| 158 | | //============================================================ |
| 159 | | // osd_thread_wait_free |
| 160 | | //============================================================ |
| 161 | | |
| 162 | | void osd_thread_wait_free(osd_thread *thread) |
| 163 | | { |
| 164 | | } |
| 165 | | |
| 166 | | |
| 167 | | //============================================================ |
| 168 | | // osd_process_kill |
| 169 | | //============================================================ |
| 170 | | |
| 171 | | void osd_process_kill(void) |
| 172 | | { |
| 173 | | } |
trunk/src/osd/sdl/sdlsync_ntc.c
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // sdlsync.c - SDL core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2011, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #ifndef _GNU_SOURCE |
| 13 | | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | | #endif |
| 15 | | |
| 16 | | #include "sdlinc.h" |
| 17 | | |
| 18 | | #ifdef SDLMAME_MACOSX |
| 19 | | #include <mach/mach.h> |
| 20 | | #include <signal.h> |
| 21 | | #endif |
| 22 | | |
| 23 | | #if defined(SDLMAME_NETBSD) || defined(SDLMAME_OPENBSD) |
| 24 | | /* for SIGKILL */ |
| 25 | | #include <signal.h> |
| 26 | | #endif |
| 27 | | |
| 28 | | // standard C headers |
| 29 | | #include <math.h> |
| 30 | | #include <unistd.h> |
| 31 | | |
| 32 | | // MAME headers |
| 33 | | #include "osdcore.h" |
| 34 | | #include "osinline.h" |
| 35 | | #include "sdlsync.h" |
| 36 | | |
| 37 | | #include "eminline.h" |
| 38 | | |
| 39 | | #include <pthread.h> |
| 40 | | #include <errno.h> |
| 41 | | #include <sys/time.h> |
| 42 | | |
| 43 | | struct osd_lock { |
| 44 | | volatile pthread_t holder; |
| 45 | | INT32 count; |
| 46 | | #ifdef PTR64 |
| 47 | | INT8 padding[52]; // Fill a 64-byte cache line |
| 48 | | #else |
| 49 | | INT8 padding[56]; // A bit more padding |
| 50 | | #endif |
| 51 | | }; |
| 52 | | |
| 53 | | struct osd_event { |
| 54 | | pthread_mutex_t mutex; |
| 55 | | pthread_cond_t cond; |
| 56 | | volatile INT32 autoreset; |
| 57 | | volatile INT32 signalled; |
| 58 | | #ifdef PTR64 |
| 59 | | INT8 padding[40]; // Fill a 64-byte cache line |
| 60 | | #else |
| 61 | | INT8 padding[48]; // A bit more padding |
| 62 | | #endif |
| 63 | | }; |
| 64 | | |
| 65 | | |
| 66 | | //============================================================ |
| 67 | | // TYPE DEFINITIONS |
| 68 | | //============================================================ |
| 69 | | |
| 70 | | struct osd_thread { |
| 71 | | pthread_t thread; |
| 72 | | }; |
| 73 | | |
| 74 | | struct osd_scalable_lock |
| 75 | | { |
| 76 | | struct |
| 77 | | { |
| 78 | | volatile INT32 haslock; // do we have the lock? |
| 79 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 80 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 81 | | volatile INT32 nextindex; // index of next slot to use |
| 82 | | }; |
| 83 | | |
| 84 | | |
| 85 | | //============================================================ |
| 86 | | // Scalable Locks |
| 87 | | //============================================================ |
| 88 | | |
| 89 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 90 | | { |
| 91 | | osd_scalable_lock *lock; |
| 92 | | |
| 93 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 94 | | |
| 95 | | memset(lock, 0, sizeof(*lock)); |
| 96 | | lock->slot[0].haslock = TRUE; |
| 97 | | return lock; |
| 98 | | } |
| 99 | | |
| 100 | | |
| 101 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 102 | | { |
| 103 | | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 104 | | |
| 105 | | #if defined(__i386__) || defined(__x86_64__) |
| 106 | | register INT32 tmp; |
| 107 | | __asm__ __volatile__ ( |
| 108 | | "1: clr %[tmp] ;" |
| 109 | | " xchg %[haslock], %[tmp] ;" |
| 110 | | " test %[tmp], %[tmp] ;" |
| 111 | | " jne 3f ;" |
| 112 | | "2: mov %[haslock], %[tmp] ;" |
| 113 | | " test %[tmp], %[tmp] ;" |
| 114 | | " jne 1b ;" |
| 115 | | " pause ;" |
| 116 | | " jmp 2b ;" |
| 117 | | "3: " |
| 118 | | : [haslock] "+m" (lock->slot[myslot].haslock) |
| 119 | | , [tmp] "=&r" (tmp) |
| 120 | | : |
| 121 | | : "cc" |
| 122 | | ); |
| 123 | | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 124 | | register INT32 tmp; |
| 125 | | __asm__ __volatile__ ( |
| 126 | | "1: lwarx %[tmp], 0, %[haslock] \n" |
| 127 | | " cmpwi %[tmp], 0 \n" |
| 128 | | " bne 3f \n" |
| 129 | | "2: lwzx %[tmp], 0, %[haslock] \n" |
| 130 | | " cmpwi %[tmp], 0 \n" |
| 131 | | " bne 1b \n" |
| 132 | | " nop \n" |
| 133 | | " nop \n" |
| 134 | | " b 2b \n" |
| 135 | | "3: li %[tmp], 0 \n" |
| 136 | | " sync \n" |
| 137 | | " stwcx. %[tmp], 0, %[haslock] \n" |
| 138 | | " bne- 1b \n" |
| 139 | | " eieio \n" |
| 140 | | : [tmp] "=&r" (tmp) |
| 141 | | : [haslock] "r" (&lock->slot[myslot].haslock) |
| 142 | | : "cr0" |
| 143 | | ); |
| 144 | | #else |
| 145 | | INT32 backoff = 1; |
| 146 | | while (!osd_compare_exchange32(&lock->slot[myslot].haslock, TRUE, FALSE)) |
| 147 | | { |
| 148 | | INT32 backcount; |
| 149 | | for (backcount = 0; backcount < backoff; backcount++) |
| 150 | | osd_yield_processor(); |
| 151 | | backoff <<= 1; |
| 152 | | } |
| 153 | | #endif |
| 154 | | return myslot; |
| 155 | | } |
| 156 | | |
| 157 | | |
| 158 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 159 | | { |
| 160 | | #if defined(__i386__) || defined(__x86_64__) |
| 161 | | register INT32 tmp = TRUE; |
| 162 | | __asm__ __volatile__ ( |
| 163 | | " xchg %[haslock], %[tmp] ;" |
| 164 | | : [haslock] "+m" (lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock) |
| 165 | | , [tmp] "+r" (tmp) |
| 166 | | : |
| 167 | | ); |
| 168 | | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 169 | | lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock = TRUE; |
| 170 | | __asm__ __volatile__ ( " eieio " : : ); |
| 171 | | #else |
| 172 | | osd_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 173 | | #endif |
| 174 | | } |
| 175 | | |
| 176 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 177 | | { |
| 178 | | free(lock); |
| 179 | | } |
| 180 | | |
| 181 | | INLINE pthread_t osd_compare_exchange_pthread_t(pthread_t volatile *ptr, pthread_t compare, pthread_t exchange) |
| 182 | | { |
| 183 | | #ifdef PTR64 |
| 184 | | INT64 result = compare_exchange64((INT64 volatile *)ptr, (INT64)compare, (INT64)exchange); |
| 185 | | #else |
| 186 | | INT32 result = compare_exchange32((INT32 volatile *)ptr, (INT32)compare, (INT32)exchange); |
| 187 | | #endif |
| 188 | | return (pthread_t)result; |
| 189 | | } |
| 190 | | |
| 191 | | INLINE pthread_t osd_exchange_pthread_t(pthread_t volatile *ptr, pthread_t exchange) |
| 192 | | { |
| 193 | | #ifdef PTR64 |
| 194 | | INT64 result = osd_exchange64((INT64 volatile *)ptr, (INT64)exchange); |
| 195 | | #else |
| 196 | | INT32 result = atomic_exchange32((INT32 volatile *)ptr, (INT32)exchange); |
| 197 | | #endif |
| 198 | | return (pthread_t)result; |
| 199 | | } |
| 200 | | |
| 201 | | |
| 202 | | //============================================================ |
| 203 | | // osd_lock_alloc |
| 204 | | //============================================================ |
| 205 | | |
| 206 | | osd_lock *osd_lock_alloc(void) |
| 207 | | { |
| 208 | | osd_lock *lock; |
| 209 | | |
| 210 | | lock = (osd_lock *)calloc(1, sizeof(osd_lock)); |
| 211 | | |
| 212 | | lock->holder = 0; |
| 213 | | lock->count = 0; |
| 214 | | |
| 215 | | return lock; |
| 216 | | } |
| 217 | | |
| 218 | | //============================================================ |
| 219 | | // osd_lock_acquire |
| 220 | | //============================================================ |
| 221 | | |
| 222 | | void osd_lock_acquire(osd_lock *lock) |
| 223 | | { |
| 224 | | pthread_t current, prev; |
| 225 | | |
| 226 | | current = pthread_self(); |
| 227 | | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 228 | | if (prev != (size_t)NULL && prev != current) |
| 229 | | { |
| 230 | | do { |
| 231 | | register INT32 spin = 10000; // Convenient spin count |
| 232 | | register pthread_t tmp; |
| 233 | | #if defined(__i386__) || defined(__x86_64__) |
| 234 | | __asm__ __volatile__ ( |
| 235 | | "1: pause ;" |
| 236 | | " mov %[holder], %[tmp] ;" |
| 237 | | " test %[tmp], %[tmp] ;" |
| 238 | | " loopne 1b ;" |
| 239 | | : [spin] "+c" (spin) |
| 240 | | , [tmp] "=&r" (tmp) |
| 241 | | : [holder] "m" (lock->holder) |
| 242 | | : "cc" |
| 243 | | ); |
| 244 | | #elif defined(__ppc__) || defined(__PPC__) |
| 245 | | __asm__ __volatile__ ( |
| 246 | | "1: nop \n" |
| 247 | | " nop \n" |
| 248 | | " lwzx %[tmp], 0, %[holder] \n" |
| 249 | | " cmpwi %[tmp], 0 \n" |
| 250 | | " bdnzt eq, 1b \n" |
| 251 | | : [spin] "+c" (spin) |
| 252 | | , [tmp] "=&r" (tmp) |
| 253 | | : [holder] "r" (&lock->holder) |
| 254 | | : "cr0" |
| 255 | | ); |
| 256 | | #elif defined(__ppc64__) || defined(__PPC64__) |
| 257 | | __asm__ __volatile__ ( |
| 258 | | "1: nop \n" |
| 259 | | " nop \n" |
| 260 | | " ldx %[tmp], 0, %[holder] \n" |
| 261 | | " cmpdi %[tmp], 0 \n" |
| 262 | | " bdnzt eq, 1b \n" |
| 263 | | : [spin] "+c" (spin) |
| 264 | | , [tmp] "=&r" (tmp) |
| 265 | | : [holder] "r" (&lock->holder) |
| 266 | | : "cr0" |
| 267 | | ); |
| 268 | | #else |
| 269 | | while (--spin > 0 && lock->holder != NULL) |
| 270 | | osd_yield_processor(); |
| 271 | | #endif |
| 272 | | #if 0 |
| 273 | | /* If you mean to use locks as a blocking mechanism for extended |
| 274 | | * periods of time, you should do something like this. However, |
| 275 | | * it kills the performance of gaelco3d. |
| 276 | | */ |
| 277 | | if (spin == 0) |
| 278 | | { |
| 279 | | struct timespec sleep = { 0, 100000 }, remaining; |
| 280 | | nanosleep(&sleep, &remaining); // sleep for 100us |
| 281 | | } |
| 282 | | #endif |
| 283 | | } while (osd_compare_exchange_pthread_t(&lock->holder, 0, current) != (size_t)NULL); |
| 284 | | } |
| 285 | | lock->count++; |
| 286 | | } |
| 287 | | |
| 288 | | //============================================================ |
| 289 | | // osd_lock_try |
| 290 | | //============================================================ |
| 291 | | |
| 292 | | int osd_lock_try(osd_lock *lock) |
| 293 | | { |
| 294 | | pthread_t current, prev; |
| 295 | | |
| 296 | | current = pthread_self(); |
| 297 | | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 298 | | if (prev == (size_t)NULL || prev == current) |
| 299 | | { |
| 300 | | lock->count++; |
| 301 | | return 1; |
| 302 | | } |
| 303 | | return 0; |
| 304 | | } |
| 305 | | |
| 306 | | //============================================================ |
| 307 | | // osd_lock_release |
| 308 | | //============================================================ |
| 309 | | |
| 310 | | void osd_lock_release(osd_lock *lock) |
| 311 | | { |
| 312 | | pthread_t current; |
| 313 | | |
| 314 | | current = pthread_self(); |
| 315 | | if (lock->holder == current) |
| 316 | | { |
| 317 | | if (--lock->count == 0) |
| 318 | | #if defined(__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 319 | | lock->holder = 0; |
| 320 | | __asm__ __volatile__( " eieio " : : ); |
| 321 | | #else |
| 322 | | osd_exchange_pthread_t(&lock->holder, 0); |
| 323 | | #endif |
| 324 | | return; |
| 325 | | } |
| 326 | | |
| 327 | | // trying to release a lock you don't hold is bad! |
| 328 | | // assert(lock->holder == pthread_self()); |
| 329 | | } |
| 330 | | |
| 331 | | //============================================================ |
| 332 | | // osd_lock_free |
| 333 | | //============================================================ |
| 334 | | |
| 335 | | void osd_lock_free(osd_lock *lock) |
| 336 | | { |
| 337 | | free(lock); |
| 338 | | } |
| 339 | | |
| 340 | | //============================================================ |
| 341 | | // osd_event_alloc |
| 342 | | //============================================================ |
| 343 | | |
| 344 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 345 | | { |
| 346 | | osd_event *ev; |
| 347 | | pthread_mutexattr_t mtxattr; |
| 348 | | |
| 349 | | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 350 | | |
| 351 | | pthread_mutexattr_init(&mtxattr); |
| 352 | | pthread_mutex_init(&ev->mutex, &mtxattr); |
| 353 | | pthread_cond_init(&ev->cond, NULL); |
| 354 | | ev->signalled = initialstate; |
| 355 | | ev->autoreset = !manualreset; |
| 356 | | |
| 357 | | return ev; |
| 358 | | } |
| 359 | | |
| 360 | | //============================================================ |
| 361 | | // osd_event_free |
| 362 | | //============================================================ |
| 363 | | |
| 364 | | void osd_event_free(osd_event *event) |
| 365 | | { |
| 366 | | pthread_mutex_destroy(&event->mutex); |
| 367 | | pthread_cond_destroy(&event->cond); |
| 368 | | free(event); |
| 369 | | } |
| 370 | | |
| 371 | | //============================================================ |
| 372 | | // osd_event_set |
| 373 | | //============================================================ |
| 374 | | |
| 375 | | void osd_event_set(osd_event *event) |
| 376 | | { |
| 377 | | pthread_mutex_lock(&event->mutex); |
| 378 | | if (event->signalled == FALSE) |
| 379 | | { |
| 380 | | event->signalled = TRUE; |
| 381 | | if (event->autoreset) |
| 382 | | pthread_cond_signal(&event->cond); |
| 383 | | else |
| 384 | | pthread_cond_broadcast(&event->cond); |
| 385 | | } |
| 386 | | pthread_mutex_unlock(&event->mutex); |
| 387 | | } |
| 388 | | |
| 389 | | //============================================================ |
| 390 | | // osd_event_reset |
| 391 | | //============================================================ |
| 392 | | |
| 393 | | void osd_event_reset(osd_event *event) |
| 394 | | { |
| 395 | | pthread_mutex_lock(&event->mutex); |
| 396 | | event->signalled = FALSE; |
| 397 | | pthread_mutex_unlock(&event->mutex); |
| 398 | | } |
| 399 | | |
| 400 | | //============================================================ |
| 401 | | // osd_event_wait |
| 402 | | //============================================================ |
| 403 | | |
| 404 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 405 | | { |
| 406 | | pthread_mutex_lock(&event->mutex); |
| 407 | | if (!timeout) |
| 408 | | { |
| 409 | | if (!event->signalled) |
| 410 | | { |
| 411 | | pthread_mutex_unlock(&event->mutex); |
| 412 | | return FALSE; |
| 413 | | } |
| 414 | | } |
| 415 | | else |
| 416 | | { |
| 417 | | if (!event->signalled) |
| 418 | | { |
| 419 | | struct timespec ts; |
| 420 | | struct timeval tp; |
| 421 | | UINT64 msec = timeout * 1000 / osd_ticks_per_second(); |
| 422 | | UINT64 nsec; |
| 423 | | |
| 424 | | gettimeofday(&tp, NULL); |
| 425 | | |
| 426 | | ts.tv_sec = tp.tv_sec; |
| 427 | | nsec = (UINT64) tp.tv_usec * (UINT64) 1000 + (msec * (UINT64) 1000000); |
| 428 | | ts.tv_nsec = nsec % (UINT64) 1000000000; |
| 429 | | ts.tv_sec += nsec / (UINT64) 1000000000; |
| 430 | | |
| 431 | | do { |
| 432 | | int ret = pthread_cond_timedwait(&event->cond, &event->mutex, &ts); |
| 433 | | if ( ret == ETIMEDOUT ) |
| 434 | | { |
| 435 | | if (!event->signalled) |
| 436 | | { |
| 437 | | pthread_mutex_unlock(&event->mutex); |
| 438 | | return FALSE; |
| 439 | | } |
| 440 | | else |
| 441 | | break; |
| 442 | | } |
| 443 | | if (ret == 0) |
| 444 | | break; |
| 445 | | if ( ret != EINTR) |
| 446 | | { |
| 447 | | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 448 | | } |
| 449 | | |
| 450 | | } while (TRUE); |
| 451 | | } |
| 452 | | } |
| 453 | | |
| 454 | | if (event->autoreset) |
| 455 | | event->signalled = 0; |
| 456 | | |
| 457 | | pthread_mutex_unlock(&event->mutex); |
| 458 | | |
| 459 | | return TRUE; |
| 460 | | } |
| 461 | | |
| 462 | | //============================================================ |
| 463 | | // osd_thread_create |
| 464 | | //============================================================ |
| 465 | | |
| 466 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 467 | | { |
| 468 | | osd_thread *thread; |
| 469 | | pthread_attr_t attr; |
| 470 | | |
| 471 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 472 | | pthread_attr_init(&attr); |
| 473 | | #ifndef SDLMAME_HAIKU |
| 474 | | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
| 475 | | #endif |
| 476 | | if ( pthread_create(&thread->thread, &attr, callback, cbparam) != 0 ) |
| 477 | | { |
| 478 | | free(thread); |
| 479 | | return NULL; |
| 480 | | } |
| 481 | | return thread; |
| 482 | | } |
| 483 | | |
| 484 | | //============================================================ |
| 485 | | // osd_thread_adjust_priority |
| 486 | | //============================================================ |
| 487 | | |
| 488 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 489 | | { |
| 490 | | struct sched_param sched; |
| 491 | | int policy; |
| 492 | | |
| 493 | | if ( pthread_getschedparam( thread->thread, &policy, &sched ) == 0 ) |
| 494 | | { |
| 495 | | sched.sched_priority += adjust; |
| 496 | | if ( pthread_setschedparam(thread->thread, policy, &sched ) == 0) |
| 497 | | return TRUE; |
| 498 | | else |
| 499 | | return FALSE; |
| 500 | | } |
| 501 | | else |
| 502 | | return FALSE; |
| 503 | | } |
| 504 | | |
| 505 | | //============================================================ |
| 506 | | // osd_thread_cpu_affinity |
| 507 | | //============================================================ |
| 508 | | |
| 509 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 510 | | { |
| 511 | | return TRUE; |
| 512 | | } |
| 513 | | |
| 514 | | //============================================================ |
| 515 | | // osd_thread_wait_free |
| 516 | | //============================================================ |
| 517 | | |
| 518 | | void osd_thread_wait_free(osd_thread *thread) |
| 519 | | { |
| 520 | | pthread_join(thread->thread, NULL); |
| 521 | | free(thread); |
| 522 | | } |
| 523 | | |
| 524 | | //============================================================ |
| 525 | | // osd_process_kill |
| 526 | | //============================================================ |
| 527 | | |
| 528 | | void osd_process_kill(void) |
| 529 | | { |
| 530 | | kill(getpid(), SIGKILL); |
| 531 | | } |
trunk/src/osd/sdl/sdlsync_os2.c
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // sdlsync.c - SDL core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #ifndef _GNU_SOURCE |
| 13 | | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | | #endif |
| 15 | | |
| 16 | | #include "sdlinc.h" |
| 17 | | |
| 18 | | // standard C headers |
| 19 | | #include <math.h> |
| 20 | | #include <unistd.h> |
| 21 | | |
| 22 | | // MAME headers |
| 23 | | #include "osdcore.h" |
| 24 | | #include "osinline.h" |
| 25 | | #include "sdlsync.h" |
| 26 | | |
| 27 | | #include "eminline.h" |
| 28 | | |
| 29 | | #define INCL_DOS |
| 30 | | #include <os2.h> |
| 31 | | |
| 32 | | #include <stdlib.h> |
| 33 | | #define pthread_t int |
| 34 | | #define pthread_self _gettid |
| 35 | | |
| 36 | | struct osd_lock { |
| 37 | | volatile pthread_t holder; |
| 38 | | INT32 count; |
| 39 | | #ifdef PTR64 |
| 40 | | INT8 padding[52]; // Fill a 64-byte cache line |
| 41 | | #else |
| 42 | | INT8 padding[56]; // A bit more padding |
| 43 | | #endif |
| 44 | | }; |
| 45 | | |
| 46 | | struct osd_event { |
| 47 | | HMTX hmtx; |
| 48 | | HEV hev; |
| 49 | | volatile INT32 autoreset; |
| 50 | | INT8 padding[52]; // Fill a 64-byte cache line |
| 51 | | }; |
| 52 | | |
| 53 | | //============================================================ |
| 54 | | // TYPE DEFINITIONS |
| 55 | | //============================================================ |
| 56 | | |
| 57 | | struct osd_thread { |
| 58 | | pthread_t thread; |
| 59 | | osd_thread_callback callback; |
| 60 | | void *param; |
| 61 | | }; |
| 62 | | |
| 63 | | struct osd_scalable_lock |
| 64 | | { |
| 65 | | struct |
| 66 | | { |
| 67 | | volatile INT32 haslock; // do we have the lock? |
| 68 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 69 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 70 | | volatile INT32 nextindex; // index of next slot to use |
| 71 | | }; |
| 72 | | |
| 73 | | |
| 74 | | //============================================================ |
| 75 | | // Scalable Locks |
| 76 | | //============================================================ |
| 77 | | |
| 78 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 79 | | { |
| 80 | | osd_scalable_lock *lock; |
| 81 | | |
| 82 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 83 | | |
| 84 | | memset(lock, 0, sizeof(*lock)); |
| 85 | | lock->slot[0].haslock = TRUE; |
| 86 | | return lock; |
| 87 | | } |
| 88 | | |
| 89 | | |
| 90 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 91 | | { |
| 92 | | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 93 | | |
| 94 | | #if defined(__i386__) || defined(__x86_64__) |
| 95 | | register INT32 tmp; |
| 96 | | __asm__ __volatile__ ( |
| 97 | | "1: clr %[tmp] ;" |
| 98 | | " xchg %[haslock], %[tmp] ;" |
| 99 | | " test %[tmp], %[tmp] ;" |
| 100 | | " jne 3f ;" |
| 101 | | "2: mov %[haslock], %[tmp] ;" |
| 102 | | " test %[tmp], %[tmp] ;" |
| 103 | | " jne 1b ;" |
| 104 | | " pause ;" |
| 105 | | " jmp 2b ;" |
| 106 | | "3: " |
| 107 | | : [haslock] "+m" (lock->slot[myslot].haslock) |
| 108 | | , [tmp] "=&r" (tmp) |
| 109 | | : |
| 110 | | : "%cc" |
| 111 | | ); |
| 112 | | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 113 | | register INT32 tmp; |
| 114 | | __asm__ __volatile__ ( |
| 115 | | "1: lwarx %[tmp], 0, %[haslock] \n" |
| 116 | | " cmpwi %[tmp], 0 \n" |
| 117 | | " bne 3f \n" |
| 118 | | "2: lwzx %[tmp], 0, %[haslock] \n" |
| 119 | | " cmpwi %[tmp], 0 \n" |
| 120 | | " bne 1b \n" |
| 121 | | " nop \n" |
| 122 | | " nop \n" |
| 123 | | " b 2b \n" |
| 124 | | "3: li %[tmp], 0 \n" |
| 125 | | " sync \n" |
| 126 | | " stwcx. %[tmp], 0, %[haslock] \n" |
| 127 | | " bne- 1b \n" |
| 128 | | " eieio \n" |
| 129 | | : [tmp] "=&r" (tmp) |
| 130 | | : [haslock] "r" (&lock->slot[myslot].haslock) |
| 131 | | : "cr0" |
| 132 | | ); |
| 133 | | #else |
| 134 | | INT32 backoff = 1; |
| 135 | | while (!osd_compare_exchange32(&lock->slot[myslot].haslock, TRUE, FALSE)) |
| 136 | | { |
| 137 | | INT32 backcount; |
| 138 | | for (backcount = 0; backcount < backoff; backcount++) |
| 139 | | osd_yield_processor(); |
| 140 | | backoff <<= 1; |
| 141 | | } |
| 142 | | #endif |
| 143 | | return myslot; |
| 144 | | } |
| 145 | | |
| 146 | | |
| 147 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 148 | | { |
| 149 | | #if defined(__i386__) || defined(__x86_64__) |
| 150 | | register INT32 tmp = TRUE; |
| 151 | | __asm__ __volatile__ ( |
| 152 | | " xchg %[haslock], %[tmp] ;" |
| 153 | | : [haslock] "+m" (lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock) |
| 154 | | , [tmp] "+r" (tmp) |
| 155 | | : |
| 156 | | ); |
| 157 | | #elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 158 | | lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock = TRUE; |
| 159 | | __asm__ __volatile__ ( " eieio " : : ); |
| 160 | | #else |
| 161 | | osd_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 162 | | #endif |
| 163 | | } |
| 164 | | |
| 165 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 166 | | { |
| 167 | | free(lock); |
| 168 | | } |
| 169 | | |
| 170 | | INLINE pthread_t osd_compare_exchange_pthread_t(pthread_t volatile *ptr, pthread_t compare, pthread_t exchange) |
| 171 | | { |
| 172 | | #ifdef PTR64 |
| 173 | | INT64 result = compare_exchange64((INT64 volatile *)ptr, (INT64)compare, (INT64)exchange); |
| 174 | | #else |
| 175 | | INT32 result = compare_exchange32((INT32 volatile *)ptr, (INT32)compare, (INT32)exchange); |
| 176 | | #endif |
| 177 | | return (pthread_t)result; |
| 178 | | } |
| 179 | | |
| 180 | | INLINE pthread_t osd_exchange_pthread_t(pthread_t volatile *ptr, pthread_t exchange) |
| 181 | | { |
| 182 | | #ifdef PTR64 |
| 183 | | INT64 result = osd_exchange64((INT64 volatile *)ptr, (INT64)exchange); |
| 184 | | #else |
| 185 | | INT32 result = atomic_exchange32((INT32 volatile *)ptr, (INT32)exchange); |
| 186 | | #endif |
| 187 | | return (pthread_t)result; |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | //============================================================ |
| 192 | | // osd_lock_alloc |
| 193 | | //============================================================ |
| 194 | | |
| 195 | | osd_lock *osd_lock_alloc(void) |
| 196 | | { |
| 197 | | osd_lock *lock; |
| 198 | | |
| 199 | | lock = (osd_lock *)calloc(1, sizeof(osd_lock)); |
| 200 | | |
| 201 | | lock->holder = 0; |
| 202 | | lock->count = 0; |
| 203 | | |
| 204 | | return lock; |
| 205 | | } |
| 206 | | |
| 207 | | //============================================================ |
| 208 | | // osd_lock_acquire |
| 209 | | //============================================================ |
| 210 | | |
| 211 | | void osd_lock_acquire(osd_lock *lock) |
| 212 | | { |
| 213 | | pthread_t current, prev; |
| 214 | | |
| 215 | | current = pthread_self(); |
| 216 | | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 217 | | if (prev != (size_t)NULL && prev != current) |
| 218 | | { |
| 219 | | do { |
| 220 | | register INT32 spin = 10000; // Convenient spin count |
| 221 | | register pthread_t tmp; |
| 222 | | #if defined(__i386__) || defined(__x86_64__) |
| 223 | | __asm__ __volatile__ ( |
| 224 | | "1: pause ;" |
| 225 | | " mov %[holder], %[tmp] ;" |
| 226 | | " test %[tmp], %[tmp] ;" |
| 227 | | " loopne 1b ;" |
| 228 | | : [spin] "+c" (spin) |
| 229 | | , [tmp] "=&r" (tmp) |
| 230 | | : [holder] "m" (lock->holder) |
| 231 | | : "%cc" |
| 232 | | ); |
| 233 | | #elif defined(__ppc__) || defined(__PPC__) |
| 234 | | __asm__ __volatile__ ( |
| 235 | | "1: nop \n" |
| 236 | | " nop \n" |
| 237 | | " lwzx %[tmp], 0, %[holder] \n" |
| 238 | | " cmpwi %[tmp], 0 \n" |
| 239 | | " bdnzt eq, 1b \n" |
| 240 | | : [spin] "+c" (spin) |
| 241 | | , [tmp] "=&r" (tmp) |
| 242 | | : [holder] "r" (&lock->holder) |
| 243 | | : "cr0" |
| 244 | | ); |
| 245 | | #elif defined(__ppc64__) || defined(__PPC64__) |
| 246 | | __asm__ __volatile__ ( |
| 247 | | "1: nop \n" |
| 248 | | " nop \n" |
| 249 | | " ldx %[tmp], 0, %[holder] \n" |
| 250 | | " cmpdi %[tmp], 0 \n" |
| 251 | | " bdnzt eq, 1b \n" |
| 252 | | : [spin] "+c" (spin) |
| 253 | | , [tmp] "=&r" (tmp) |
| 254 | | : [holder] "r" (&lock->holder) |
| 255 | | : "cr0" |
| 256 | | ); |
| 257 | | #else |
| 258 | | while (--spin > 0 && lock->holder != NULL) |
| 259 | | osd_yield_processor(); |
| 260 | | #endif |
| 261 | | #if 0 |
| 262 | | /* If you mean to use locks as a blocking mechanism for extended |
| 263 | | * periods of time, you should do something like this. However, |
| 264 | | * it kills the performance of gaelco3d. |
| 265 | | */ |
| 266 | | if (spin == 0) |
| 267 | | { |
| 268 | | struct timespec sleep = { 0, 100000 }, remaining; |
| 269 | | nanosleep(&sleep, &remaining); // sleep for 100us |
| 270 | | } |
| 271 | | #endif |
| 272 | | } while (osd_compare_exchange_pthread_t(&lock->holder, 0, current) != (size_t)NULL); |
| 273 | | } |
| 274 | | lock->count++; |
| 275 | | } |
| 276 | | |
| 277 | | //============================================================ |
| 278 | | // osd_lock_try |
| 279 | | //============================================================ |
| 280 | | |
| 281 | | int osd_lock_try(osd_lock *lock) |
| 282 | | { |
| 283 | | pthread_t current, prev; |
| 284 | | |
| 285 | | current = pthread_self(); |
| 286 | | prev = osd_compare_exchange_pthread_t(&lock->holder, 0, current); |
| 287 | | if (prev == (size_t)NULL || prev == current) |
| 288 | | { |
| 289 | | lock->count++; |
| 290 | | return 1; |
| 291 | | } |
| 292 | | return 0; |
| 293 | | } |
| 294 | | |
| 295 | | //============================================================ |
| 296 | | // osd_lock_release |
| 297 | | //============================================================ |
| 298 | | |
| 299 | | void osd_lock_release(osd_lock *lock) |
| 300 | | { |
| 301 | | pthread_t current; |
| 302 | | |
| 303 | | current = pthread_self(); |
| 304 | | if (lock->holder == current) |
| 305 | | { |
| 306 | | if (--lock->count == 0) |
| 307 | | #if defined(__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__) |
| 308 | | lock->holder = 0; |
| 309 | | __asm__ __volatile__( " eieio " : : ); |
| 310 | | #else |
| 311 | | osd_exchange_pthread_t(&lock->holder, 0); |
| 312 | | #endif |
| 313 | | return; |
| 314 | | } |
| 315 | | |
| 316 | | // trying to release a lock you don't hold is bad! |
| 317 | | // assert(lock->holder == pthread_self()); |
| 318 | | } |
| 319 | | |
| 320 | | //============================================================ |
| 321 | | // osd_lock_free |
| 322 | | //============================================================ |
| 323 | | |
| 324 | | void osd_lock_free(osd_lock *lock) |
| 325 | | { |
| 326 | | free(lock); |
| 327 | | } |
| 328 | | |
| 329 | | //============================================================ |
| 330 | | // osd_event_alloc |
| 331 | | //============================================================ |
| 332 | | |
| 333 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 334 | | { |
| 335 | | osd_event *ev; |
| 336 | | |
| 337 | | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 338 | | |
| 339 | | DosCreateMutexSem(NULL, &ev->hmtx, 0, FALSE); |
| 340 | | DosCreateEventSem(NULL, &ev->hev, 0, initialstate); |
| 341 | | ev->autoreset = !manualreset; |
| 342 | | |
| 343 | | return ev; |
| 344 | | } |
| 345 | | |
| 346 | | //============================================================ |
| 347 | | // osd_event_free |
| 348 | | //============================================================ |
| 349 | | |
| 350 | | void osd_event_free(osd_event *event) |
| 351 | | { |
| 352 | | DosCloseMutexSem(event->hmtx); |
| 353 | | DosCloseEventSem(event->hev); |
| 354 | | free(event); |
| 355 | | } |
| 356 | | |
| 357 | | //============================================================ |
| 358 | | // osd_event_set |
| 359 | | //============================================================ |
| 360 | | |
| 361 | | void osd_event_set(osd_event *event) |
| 362 | | { |
| 363 | | DosPostEventSem(event->hev); |
| 364 | | } |
| 365 | | |
| 366 | | //============================================================ |
| 367 | | // osd_event_reset |
| 368 | | //============================================================ |
| 369 | | |
| 370 | | void osd_event_reset(osd_event *event) |
| 371 | | { |
| 372 | | ULONG ulCount; |
| 373 | | |
| 374 | | DosResetEventSem(event->hev, &ulCount); |
| 375 | | } |
| 376 | | |
| 377 | | //============================================================ |
| 378 | | // osd_event_wait |
| 379 | | //============================================================ |
| 380 | | |
| 381 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 382 | | { |
| 383 | | ULONG rc; |
| 384 | | |
| 385 | | if(event->autoreset) |
| 386 | | DosRequestMutexSem(event->hmtx, -1); |
| 387 | | |
| 388 | | rc = DosWaitEventSem(event->hev, timeout * 1000 / osd_ticks_per_second()); |
| 389 | | |
| 390 | | if(event->autoreset) |
| 391 | | { |
| 392 | | ULONG ulCount; |
| 393 | | |
| 394 | | if(rc == 0) |
| 395 | | DosResetEventSem(event->hev, &ulCount); |
| 396 | | |
| 397 | | DosReleaseMutexSem(event->hmtx); |
| 398 | | } |
| 399 | | |
| 400 | | return (rc == 0); |
| 401 | | } |
| 402 | | |
| 403 | | //============================================================ |
| 404 | | // osd_thread_create |
| 405 | | //============================================================ |
| 406 | | |
| 407 | | static void worker_thread_entry(void *param) |
| 408 | | { |
| 409 | | osd_thread *thread = (osd_thread *) param; |
| 410 | | |
| 411 | | thread->callback(thread->param); |
| 412 | | } |
| 413 | | |
| 414 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 415 | | { |
| 416 | | osd_thread *thread; |
| 417 | | |
| 418 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 419 | | thread->callback = callback; |
| 420 | | thread->param = cbparam; |
| 421 | | thread->thread = _beginthread(worker_thread_entry, NULL, 65535, thread); |
| 422 | | if ( thread->thread == -1 ) |
| 423 | | { |
| 424 | | free(thread); |
| 425 | | return NULL; |
| 426 | | } |
| 427 | | return thread; |
| 428 | | } |
| 429 | | |
| 430 | | //============================================================ |
| 431 | | // osd_thread_adjust_priority |
| 432 | | //============================================================ |
| 433 | | |
| 434 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 435 | | { |
| 436 | | PTIB ptib; |
| 437 | | |
| 438 | | DosGetInfoBlocks(&ptib, NULL); |
| 439 | | |
| 440 | | if ( DosSetPriority(PRTYS_THREAD, PRTYC_NOCHANGE, |
| 441 | | ((BYTE)ptib->tib_ptib2->tib2_ulpri) + adjust, thread->thread )) |
| 442 | | return FALSE; |
| 443 | | |
| 444 | | |
| 445 | | return TRUE; |
| 446 | | } |
| 447 | | |
| 448 | | //============================================================ |
| 449 | | // osd_thread_cpu_affinity |
| 450 | | //============================================================ |
| 451 | | |
| 452 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 453 | | { |
| 454 | | return TRUE; |
| 455 | | } |
| 456 | | |
| 457 | | //============================================================ |
| 458 | | // osd_thread_wait_free |
| 459 | | //============================================================ |
| 460 | | |
| 461 | | void osd_thread_wait_free(osd_thread *thread) |
| 462 | | { |
| 463 | | TID tid = thread->thread; |
| 464 | | |
| 465 | | DosWaitThread(&tid, 0); |
| 466 | | free(thread); |
| 467 | | } |
| 468 | | |
| 469 | | //============================================================ |
| 470 | | // osd_process_kill |
| 471 | | //============================================================ |
| 472 | | |
| 473 | | void osd_process_kill(void) |
| 474 | | { |
| 475 | | PPIB ppib; |
| 476 | | |
| 477 | | DosGetInfoBlocks(NULL, &ppib); |
| 478 | | DosKillProcess(DKP_PROCESSTREE, ppib->pib_ulpid); |
| 479 | | } |
trunk/src/osd/sdl/sdlsync_sdl.c
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // sdlsync.c - SDL core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #include "sdlinc.h" |
| 13 | | |
| 14 | | // standard C headers |
| 15 | | #include <unistd.h> |
| 16 | | |
| 17 | | // MAME headers |
| 18 | | #include "osdcore.h" |
| 19 | | #include "osinline.h" |
| 20 | | #include "sdlsync.h" |
| 21 | | |
| 22 | | #include "eminline.h" |
| 23 | | |
| 24 | | #define VERBOSE (0) |
| 25 | | |
| 26 | | #if VERBOSE |
| 27 | | #define LOG( x ) do { printf x; printf("\n"); } while (0) |
| 28 | | #else |
| 29 | | #define LOG( x ) |
| 30 | | #endif |
| 31 | | struct hidden_mutex_t { |
| 32 | | SDL_mutex * id; |
| 33 | | volatile INT32 locked; |
| 34 | | volatile INT32 threadid; |
| 35 | | }; |
| 36 | | |
| 37 | | struct osd_event { |
| 38 | | SDL_mutex * mutex; |
| 39 | | SDL_cond * cond; |
| 40 | | volatile INT32 autoreset; |
| 41 | | volatile INT32 signalled; |
| 42 | | }; |
| 43 | | |
| 44 | | //============================================================ |
| 45 | | // TYPE DEFINITIONS |
| 46 | | //============================================================ |
| 47 | | |
| 48 | | struct osd_thread { |
| 49 | | SDL_Thread * thread; |
| 50 | | osd_thread_callback callback; |
| 51 | | void *param; |
| 52 | | }; |
| 53 | | |
| 54 | | struct osd_scalable_lock |
| 55 | | { |
| 56 | | SDL_mutex * mutex; |
| 57 | | }; |
| 58 | | |
| 59 | | //============================================================ |
| 60 | | // Scalable Locks |
| 61 | | //============================================================ |
| 62 | | |
| 63 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 64 | | { |
| 65 | | osd_scalable_lock *lock; |
| 66 | | |
| 67 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 68 | | |
| 69 | | lock->mutex = SDL_CreateMutex(); |
| 70 | | return lock; |
| 71 | | } |
| 72 | | |
| 73 | | |
| 74 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 75 | | { |
| 76 | | SDL_mutexP(lock->mutex); |
| 77 | | return 0; |
| 78 | | } |
| 79 | | |
| 80 | | |
| 81 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 82 | | { |
| 83 | | SDL_mutexV(lock->mutex); |
| 84 | | } |
| 85 | | |
| 86 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 87 | | { |
| 88 | | SDL_DestroyMutex(lock->mutex); |
| 89 | | free(lock); |
| 90 | | } |
| 91 | | |
| 92 | | //============================================================ |
| 93 | | // osd_lock_alloc |
| 94 | | //============================================================ |
| 95 | | |
| 96 | | osd_lock *osd_lock_alloc(void) |
| 97 | | { |
| 98 | | hidden_mutex_t *mutex; |
| 99 | | |
| 100 | | mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); |
| 101 | | |
| 102 | | mutex->id = SDL_CreateMutex(); |
| 103 | | |
| 104 | | return (osd_lock *)mutex; |
| 105 | | } |
| 106 | | |
| 107 | | //============================================================ |
| 108 | | // osd_lock_acquire |
| 109 | | //============================================================ |
| 110 | | |
| 111 | | void osd_lock_acquire(osd_lock *lock) |
| 112 | | { |
| 113 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 114 | | |
| 115 | | LOG(("osd_lock_acquire")); |
| 116 | | /* get the lock */ |
| 117 | | mutex->locked++; /* signal that we are *about* to lock - prevent osd_lock_try */ |
| 118 | | SDL_mutexP(mutex->id); |
| 119 | | mutex->threadid = SDL_ThreadID(); |
| 120 | | } |
| 121 | | |
| 122 | | //============================================================ |
| 123 | | // osd_lock_try |
| 124 | | //============================================================ |
| 125 | | |
| 126 | | int osd_lock_try(osd_lock *lock) |
| 127 | | { |
| 128 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 129 | | |
| 130 | | LOG(("osd_lock_try")); |
| 131 | | if (mutex->locked && mutex->threadid == SDL_ThreadID()) |
| 132 | | { |
| 133 | | /* get the lock */ |
| 134 | | SDL_mutexP(mutex->id); |
| 135 | | mutex->locked++; |
| 136 | | mutex->threadid = SDL_ThreadID(); |
| 137 | | return 1; |
| 138 | | } |
| 139 | | else if ((mutex->locked == 0)) |
| 140 | | { |
| 141 | | /* get the lock */ |
| 142 | | mutex->locked++; |
| 143 | | SDL_mutexP(mutex->id); |
| 144 | | mutex->threadid = SDL_ThreadID(); |
| 145 | | return 1; |
| 146 | | } |
| 147 | | else |
| 148 | | { |
| 149 | | /* fail */ |
| 150 | | return 0; |
| 151 | | } |
| 152 | | } |
| 153 | | |
| 154 | | //============================================================ |
| 155 | | // osd_lock_release |
| 156 | | //============================================================ |
| 157 | | |
| 158 | | void osd_lock_release(osd_lock *lock) |
| 159 | | { |
| 160 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 161 | | |
| 162 | | LOG(("osd_lock_release")); |
| 163 | | mutex->locked--; |
| 164 | | if (mutex->locked == 0) |
| 165 | | mutex->threadid = -1; |
| 166 | | SDL_mutexV(mutex->id); |
| 167 | | } |
| 168 | | |
| 169 | | //============================================================ |
| 170 | | // osd_lock_free |
| 171 | | //============================================================ |
| 172 | | |
| 173 | | void osd_lock_free(osd_lock *lock) |
| 174 | | { |
| 175 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 176 | | |
| 177 | | LOG(("osd_lock_free")); |
| 178 | | //osd_lock_release(lock); |
| 179 | | SDL_DestroyMutex(mutex->id); |
| 180 | | free(mutex); |
| 181 | | } |
| 182 | | |
| 183 | | //============================================================ |
| 184 | | // osd_event_alloc |
| 185 | | //============================================================ |
| 186 | | |
| 187 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 188 | | { |
| 189 | | osd_event *ev; |
| 190 | | |
| 191 | | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 192 | | |
| 193 | | ev->mutex = SDL_CreateMutex(); |
| 194 | | ev->cond = SDL_CreateCond(); |
| 195 | | ev->signalled = initialstate; |
| 196 | | ev->autoreset = !manualreset; |
| 197 | | |
| 198 | | return ev; |
| 199 | | } |
| 200 | | |
| 201 | | //============================================================ |
| 202 | | // osd_event_free |
| 203 | | //============================================================ |
| 204 | | |
| 205 | | void osd_event_free(osd_event *event) |
| 206 | | { |
| 207 | | SDL_DestroyMutex(event->mutex); |
| 208 | | SDL_DestroyCond(event->cond); |
| 209 | | free(event); |
| 210 | | } |
| 211 | | |
| 212 | | //============================================================ |
| 213 | | // osd_event_set |
| 214 | | //============================================================ |
| 215 | | |
| 216 | | void osd_event_set(osd_event *event) |
| 217 | | { |
| 218 | | LOG(("osd_event_set")); |
| 219 | | SDL_mutexP(event->mutex); |
| 220 | | if (event->signalled == FALSE) |
| 221 | | { |
| 222 | | event->signalled = TRUE; |
| 223 | | if (event->autoreset) |
| 224 | | SDL_CondSignal(event->cond); |
| 225 | | else |
| 226 | | SDL_CondBroadcast(event->cond); |
| 227 | | } |
| 228 | | SDL_mutexV(event->mutex); |
| 229 | | } |
| 230 | | |
| 231 | | //============================================================ |
| 232 | | // osd_event_reset |
| 233 | | //============================================================ |
| 234 | | |
| 235 | | void osd_event_reset(osd_event *event) |
| 236 | | { |
| 237 | | LOG(("osd_event_reset")); |
| 238 | | SDL_mutexP(event->mutex); |
| 239 | | event->signalled = FALSE; |
| 240 | | SDL_mutexV(event->mutex); |
| 241 | | } |
| 242 | | |
| 243 | | //============================================================ |
| 244 | | // osd_event_wait |
| 245 | | //============================================================ |
| 246 | | |
| 247 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 248 | | { |
| 249 | | LOG(("osd_event_wait")); |
| 250 | | SDL_mutexP(event->mutex); |
| 251 | | if (!timeout) |
| 252 | | { |
| 253 | | if (!event->signalled) |
| 254 | | { |
| 255 | | SDL_mutexV(event->mutex); |
| 256 | | return FALSE; |
| 257 | | } |
| 258 | | } |
| 259 | | else |
| 260 | | { |
| 261 | | if (!event->signalled) |
| 262 | | { |
| 263 | | UINT64 msec = (timeout * 1000) / osd_ticks_per_second(); |
| 264 | | |
| 265 | | do { |
| 266 | | int ret = SDL_CondWaitTimeout(event->cond, event->mutex, msec); |
| 267 | | if ( ret == SDL_MUTEX_TIMEDOUT ) |
| 268 | | { |
| 269 | | if (!event->signalled) |
| 270 | | { |
| 271 | | SDL_mutexV(event->mutex); |
| 272 | | return FALSE; |
| 273 | | } |
| 274 | | else |
| 275 | | break; |
| 276 | | } |
| 277 | | if (ret == 0) |
| 278 | | break; |
| 279 | | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 280 | | } while (TRUE); |
| 281 | | } |
| 282 | | } |
| 283 | | |
| 284 | | if (event->autoreset) |
| 285 | | event->signalled = 0; |
| 286 | | |
| 287 | | SDL_mutexV(event->mutex); |
| 288 | | |
| 289 | | return TRUE; |
| 290 | | } |
| 291 | | |
| 292 | | //============================================================ |
| 293 | | // osd_thread_create |
| 294 | | //============================================================ |
| 295 | | |
| 296 | | static int worker_thread_entry(void *param) |
| 297 | | { |
| 298 | | osd_thread *thread = (osd_thread *) param; |
| 299 | | void *res; |
| 300 | | |
| 301 | | res = thread->callback(thread->param); |
| 302 | | #ifdef PTR64 |
| 303 | | return (int) (INT64) res; |
| 304 | | #else |
| 305 | | return (int) res; |
| 306 | | #endif |
| 307 | | } |
| 308 | | |
| 309 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 310 | | { |
| 311 | | osd_thread *thread; |
| 312 | | |
| 313 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 314 | | thread->callback = callback; |
| 315 | | thread->param = cbparam; |
| 316 | | thread->thread = SDL_CreateThread(worker_thread_entry, thread); |
| 317 | | if ( thread->thread == NULL ) |
| 318 | | { |
| 319 | | free(thread); |
| 320 | | return NULL; |
| 321 | | } |
| 322 | | return thread; |
| 323 | | } |
| 324 | | |
| 325 | | //============================================================ |
| 326 | | // osd_thread_adjust_priority |
| 327 | | //============================================================ |
| 328 | | |
| 329 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 330 | | { |
| 331 | | return TRUE; |
| 332 | | } |
| 333 | | |
| 334 | | //============================================================ |
| 335 | | // osd_thread_cpu_affinity |
| 336 | | //============================================================ |
| 337 | | |
| 338 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 339 | | { |
| 340 | | return TRUE; |
| 341 | | } |
| 342 | | |
| 343 | | //============================================================ |
| 344 | | // osd_thread_wait_free |
| 345 | | //============================================================ |
| 346 | | |
| 347 | | void osd_thread_wait_free(osd_thread *thread) |
| 348 | | { |
| 349 | | int status; |
| 350 | | SDL_WaitThread(thread->thread, &status); |
| 351 | | free(thread); |
| 352 | | } |
trunk/src/osd/sdl/sdlsync_tc.c
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // sdlsync.c - SDL core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | // SDLMAME by Olivier Galibert and R. Belmont |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #ifndef _GNU_SOURCE |
| 13 | | #define _GNU_SOURCE // for PTHREAD_MUTEX_RECURSIVE; needs to be here before other glibc headers are included |
| 14 | | #endif |
| 15 | | |
| 16 | | #include "sdlinc.h" |
| 17 | | |
| 18 | | #ifdef SDLMAME_MACOSX |
| 19 | | #include <mach/mach.h> |
| 20 | | #endif |
| 21 | | |
| 22 | | // standard C headers |
| 23 | | #include <math.h> |
| 24 | | #include <stdlib.h> |
| 25 | | #include <unistd.h> |
| 26 | | |
| 27 | | // MAME headers |
| 28 | | #include "osdcomm.h" |
| 29 | | #include "osdcore.h" |
| 30 | | |
| 31 | | #include "sdlsync.h" |
| 32 | | |
| 33 | | #include <pthread.h> |
| 34 | | #include <errno.h> |
| 35 | | #include <signal.h> |
| 36 | | #include <sys/time.h> |
| 37 | | |
| 38 | | struct hidden_mutex_t { |
| 39 | | pthread_mutex_t id; |
| 40 | | }; |
| 41 | | |
| 42 | | struct osd_event { |
| 43 | | pthread_mutex_t mutex; |
| 44 | | pthread_cond_t cond; |
| 45 | | volatile INT32 autoreset; |
| 46 | | volatile INT32 signalled; |
| 47 | | #ifdef PTR64 |
| 48 | | INT8 padding[40]; // Fill a 64-byte cache line |
| 49 | | #else |
| 50 | | INT8 padding[48]; // A bit more padding |
| 51 | | #endif |
| 52 | | }; |
| 53 | | |
| 54 | | //============================================================ |
| 55 | | // TYPE DEFINITIONS |
| 56 | | //============================================================ |
| 57 | | |
| 58 | | struct osd_thread { |
| 59 | | pthread_t thread; |
| 60 | | }; |
| 61 | | |
| 62 | | struct osd_scalable_lock |
| 63 | | { |
| 64 | | osd_lock *lock; |
| 65 | | }; |
| 66 | | |
| 67 | | //============================================================ |
| 68 | | // Scalable Locks |
| 69 | | //============================================================ |
| 70 | | |
| 71 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 72 | | { |
| 73 | | osd_scalable_lock *lock; |
| 74 | | |
| 75 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 76 | | |
| 77 | | lock->lock = osd_lock_alloc(); |
| 78 | | return lock; |
| 79 | | } |
| 80 | | |
| 81 | | |
| 82 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 83 | | { |
| 84 | | osd_lock_acquire(lock->lock); |
| 85 | | return 0; |
| 86 | | } |
| 87 | | |
| 88 | | |
| 89 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 90 | | { |
| 91 | | osd_lock_release(lock->lock); |
| 92 | | } |
| 93 | | |
| 94 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 95 | | { |
| 96 | | osd_lock_free(lock->lock); |
| 97 | | free(lock); |
| 98 | | } |
| 99 | | |
| 100 | | |
| 101 | | //============================================================ |
| 102 | | // osd_lock_alloc |
| 103 | | //============================================================ |
| 104 | | |
| 105 | | osd_lock *osd_lock_alloc(void) |
| 106 | | { |
| 107 | | hidden_mutex_t *mutex; |
| 108 | | pthread_mutexattr_t mtxattr; |
| 109 | | |
| 110 | | mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); |
| 111 | | |
| 112 | | pthread_mutexattr_init(&mtxattr); |
| 113 | | pthread_mutexattr_settype(&mtxattr, PTHREAD_MUTEX_RECURSIVE); |
| 114 | | pthread_mutex_init(&mutex->id, &mtxattr); |
| 115 | | |
| 116 | | return (osd_lock *)mutex; |
| 117 | | } |
| 118 | | |
| 119 | | //============================================================ |
| 120 | | // osd_lock_acquire |
| 121 | | //============================================================ |
| 122 | | |
| 123 | | void osd_lock_acquire(osd_lock *lock) |
| 124 | | { |
| 125 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 126 | | int r; |
| 127 | | |
| 128 | | r = pthread_mutex_lock(&mutex->id); |
| 129 | | if (r==0) |
| 130 | | return; |
| 131 | | //osd_printf_error("Error on lock: %d: %s\n", r, strerror(r)); |
| 132 | | } |
| 133 | | |
| 134 | | //============================================================ |
| 135 | | // osd_lock_try |
| 136 | | //============================================================ |
| 137 | | |
| 138 | | int osd_lock_try(osd_lock *lock) |
| 139 | | { |
| 140 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 141 | | int r; |
| 142 | | |
| 143 | | r = pthread_mutex_trylock(&mutex->id); |
| 144 | | if (r==0) |
| 145 | | return 1; |
| 146 | | //if (r!=EBUSY) |
| 147 | | // osd_printf_error("Error on trylock: %d: %s\n", r, strerror(r)); |
| 148 | | return 0; |
| 149 | | } |
| 150 | | |
| 151 | | //============================================================ |
| 152 | | // osd_lock_release |
| 153 | | //============================================================ |
| 154 | | |
| 155 | | void osd_lock_release(osd_lock *lock) |
| 156 | | { |
| 157 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 158 | | |
| 159 | | pthread_mutex_unlock(&mutex->id); |
| 160 | | } |
| 161 | | |
| 162 | | //============================================================ |
| 163 | | // osd_lock_free |
| 164 | | //============================================================ |
| 165 | | |
| 166 | | void osd_lock_free(osd_lock *lock) |
| 167 | | { |
| 168 | | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 169 | | |
| 170 | | //pthread_mutex_unlock(&mutex->id); |
| 171 | | pthread_mutex_destroy(&mutex->id); |
| 172 | | free(mutex); |
| 173 | | } |
| 174 | | |
| 175 | | //============================================================ |
| 176 | | // osd_event_alloc |
| 177 | | //============================================================ |
| 178 | | |
| 179 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 180 | | { |
| 181 | | osd_event *ev; |
| 182 | | pthread_mutexattr_t mtxattr; |
| 183 | | |
| 184 | | ev = (osd_event *)calloc(1, sizeof(osd_event)); |
| 185 | | |
| 186 | | pthread_mutexattr_init(&mtxattr); |
| 187 | | pthread_mutex_init(&ev->mutex, &mtxattr); |
| 188 | | pthread_cond_init(&ev->cond, NULL); |
| 189 | | ev->signalled = initialstate; |
| 190 | | ev->autoreset = !manualreset; |
| 191 | | |
| 192 | | return ev; |
| 193 | | } |
| 194 | | |
| 195 | | //============================================================ |
| 196 | | // osd_event_free |
| 197 | | //============================================================ |
| 198 | | |
| 199 | | void osd_event_free(osd_event *event) |
| 200 | | { |
| 201 | | pthread_mutex_destroy(&event->mutex); |
| 202 | | pthread_cond_destroy(&event->cond); |
| 203 | | free(event); |
| 204 | | } |
| 205 | | |
| 206 | | //============================================================ |
| 207 | | // osd_event_set |
| 208 | | //============================================================ |
| 209 | | |
| 210 | | void osd_event_set(osd_event *event) |
| 211 | | { |
| 212 | | pthread_mutex_lock(&event->mutex); |
| 213 | | if (event->signalled == FALSE) |
| 214 | | { |
| 215 | | event->signalled = TRUE; |
| 216 | | if (event->autoreset) |
| 217 | | pthread_cond_signal(&event->cond); |
| 218 | | else |
| 219 | | pthread_cond_broadcast(&event->cond); |
| 220 | | } |
| 221 | | pthread_mutex_unlock(&event->mutex); |
| 222 | | } |
| 223 | | |
| 224 | | //============================================================ |
| 225 | | // osd_event_reset |
| 226 | | //============================================================ |
| 227 | | |
| 228 | | void osd_event_reset(osd_event *event) |
| 229 | | { |
| 230 | | pthread_mutex_lock(&event->mutex); |
| 231 | | event->signalled = FALSE; |
| 232 | | pthread_mutex_unlock(&event->mutex); |
| 233 | | } |
| 234 | | |
| 235 | | //============================================================ |
| 236 | | // osd_event_wait |
| 237 | | //============================================================ |
| 238 | | |
| 239 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 240 | | { |
| 241 | | pthread_mutex_lock(&event->mutex); |
| 242 | | if (!timeout) |
| 243 | | { |
| 244 | | if (!event->signalled) |
| 245 | | { |
| 246 | | pthread_mutex_unlock(&event->mutex); |
| 247 | | return FALSE; |
| 248 | | } |
| 249 | | } |
| 250 | | else |
| 251 | | { |
| 252 | | if (!event->signalled) |
| 253 | | { |
| 254 | | struct timespec ts; |
| 255 | | struct timeval tp; |
| 256 | | UINT64 msec = timeout * 1000 / osd_ticks_per_second(); |
| 257 | | UINT64 nsec; |
| 258 | | |
| 259 | | gettimeofday(&tp, NULL); |
| 260 | | |
| 261 | | ts.tv_sec = tp.tv_sec; |
| 262 | | nsec = (UINT64) tp.tv_usec * (UINT64) 1000 + (msec * (UINT64) 1000000); |
| 263 | | ts.tv_nsec = nsec % (UINT64) 1000000000; |
| 264 | | ts.tv_sec += nsec / (UINT64) 1000000000; |
| 265 | | |
| 266 | | do { |
| 267 | | int ret = pthread_cond_timedwait(&event->cond, &event->mutex, &ts); |
| 268 | | if ( ret == ETIMEDOUT ) |
| 269 | | { |
| 270 | | if (!event->signalled) |
| 271 | | { |
| 272 | | pthread_mutex_unlock(&event->mutex); |
| 273 | | return FALSE; |
| 274 | | } |
| 275 | | else |
| 276 | | break; |
| 277 | | } |
| 278 | | if (ret == 0) |
| 279 | | break; |
| 280 | | if ( ret != EINTR) |
| 281 | | { |
| 282 | | printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); |
| 283 | | } |
| 284 | | |
| 285 | | } while (TRUE); |
| 286 | | } |
| 287 | | } |
| 288 | | |
| 289 | | if (event->autoreset) |
| 290 | | event->signalled = 0; |
| 291 | | |
| 292 | | pthread_mutex_unlock(&event->mutex); |
| 293 | | |
| 294 | | return TRUE; |
| 295 | | } |
| 296 | | |
| 297 | | //============================================================ |
| 298 | | // osd_thread_create |
| 299 | | //============================================================ |
| 300 | | |
| 301 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 302 | | { |
| 303 | | osd_thread *thread; |
| 304 | | pthread_attr_t attr; |
| 305 | | |
| 306 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 307 | | pthread_attr_init(&attr); |
| 308 | | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
| 309 | | if ( pthread_create(&thread->thread, &attr, callback, cbparam) != 0 ) |
| 310 | | { |
| 311 | | free(thread); |
| 312 | | return NULL; |
| 313 | | } |
| 314 | | return thread; |
| 315 | | } |
| 316 | | |
| 317 | | //============================================================ |
| 318 | | // osd_thread_adjust_priority |
| 319 | | //============================================================ |
| 320 | | |
| 321 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 322 | | { |
| 323 | | struct sched_param sched; |
| 324 | | int policy; |
| 325 | | |
| 326 | | if ( pthread_getschedparam( thread->thread, &policy, &sched ) == 0 ) |
| 327 | | { |
| 328 | | sched.sched_priority += adjust; |
| 329 | | if ( pthread_setschedparam(thread->thread, policy, &sched ) == 0) |
| 330 | | return TRUE; |
| 331 | | else |
| 332 | | return FALSE; |
| 333 | | } |
| 334 | | else |
| 335 | | return FALSE; |
| 336 | | } |
| 337 | | |
| 338 | | //============================================================ |
| 339 | | // osd_thread_cpu_affinity |
| 340 | | //============================================================ |
| 341 | | |
| 342 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 343 | | { |
| 344 | | #if !defined(NO_AFFINITY_NP) |
| 345 | | cpu_set_t cmask; |
| 346 | | pthread_t lthread; |
| 347 | | int bitnum; |
| 348 | | |
| 349 | | CPU_ZERO(&cmask); |
| 350 | | for (bitnum=0; bitnum<32; bitnum++) |
| 351 | | if (mask & (1<<bitnum)) |
| 352 | | CPU_SET(bitnum, &cmask); |
| 353 | | |
| 354 | | if (thread == NULL) |
| 355 | | lthread = pthread_self(); |
| 356 | | else |
| 357 | | lthread = thread->thread; |
| 358 | | |
| 359 | | if (pthread_setaffinity_np(lthread, sizeof(cmask), &cmask) <0) |
| 360 | | { |
| 361 | | /* Not available during link in all targets */ |
| 362 | | fprintf(stderr, "error %d setting cpu affinity to mask %08x", errno, mask); |
| 363 | | return FALSE; |
| 364 | | } |
| 365 | | else |
| 366 | | return TRUE; |
| 367 | | #else |
| 368 | | return TRUE; |
| 369 | | #endif |
| 370 | | } |
| 371 | | |
| 372 | | //============================================================ |
| 373 | | // osd_thread_wait_free |
| 374 | | //============================================================ |
| 375 | | |
| 376 | | void osd_thread_wait_free(osd_thread *thread) |
| 377 | | { |
| 378 | | pthread_join(thread->thread, NULL); |
| 379 | | free(thread); |
| 380 | | } |
| 381 | | |
| 382 | | //============================================================ |
| 383 | | // osd_process_kill |
| 384 | | //============================================================ |
| 385 | | |
| 386 | | void osd_process_kill(void) |
| 387 | | { |
| 388 | | kill(getpid(), SIGKILL); |
| 389 | | } |
trunk/src/osd/windows/winsync.c
| r242708 | r242709 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Aaron Giles |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // winsync.c - Win32 OSD core synchronization functions |
| 6 | | // |
| 7 | | //============================================================ |
| 8 | | |
| 9 | | // standard windows headers |
| 10 | | #define WIN32_LEAN_AND_MEAN |
| 11 | | #include <windows.h> |
| 12 | | #include <stdlib.h> |
| 13 | | #include <process.h> |
| 14 | | |
| 15 | | // MAME headers |
| 16 | | #include "osdcore.h" |
| 17 | | #include "osinline.h" |
| 18 | | #include "winsync.h" |
| 19 | | |
| 20 | | |
| 21 | | //============================================================ |
| 22 | | // DEBUGGING |
| 23 | | //============================================================ |
| 24 | | |
| 25 | | #define DEBUG_SLOW_LOCKS 0 |
| 26 | | #define USE_SCALABLE_LOCKS (0) |
| 27 | | |
| 28 | | |
| 29 | | |
| 30 | | //============================================================ |
| 31 | | // TYPE DEFINITIONS |
| 32 | | //============================================================ |
| 33 | | |
| 34 | | typedef BOOL (WINAPI *try_enter_critical_section_ptr)(LPCRITICAL_SECTION lpCriticalSection); |
| 35 | | |
| 36 | | struct osd_lock |
| 37 | | { |
| 38 | | CRITICAL_SECTION critsect; |
| 39 | | }; |
| 40 | | |
| 41 | | struct osd_event |
| 42 | | { |
| 43 | | void * ptr; |
| 44 | | }; |
| 45 | | |
| 46 | | struct osd_thread { |
| 47 | | HANDLE handle; |
| 48 | | osd_thread_callback callback; |
| 49 | | void *param; |
| 50 | | }; |
| 51 | | |
| 52 | | struct osd_scalable_lock |
| 53 | | { |
| 54 | | #if USE_SCALABLE_LOCKS |
| 55 | | struct |
| 56 | | { |
| 57 | | volatile INT32 haslock; // do we have the lock? |
| 58 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 59 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 60 | | volatile INT32 nextindex; // index of next slot to use |
| 61 | | #else |
| 62 | | CRITICAL_SECTION section; |
| 63 | | #endif |
| 64 | | }; |
| 65 | | |
| 66 | | |
| 67 | | //============================================================ |
| 68 | | // GLOBAL VARIABLES |
| 69 | | //============================================================ |
| 70 | | |
| 71 | | static try_enter_critical_section_ptr try_enter_critical_section = NULL; |
| 72 | | static int checked_for_try_enter = FALSE; |
| 73 | | |
| 74 | | |
| 75 | | |
| 76 | | //============================================================ |
| 77 | | // osd_lock_alloc |
| 78 | | //============================================================ |
| 79 | | |
| 80 | | osd_lock *osd_lock_alloc(void) |
| 81 | | { |
| 82 | | osd_lock *lock = (osd_lock *)malloc(sizeof(*lock)); |
| 83 | | if (lock == NULL) |
| 84 | | return NULL; |
| 85 | | InitializeCriticalSection(&lock->critsect); |
| 86 | | return lock; |
| 87 | | } |
| 88 | | |
| 89 | | |
| 90 | | //============================================================ |
| 91 | | // osd_lock_acquire |
| 92 | | //============================================================ |
| 93 | | |
| 94 | | void osd_lock_acquire(osd_lock *lock) |
| 95 | | { |
| 96 | | #if DEBUG_SLOW_LOCKS |
| 97 | | osd_ticks_t ticks = osd_ticks(); |
| 98 | | #endif |
| 99 | | |
| 100 | | // block until we can acquire the lock |
| 101 | | EnterCriticalSection(&lock->critsect); |
| 102 | | |
| 103 | | #if DEBUG_SLOW_LOCKS |
| 104 | | // log any locks that take more than 1ms |
| 105 | | ticks = osd_ticks() - ticks; |
| 106 | | if (ticks > osd_ticks_per_second() / 1000) osd_printf_debug("Blocked %d ticks on lock acquire\n", (int)ticks); |
| 107 | | #endif |
| 108 | | } |
| 109 | | |
| 110 | | |
| 111 | | //============================================================ |
| 112 | | // osd_lock_try |
| 113 | | //============================================================ |
| 114 | | |
| 115 | | int osd_lock_try(osd_lock *lock) |
| 116 | | { |
| 117 | | int result = TRUE; |
| 118 | | |
| 119 | | // if we haven't yet checked for the TryEnter API, do it now |
| 120 | | if (!checked_for_try_enter) |
| 121 | | { |
| 122 | | // see if we can use TryEnterCriticalSection |
| 123 | | HMODULE library = LoadLibrary(TEXT("kernel32.dll")); |
| 124 | | if (library != NULL) |
| 125 | | try_enter_critical_section = (try_enter_critical_section_ptr)GetProcAddress(library, "TryEnterCriticalSection"); |
| 126 | | checked_for_try_enter = TRUE; |
| 127 | | } |
| 128 | | |
| 129 | | // if we have it, use it, otherwise just block |
| 130 | | if (try_enter_critical_section != NULL) |
| 131 | | result = (*try_enter_critical_section)(&lock->critsect); |
| 132 | | else |
| 133 | | EnterCriticalSection(&lock->critsect); |
| 134 | | return result; |
| 135 | | } |
| 136 | | |
| 137 | | |
| 138 | | //============================================================ |
| 139 | | // osd_lock_release |
| 140 | | //============================================================ |
| 141 | | |
| 142 | | void osd_lock_release(osd_lock *lock) |
| 143 | | { |
| 144 | | LeaveCriticalSection(&lock->critsect); |
| 145 | | } |
| 146 | | |
| 147 | | |
| 148 | | //============================================================ |
| 149 | | // osd_lock_free |
| 150 | | //============================================================ |
| 151 | | |
| 152 | | void osd_lock_free(osd_lock *lock) |
| 153 | | { |
| 154 | | DeleteCriticalSection(&lock->critsect); |
| 155 | | free(lock); |
| 156 | | } |
| 157 | | |
| 158 | | |
| 159 | | //============================================================ |
| 160 | | // win_compare_exchange32 |
| 161 | | //============================================================ |
| 162 | | |
| 163 | | INT32 win_compare_exchange32(INT32 volatile *ptr, INT32 compare, INT32 exchange) |
| 164 | | { |
| 165 | | return InterlockedCompareExchange((LPLONG)ptr, (LONG)exchange, (LONG)compare); |
| 166 | | } |
| 167 | | |
| 168 | | |
| 169 | | //============================================================ |
| 170 | | // win_compare_exchange64 |
| 171 | | //============================================================ |
| 172 | | |
| 173 | | #ifdef PTR64 |
| 174 | | INT64 win_compare_exchange64(INT64 volatile *ptr, INT64 compare, INT64 exchange) |
| 175 | | { |
| 176 | | return InterlockedCompareExchange64((LONGLONG*)ptr, (LONGLONG)exchange, (LONGLONG)compare); |
| 177 | | } |
| 178 | | #endif |
| 179 | | |
| 180 | | |
| 181 | | //============================================================ |
| 182 | | // win_atomic_exchange32 |
| 183 | | //============================================================ |
| 184 | | |
| 185 | | INT32 win_atomic_exchange32(INT32 volatile *ptr, INT32 exchange) |
| 186 | | { |
| 187 | | return InterlockedExchange((LONG *) ptr, exchange); |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | //============================================================ |
| 192 | | // win_atomic_add32 |
| 193 | | //============================================================ |
| 194 | | |
| 195 | | INT32 win_atomic_add32(INT32 volatile *ptr, INT32 delta) |
| 196 | | { |
| 197 | | return InterlockedExchangeAdd((LONG *) ptr, delta) + delta; |
| 198 | | } |
| 199 | | |
| 200 | | //============================================================ |
| 201 | | // osd_event_alloc |
| 202 | | //============================================================ |
| 203 | | |
| 204 | | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 205 | | { |
| 206 | | return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL); |
| 207 | | } |
| 208 | | |
| 209 | | //============================================================ |
| 210 | | // osd_event_free |
| 211 | | //============================================================ |
| 212 | | |
| 213 | | void osd_event_free(osd_event *event) |
| 214 | | { |
| 215 | | CloseHandle((HANDLE) event); |
| 216 | | } |
| 217 | | |
| 218 | | //============================================================ |
| 219 | | // osd_event_set |
| 220 | | //============================================================ |
| 221 | | |
| 222 | | void osd_event_set(osd_event *event) |
| 223 | | { |
| 224 | | SetEvent((HANDLE) event); |
| 225 | | } |
| 226 | | |
| 227 | | //============================================================ |
| 228 | | // osd_event_reset |
| 229 | | //============================================================ |
| 230 | | |
| 231 | | void osd_event_reset(osd_event *event) |
| 232 | | { |
| 233 | | ResetEvent((HANDLE) event); |
| 234 | | } |
| 235 | | |
| 236 | | //============================================================ |
| 237 | | // osd_event_wait |
| 238 | | //============================================================ |
| 239 | | |
| 240 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 241 | | { |
| 242 | | int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second()); |
| 243 | | return ( ret == WAIT_OBJECT_0); |
| 244 | | } |
| 245 | | |
| 246 | | //============================================================ |
| 247 | | // osd_thread_create |
| 248 | | //============================================================ |
| 249 | | |
| 250 | | static unsigned __stdcall worker_thread_entry(void *param) |
| 251 | | { |
| 252 | | osd_thread *thread = (osd_thread *) param; |
| 253 | | void *res; |
| 254 | | res = thread->callback(thread->param); |
| 255 | | #ifdef PTR64 |
| 256 | | return (unsigned) (long long) res; |
| 257 | | #else |
| 258 | | return (unsigned) res; |
| 259 | | #endif |
| 260 | | } |
| 261 | | |
| 262 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) |
| 263 | | { |
| 264 | | osd_thread *thread; |
| 265 | | uintptr_t handle; |
| 266 | | |
| 267 | | thread = (osd_thread *)calloc(1, sizeof(osd_thread)); |
| 268 | | thread->callback = callback; |
| 269 | | thread->param = cbparam; |
| 270 | | handle = _beginthreadex(NULL, 0, worker_thread_entry, thread, 0, NULL); |
| 271 | | thread->handle = (HANDLE) handle; |
| 272 | | return thread; |
| 273 | | } |
| 274 | | |
| 275 | | //============================================================ |
| 276 | | // osd_thread_wait_free |
| 277 | | //============================================================ |
| 278 | | |
| 279 | | void osd_thread_wait_free(osd_thread *thread) |
| 280 | | { |
| 281 | | WaitForSingleObject(thread->handle, INFINITE); |
| 282 | | CloseHandle(thread->handle); |
| 283 | | free(thread); |
| 284 | | } |
| 285 | | |
| 286 | | //============================================================ |
| 287 | | // osd_thread_adjust_priority |
| 288 | | //============================================================ |
| 289 | | |
| 290 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust) |
| 291 | | { |
| 292 | | if (adjust) |
| 293 | | SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); |
| 294 | | else |
| 295 | | SetThreadPriority(thread->handle, GetThreadPriority(GetCurrentThread())); |
| 296 | | return TRUE; |
| 297 | | } |
| 298 | | |
| 299 | | //============================================================ |
| 300 | | // osd_thread_cpu_affinity |
| 301 | | //============================================================ |
| 302 | | |
| 303 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 304 | | { |
| 305 | | return TRUE; |
| 306 | | } |
| 307 | | |
| 308 | | //============================================================ |
| 309 | | // osd_process_kill |
| 310 | | //============================================================ |
| 311 | | |
| 312 | | void osd_process_kill(void) |
| 313 | | { |
| 314 | | TerminateProcess(GetCurrentProcess(), -1); |
| 315 | | } |
| 316 | | |
| 317 | | //============================================================ |
| 318 | | // Scalable Locks |
| 319 | | //============================================================ |
| 320 | | |
| 321 | | osd_scalable_lock *osd_scalable_lock_alloc(void) |
| 322 | | { |
| 323 | | osd_scalable_lock *lock; |
| 324 | | |
| 325 | | lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); |
| 326 | | |
| 327 | | memset(lock, 0, sizeof(*lock)); |
| 328 | | #if USE_SCALABLE_LOCKS |
| 329 | | lock->slot[0].haslock = TRUE; |
| 330 | | #else |
| 331 | | InitializeCriticalSection(&lock->section); |
| 332 | | #endif |
| 333 | | return lock; |
| 334 | | } |
| 335 | | |
| 336 | | |
| 337 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) |
| 338 | | { |
| 339 | | #if USE_SCALABLE_LOCKS |
| 340 | | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 341 | | INT32 backoff = 1; |
| 342 | | |
| 343 | | while (!lock->slot[myslot].haslock) |
| 344 | | { |
| 345 | | INT32 backcount; |
| 346 | | for (backcount = 0; backcount < backoff; backcount++) |
| 347 | | osd_yield_processor(); |
| 348 | | backoff <<= 1; |
| 349 | | } |
| 350 | | lock->slot[myslot].haslock = FALSE; |
| 351 | | return myslot; |
| 352 | | #else |
| 353 | | EnterCriticalSection(&lock->section); |
| 354 | | return 0; |
| 355 | | #endif |
| 356 | | } |
| 357 | | |
| 358 | | |
| 359 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) |
| 360 | | { |
| 361 | | #if USE_SCALABLE_LOCKS |
| 362 | | atomic_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 363 | | #else |
| 364 | | LeaveCriticalSection(&lock->section); |
| 365 | | #endif |
| 366 | | } |
| 367 | | |
| 368 | | |
| 369 | | void osd_scalable_lock_free(osd_scalable_lock *lock) |
| 370 | | { |
| 371 | | #if USE_SCALABLE_LOCKS |
| 372 | | #else |
| 373 | | DeleteCriticalSection(&lock->section); |
| 374 | | #endif |
| 375 | | free(lock); |
| 376 | | } |
trunk/src/osd/windows/winsync.h
| r242708 | r242709 | |
| 1 | | //============================================================ |
| 2 | | // |
| 3 | | // winsync.h - Windows core synchronization functions |
| 4 | | // |
| 5 | | // Copyright (c) 1996-2014, Nicola Salmoria and the MAME Team. |
| 6 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | | // |
| 8 | | //============================================================ |
| 9 | | |
| 10 | | #ifndef __WINSYNC__ |
| 11 | | #define __WINSYNC__ |
| 12 | | |
| 13 | | /*************************************************************************** |
| 14 | | SYNCHRONIZATION INTERFACES - Events |
| 15 | | ***************************************************************************/ |
| 16 | | |
| 17 | | /* osd_event is an opaque type which represents a setable/resetable event */ |
| 18 | | |
| 19 | | struct osd_event; |
| 20 | | |
| 21 | | |
| 22 | | /*----------------------------------------------------------------------------- |
| 23 | | osd_lock_event_alloc: allocate a new event |
| 24 | | |
| 25 | | Parameters: |
| 26 | | |
| 27 | | manualreset - boolean. If true, the event will be automatically set |
| 28 | | to non-signalled after a thread successfully waited for |
| 29 | | it. |
| 30 | | initialstate - boolean. If true, the event is signalled initially. |
| 31 | | |
| 32 | | Return value: |
| 33 | | |
| 34 | | A pointer to the allocated event. |
| 35 | | -----------------------------------------------------------------------------*/ |
| 36 | | osd_event *osd_event_alloc(int manualreset, int initialstate); |
| 37 | | |
| 38 | | |
| 39 | | /*----------------------------------------------------------------------------- |
| 40 | | osd_event_wait: wait for an event to be signalled |
| 41 | | |
| 42 | | Parameters: |
| 43 | | |
| 44 | | event - The event to wait for. If the event is in signalled state, the |
| 45 | | function returns immediately. If not it will wait for the event |
| 46 | | to become signalled. |
| 47 | | timeout - timeout in osd_ticks |
| 48 | | |
| 49 | | Return value: |
| 50 | | |
| 51 | | TRUE: The event was signalled |
| 52 | | FALSE: A timeout occurred |
| 53 | | -----------------------------------------------------------------------------*/ |
| 54 | | int osd_event_wait(osd_event *event, osd_ticks_t timeout); |
| 55 | | |
| 56 | | |
| 57 | | /*----------------------------------------------------------------------------- |
| 58 | | osd_event_reset: reset an event to non-signalled state |
| 59 | | |
| 60 | | Parameters: |
| 61 | | |
| 62 | | event - The event to set to non-signalled state |
| 63 | | |
| 64 | | Return value: |
| 65 | | |
| 66 | | None |
| 67 | | -----------------------------------------------------------------------------*/ |
| 68 | | void osd_event_reset(osd_event *event); |
| 69 | | |
| 70 | | |
| 71 | | /*----------------------------------------------------------------------------- |
| 72 | | osd_event_set: set an event to signalled state |
| 73 | | |
| 74 | | Parameters: |
| 75 | | |
| 76 | | event - The event to set to signalled state |
| 77 | | |
| 78 | | Return value: |
| 79 | | |
| 80 | | None |
| 81 | | |
| 82 | | Notes: |
| 83 | | |
| 84 | | All threads waiting for the event will be signalled. |
| 85 | | -----------------------------------------------------------------------------*/ |
| 86 | | void osd_event_set(osd_event *event); |
| 87 | | |
| 88 | | |
| 89 | | /*----------------------------------------------------------------------------- |
| 90 | | osd_event_free: free the memory and resources associated with an osd_event |
| 91 | | |
| 92 | | Parameters: |
| 93 | | |
| 94 | | event - a pointer to a previously allocated osd_event. |
| 95 | | |
| 96 | | Return value: |
| 97 | | |
| 98 | | None. |
| 99 | | -----------------------------------------------------------------------------*/ |
| 100 | | void osd_event_free(osd_event *event); |
| 101 | | |
| 102 | | /*************************************************************************** |
| 103 | | SYNCHRONIZATION INTERFACES - Threads |
| 104 | | ***************************************************************************/ |
| 105 | | |
| 106 | | /* osd_thread is an opaque type which represents a thread */ |
| 107 | | struct osd_thread; |
| 108 | | |
| 109 | | |
| 110 | | /* osd_thread_callback is a callback function that will be called from the thread */ |
| 111 | | typedef void *(*osd_thread_callback)(void *param); |
| 112 | | |
| 113 | | |
| 114 | | /*----------------------------------------------------------------------------- |
| 115 | | osd_thread_create: create a new thread |
| 116 | | |
| 117 | | Parameters: |
| 118 | | |
| 119 | | callback - The callback function to be called once the thread is up |
| 120 | | cbparam - The parameter to pass to the callback function. |
| 121 | | |
| 122 | | Return value: |
| 123 | | |
| 124 | | A pointer to the created thread. |
| 125 | | -----------------------------------------------------------------------------*/ |
| 126 | | osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam); |
| 127 | | |
| 128 | | /*----------------------------------------------------------------------------- |
| 129 | | osd_thread_adjust_priority: adjust priority of a thread |
| 130 | | |
| 131 | | Parameters: |
| 132 | | |
| 133 | | thread - A pointer to a previously created thread. |
| 134 | | adjust - signed integer to add to the thread priority |
| 135 | | |
| 136 | | Return value: |
| 137 | | |
| 138 | | TRUE on success, FALSE on failure |
| 139 | | -----------------------------------------------------------------------------*/ |
| 140 | | int osd_thread_adjust_priority(osd_thread *thread, int adjust); |
| 141 | | |
| 142 | | |
| 143 | | /*----------------------------------------------------------------------------- |
| 144 | | osd_thread_cpu_affinity: change cpu affinity of a thread |
| 145 | | |
| 146 | | Parameters: |
| 147 | | |
| 148 | | thread - A pointer to a previously created thread |
| 149 | | or NULL for main thread |
| 150 | | mask - bitmask to which cpus to bind |
| 151 | | i.e. 0x01 1st cpu, 0x02, 2nd cpu, 0x04 3rd cpu |
| 152 | | |
| 153 | | Return value: |
| 154 | | |
| 155 | | TRUE on success, FALSE on failure |
| 156 | | -----------------------------------------------------------------------------*/ |
| 157 | | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask); |
| 158 | | |
| 159 | | |
| 160 | | /*----------------------------------------------------------------------------- |
| 161 | | osd_thread_wait_free: wait for thread to finish and free resources |
| 162 | | |
| 163 | | Parameters: |
| 164 | | |
| 165 | | thread - A pointer to a previously created thread. |
| 166 | | |
| 167 | | Return value: |
| 168 | | |
| 169 | | None. |
| 170 | | -----------------------------------------------------------------------------*/ |
| 171 | | void osd_thread_wait_free(osd_thread *thread); |
| 172 | | |
| 173 | | /*----------------------------------------------------------------------------- |
| 174 | | osd_process_kill: kill the current process |
| 175 | | |
| 176 | | Parameters: |
| 177 | | |
| 178 | | None. |
| 179 | | |
| 180 | | Return value: |
| 181 | | |
| 182 | | None. |
| 183 | | -----------------------------------------------------------------------------*/ |
| 184 | | void osd_process_kill(void); |
| 185 | | |
| 186 | | //============================================================ |
| 187 | | // Scalable Locks |
| 188 | | //============================================================ |
| 189 | | |
| 190 | | struct osd_scalable_lock; |
| 191 | | |
| 192 | | osd_scalable_lock *osd_scalable_lock_alloc(void); |
| 193 | | |
| 194 | | INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock); |
| 195 | | |
| 196 | | void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot); |
| 197 | | |
| 198 | | void osd_scalable_lock_free(osd_scalable_lock *lock); |
| 199 | | |
| 200 | | #endif /* __WINSYNC__ */ |