Friday, November 4, 2011

Global locking through StablePtr

I spoke before of using global locks in Haskell to protect a thread-unsafe C library. And I wrote about a GHC bug which breaks the most straightforward way to get a global lock.

My new solution is to store an MVar lock in a C global variable via StablePtr. I've implemented this, and it seems to work. I'd appreciate if people could bang on this code and report any issues.

You can get the library from Hackage or browse the source, including a test program. You can also use this code as a template for including a similar lock in your own Haskell project.

The C code

On the C side, we declare a global variable and a function to read that variable.

static void* global = 0;

void* hs_globalzmlock_get_global(void) {
return global;
}

To avoid name clashes, I gave this function a long name based on the z-encoding of my package's name. The variable named global will not conflict with another compilation unit, because it's declared static.

Another C function will set this variable, if it was previously 0. Two threads might execute this code concurrently, so we use a GCC built-in for atomic memory access.

int hs_globalzmlock_set_global(void* new_global) {
void* old = __sync_val_compare_and_swap(&global, 0, new_global);
return (old == 0);
}

If old is not 0, then someone has already set global, and our assignment was dropped. We report this condition to the caller.

Foreign imports

On the Haskell side, we import these C functions.

foreign import ccall unsafe "hs_globalzmlock_get_global"
c_get_global :: IO (Ptr ())

foreign import ccall "hs_globalzmlock_set_global"
c_set_global :: Ptr () -> IO CInt

The unsafe import of c_get_global demands justification. This wrinkle arises from the fact that GHC runs many Haskell threads on the same OS thread. A long-running foreign call from that OS thread might block unrelated Haskell code. GHC prevents this by moving the foreign call and/or other Haskell threads to a different OS thread. This adds latency to the foreign call — about 100 nanoseconds in my tests.

In most cases a 100 ns overhead is negligible. But it matters for functions which are guaranteed to return in a very short amount of time. And blocking other Haskell threads during such a short call is fine. Marking the import unsafe tells GHC to ignore the blocking concern, and generate a direct C function call.

Our function c_get_global is a good use case for unsafe, because it simply returns a global variable. In my tests, adding unsafe decreased the overall latency of locking by about 50%. We cannot use unsafe with c_set_global because, in the worst case, GCC implements atomic operations with blocking library functions. That's okay because c_set_global will only be called a few times anyway.

The Haskell code

Now we have access to a C global of type void*, and we want to store a Haskell value of type MVar (). The StablePtr module is just what we need. A StablePtr is a reference to some Haskell expression, which can be converted to Ptr (), aka void*. There is no guarantee about this Ptr () value, except that it can be converted back to the original StablePtr.

Here's how we store an MVar:

set :: IO ()
set = do
mv <- newMVar ()
ptr <- newStablePtr mv
ret <- c_set_global (castStablePtrToPtr ptr)
when (ret == 0) $
freeStablePtr ptr

It's fine for two threads to enter set concurrently. In one thread, the assignment will be dropped, and c_set_global will return 0. In that case we free the unused StablePtr, and the MVar will eventually be garbage-collected. StablePtrs must be freed manually, because the GHC garbage collector can't tell if some C code has stashed away the corresponding void*.

Now we can retrieve the MVar, or create it if necessary.

get :: IO (MVar ())
get = do
p <- c_get_global
if p == nullPtr
then set >> get
else deRefStablePtr (castPtrToStablePtr p)

In the common path, we do an unsynchronized read on the global variable. Only if the variable appears to contain NULL do we allocate an MVar, perform a synchronized compare-and-swap, etc. This keeps overhead low, and makes this library suitable for fine-grained locking.

All that's left is the user-visible locking interface:

lock :: IO a -> IO a
lock act = get >>= flip withMVar (const act)

Inspecting the machine code

Just for fun, let's see how GCC implements __sync_val_compare_and_swap on the AMD64 architecture.

$ objdump -d dist/build/cbits/global.o
...
0000000000000010 <hs_globalzmlock_set_global>:
  10:   31 c0                   xor    %eax,%eax
  12:   f0 48 0f b1 3d 00 00    lock cmpxchg %rdi,0x0(%rip)
  19:   00 00
....

This lock cmpxchg is the same instruction used by the GHC runtime system for its own atomic compare-and-swap. The offset on the operand 0x0(%rip) will be relocated to point at global.

