home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / unix / programm / 4308 < prev    next >
Encoding:
Internet Message Format  |  1992-08-14  |  7.7 KB

  1. Xref: sparky comp.unix.programmer:4308 comp.unix.internals:1692
  2. Path: sparky!uunet!dtix!darwin.sura.net!mips!sdd.hp.com!caen!hellgate.utah.edu!fcom.cc.utah.edu!gateway.univel.com!ns.Novell.COM!gateway.novell.com!ithaca.Eng.Sandy.Novell.COM!terry
  3. From: terry@ithaca.Eng.Sandy.Novell.COM (Terry Lambert)
  4. Newsgroups: comp.unix.programmer,comp.unix.internals
  5. Subject: Re: SVR4 semaphore overhead???
  6. Message-ID: <1992Aug14.222159.12495@gateway.novell.com>
  7. Date: 14 Aug 92 22:21:59 GMT
  8. References: <1992Aug8.131020.17966@ttsi.lonestar.org> <1992Aug13.020203.7490@ttsi.lonestar.org>
  9. Sender: news@gateway.novell.com (NetNews)
  10. Organization: Novell NPD -- Sandy, UT
  11. Lines: 149
  12. Nntp-Posting-Host: ithaca.eng.sandy.novell.com
  13.  
  14. In article <1992Aug13.020203.7490@ttsi.lonestar.org> mse@ttsi.lonestar.org (Mark Evans) writes:
  15. >In article <1992Aug8.131020.17966@ttsi.lonestar.org> I wrote:
  16. >>I have seen postings from time to time regarding the overhead of
  17. >>semaphores in SVR4, but not many followups.  I'm now in the boat
  18. >>of considering the usage of semaphores for mutual exclusion and
  19. >>resource coordination between a substantial number (~30) of 
  20. >>processes.  There is a potential for a large number of semaphores
  21. >>(60-90) to get allocated.
  22. >>
  23. >>Someone recently posted an observation that as the number of
  24. >>semaphores in a system grows, so does the overhead.  Can anyone
  25. >>confirm this?
  26. >
  27. >On a Tandem Integrity R3000 machine running SVR4, I found no
  28. >degradation in performance on a given semaphore as the number of 
  29. >semaphores in a set increased from 1 to 25 (current sysgen'd max).
  30. >I am chagrined, however, at the 70 microseconds or so taken to
  31. >do a simple semop() lock, as compared to the .82 microseconds it
  32. >takes to call _test_and_set(), a mips-supplied routine in 
  33. >libc.a which performs an indivisible test-and-set (actually, it's
  34. >read-modify-write).  As suggested in previous articles and by
  35. >respondents to my original post, I am cooking up a
  36. >lightweight semaphore package using _test_and_test() for the
  37. >lock, and system semaphores (or message queue or pause/signal)
  38. >for sleep/wakeup when contention arises.
  39. >
  40. >A couple of questions have come up that require expert knowledge:
  41. >
  42. >(1) Is there a way for a process to reschedule itself, i.e., go to
  43. >the end of the current ready-to-run list?  I don't want to resort
  44. >to a sleep_ms() call if I can avoid it.
  45.  
  46.     Under SVR4, there is no way to do this (I will assume that you
  47. are talking about SVR4 due to the Subject: line) because the scheduler
  48. code has been intentionally seperated.  You would have to be able to
  49. determine the order in which something is removed from the ready-to-run
  50. queue and placed on the run queue, and you can't do that contextually.
  51.  
  52.     The Tandem _test_and_set() uses a hardware mechanism (precisely
  53. like that one available on VAXen), and as such is not relative to your
  54. lbolt value, but is instead relative to your system clock.  Semaphores
  55. and other consumers of CPU quantums are in terms of lbolt.
  56.  
  57. >(2) When multiple processes contend for a system semaphore, are
  58. >they rewarded in FIFO order as the semaphore becomes available?
  59. >I have gotten the impression from previous testing that this is not so.
  60. >Can anyone explain the data structures & algorithm used behind the
  61. >scenes?
  62.  
  63. No, they are not.  A wakeup is issued on the address, which moves all
  64. the processes sleeping on it to the ready_to_run queue.  The scheduler
  65. then picks one to run at the next timer interrupt.  This may not be
  66. the process who was waiting the longest (although the longer a process
  67. is waiting, the higher it's priority in the queue), and so, yes, you
  68. can get starvation.  So what you believe is correct:  Semaphore requests
  69. are not queued.
  70.  
  71. Now when the processes awaken, each attempts to grab the semaphore; the
  72. first one returns to user land; the rest go back to sleep.  This is
  73. called "the thundering herd" problem, and has been at least partially
  74. resolved in Sequent's OS, but a fat lot of good that'll do you.
  75.  
  76. >Writing this simple lock/unlock package at the user level without
  77. >resorting to priority controls is surprisingly mind-boggling if you 
  78. >consider all the races.  I'm on my fourth "I've got it" approach.
  79. >When I really do "have it," I'll happily share the results to the
  80. >many who have expressed interest in the subject.  If you think
  81. >you have a solution, I know many out here would love to see it.
  82.  
  83. One soloution is the creation of a system call.  You can do this on SVR4
  84. even though their equivalent of the init_systent.c is pre-linked into
  85. os.o and is thus not user-replacable.  The way you do this is to go
  86. through the table looking for the nosys() function pointers, and replace
  87. that entry.  The reason you use a driver is to allow you a known query
  88. point (via ioctl()) to find out which entry to use "syscall()" with,
  89. and to provide system startup initialization of the table entry and any
  90. data structures.
  91.  
  92. I have done this in two different instances to provide a FIFOed semaphore
  93. mechanism with low overhead.
  94.  
  95. Your single system call is then divided, via it's first parameter, into
  96. multiple libarary entry points for "lws_init()" to init the semaphores
  97. by returning you the sytem call to use; lws_init() then uses this entry
  98. point to make a syscall() on your behalf with the number semaphores you
  99. will need.  Another ioctl is made to indicate to the driver what needs
  100. to be cleaned up on close by this process, and then the fd is left open
  101. to allow you to resource-track close without specific deinitialization
  102. which might be defeated by a core dump or abnormal exit.
  103.  
  104. A call "lws_create()" returns the index of an entry in your table of
  105. semaphores allocated during the init or -1.
  106.  
  107. A call "lws_release()" returns the index to the unallocated pool.
  108.  
  109. A call "lws_acquire()" acquires the given index.  This will sleep on the
  110. address of the semaphore requested (ie: &my_sems[ idx]) in the kernel if
  111. the semaphore is currently allocated.  If the semaphore is allocated, the
  112. pid of the allocator is stored in the semaphore struct as well so that
  113. resource track cleanup of the process can wake up sleepers so that the
  114. semaphore in question is not deadlocked.
  115.  
  116. A call to "lws_free()" frees the given index, and does a wakeup on the
  117. associated elements address so that the next requestor can proceed.
  118.  
  119.  
  120. order:
  121.  
  122.     lws_init()
  123.     [Any number of:]
  124.         lws_create()
  125.  
  126.         [Any number of:]
  127.             lws_acquire()
  128.             lws_free()
  129.     
  130.         lws_release()
  131.     
  132.     [Resource track cleanup by close of fd on process exit]
  133.  
  134.  
  135. FIFO order can be enforced by either ignoring "the thundering herd" problem
  136. and keeping an outstanding count of requests per semaphore, wherein each
  137. attempted acquirer copies this value on initial attempt and decrements it
  138. each time it wakes up.  If the number is !0, it goes back to sleep;
  139. otherwise, it owns it.  This relies on kernel serialization of system
  140. calls, so would require a mutex on AIX/Solaris 2.0.  If the number is
  141. 0, the mutex is acquired, and the call returns to the requestor.  This
  142. has the effect of guaranteeing FIFO order.
  143.  
  144. The problem of waking up only the one who is next in line for the semaphore
  145. can be resolved by allocation of more kernel memory for "queued request
  146. elements", and sleeping on the address of your queue element rather than
  147. the semaphore list entry (which becomes a queue head pointer).  Release
  148. removes the element of the releasor from the queue, and wakes up the next
  149. entry.  This has the problem of requiring kernel memory allocation/dealloc
  150. on request/release (unless such memory is statically allocated), and
  151. complicates both the release an resource track cleanup by requiring an
  152. additional pointer and link list for all queue entries for the necessary
  153. reverse lookup.
  154.  
  155.  
  156.                     Terry Lambert
  157.                     terry_lambert@gateway.novell.com
  158.                     terry@icarus.weber.edu
  159.  
  160. ---
  161. Disclaimer:  Any opinions in this posting are my own and not those of
  162. my present or previous employers.
  163.