18 comments:

  1. Easyworship Crack
    Cracked Here is a useful place where you can easily find Activators, Patch, Full version software Free Download, License key, serial key, keygen, Activation Key and Torrents.
    Get all of these by easily just on a single click.

    ReplyDelete
  2. Your website, especially this blog page, has recently provided me with lots of useful information. Your articles have received numerous comments as well. Thanks for sharing. This is a very popular platform and it is a topic of discussion among people. This article can help you get more likes and popularity for your Instagram post if you want more likes and popularity. To learn more, read the whole profile Generate Fake Instagram Post

    ReplyDelete
  3. เหตุผลที่ควรสมัครเดิมพันออนไลน์กับ Ufabet

    1. เว็บพนันออนไลน์ Ufabet เว็บตรง เป็นเว็บพนันที่ถูกกฎหมายจดทะเบียนจริงมีสำนักงานจริงในหลายประเทศ จึงทำให้คุณเชื่อถือบริการของที่นี่ได้

    2. บริการเกมพนันที่นี่มีให้ครบแน่นอน เดิมพันกีฬา เดิมพันคาสิโน และ ยังอัพเดทบริการเกมใหม่ ๆ ทันสมัยแปลกใหม่มากมาย เอาใจคอพนันชาวไทยตลอดทั้งปี ทุกบริการเล่นง่ายผ่านระบบออนไลน์ เป็นสมาชิกที่นี่ได้สิทธิประโยชน์อื่น ๆ ที่พร้อมให้สมาชิกเลือกได้

    3. มีพนักงานพร้อมดูแลสมาชิกมีตลอด 24 ชั่วโมง ติดต่อได้ง่าย บริการข้อมูลข่าวสารและสูตรการเดิมพันต่าง ๆ มากมายให้สมาชิกได้เล่นเดิมพันตลอดทั้งปี เล่นบริการเดิมพันทำเงินเลือกที่นี่ย้ำว่าเป็นบริการสุดพิเศษ ทำเงินได้ทำกำไรได้จริง

    ReplyDelete
  4. เล่นเดิมพันได้ลื่นไหล ทำเงินได้จริง เกมใหม่มีตลอดเวลาแน่นอน การันตีเลยว่า Ufabet ทำให้คุณไม่พลาดที่จะทำเงินกับเกมพนันทันสมัย พนันออนไลน์ ทุกบริการที่คุณต้องการมีให้ที่นี่แน่นอน ย้ำว่าอย่าพลาดหากกำลังมองหาการเดิมพันออนไลน์ดี ๆ เชื่อถือได้จ่ายจริง แนะนำเลือกที่นี่ไม่พลาดแน่นอน ก่อนตัดสินใจเลือกอ่านคำแนะนำของเราได้และเหตผลที่เราอยากบอกคือ

    ReplyDelete
  5. เว็บไซต์เดิมพันออนไลน์ที่ครบวงจรที่สุด ต้องยกนิ้วให้ SA Gaming เจ้าแห่งคาสิโนออนไลน์ดีที่สุด เล่นง่ายได้เงินจริง https://sagameallinone.com/ เว็บไซต์เดิมพันออนไลน์ ที่ครบวงจรที่สุด เกมเดิมพันออนไลน์ครบวงจร ตอบโจทย์ทุกความต้องการของผู้เล่น เพราพว่าเราได้รวบรวมเกมเดิมพันออนไลน์ทุกค่าย ทุกเกม ทุกเเขนงไว้ในเว็บไซต์เดียว เข้าถึงง่าย ใช้งานสะดวก เว็บเดียวจบครบทุกบริการ.

    ReplyDelete
  6. Gutt Websäit : Zonahobisaya
    Gutt Websäit : Sinopsis Film Terbaru
    Gutt Websäit : Zonahobisaya
    Gutt Websäit : Zonahobisaya
    Gutt Websäit : Profil
    Gutt Websäit : Zonahobisaya
    Gutt Websäit : Zonahobisaya
    Gutt Websäit : Zonahobisaya

    ReplyDelete
  7. I like your post and everything you share with is extremely informative. Keep sharing informative posting here.

    ReplyDelete
  8. C programming is a general-purpose, procedural, imperative computer programming language developed in 1972 by Dennis M.

    ReplyDelete
  9. Thank you for posting a lot of interesting posts.

    ReplyDelete
  10. I wanted to thank you for this excellent read.

    ReplyDelete
  11. I definitely loved every little bit of it.

    ReplyDelete
  12. here, but I thought this submit used to be good

    ReplyDelete
  13. You really amazed me with your writing talent. Thank you for sharing again.

    ReplyDelete
  14. This web site truly has all the information

    ReplyDelete
  15. Thanks and Best of luck to your next Blog in future.

    ReplyDelete
  16. I appreciate you sharing the helpful information in this article. Check out this article Farnsworth Lantern Test. For prospective recruits, understanding the restrictions and exclusions is essential.

    ReplyDelete