genlock.txt 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. Introduction
  2. 'genlock' is an in-kernel API and optional userspace interface for a generic
  3. cross-process locking mechanism. The API is designed for situations where
  4. multiple user space processes and/or kernel drivers need to coordinate access
  5. to a shared resource, such as a graphics buffer. The API was designed with
  6. graphics buffers in mind, but is sufficiently generic to allow it to be
  7. independently used with different types of resources. The chief advantage
  8. of genlock over other cross-process locking mechanisms is that the resources
  9. can be accessed by both userspace and kernel drivers which allows resources
  10. to be locked or unlocked by asynchronous events in the kernel without the
  11. intervention of user space.
  12. As an example, consider a graphics buffer that is shared between a rendering
  13. application and a compositing window manager. The application renders into a
  14. buffer. That buffer is reused by the compositing window manager as a texture.
  15. To avoid corruption, access to the buffer needs to be restricted so that one
  16. is not drawing on the surface while the other is reading. Locks can be
  17. explicitly added between the rendering stages in the processes, but explicit
  18. locks require that the application wait for rendering and purposely release the
  19. lock. An implicit release triggered by an asynchronous event from the GPU
  20. kernel driver, however, will let execution continue without requiring the
  21. intercession of user space.
  22. SW Goals
  23. The genlock API implements exclusive write locks and shared read locks meaning
  24. that there can only be one writer at a time, but multiple readers. Processes
  25. that are unable to acquire a lock can be optionally blocked until the resource
  26. becomes available.
  27. Locks are shared between processes. Each process will have its own private
  28. instance for a lock known as a handle. Handles can be shared between user
  29. space and kernel space to allow a kernel driver to unlock or lock a buffer
  30. on behalf of a user process.
  31. Locks within a process using a single genlock handle follow the same rules for
  32. exclusive write locks with multiple readers. Genlock cannot provide deadlock
  33. protection because the same handle can be used simultaneously by a producer and
  34. consumer. In practice in the event that the client creates a deadlock an error
  35. will still be generated when the timeout expires.
  36. Kernel API
  37. Access to the genlock API can either be via the in-kernel API or via an
  38. optional character device (/dev/genlock). The character device is primarily
  39. to be used for legacy resource sharing APIs that cannot be easily changed.
  40. New resource sharing APIs from this point should implement a scheme specific
  41. wrapper for locking.
  42. To create or attach to an existing lock, a process or kernel driver must first
  43. create a handle. Each handle is linked to a single lock at any time. An entityi
  44. may have multiple handles, each associated with a different lock. Once a handle
  45. has been created, the owner may create a new lock or attach an existing lock
  46. that has been exported from a different handle.
  47. Once the handle has a lock attached, the owning process may attempt to lock the
  48. buffer for read or write. Write locks are exclusive, meaning that only one
  49. process may acquire it at any given time. Read locks are shared, meaning that
  50. multiple readers can hold the lock at the same time. Attempts to acquire a read
  51. lock with a writer active or a write lock with one or more readers or writers
  52. active will typically cause the process to block until the lock is acquired.
  53. When the lock is released, all waiting processes will be woken up. Ownership
  54. of the lock is reference counted, meaning that any one owner can "lock"
  55. multiple times. The lock will only be released from the owner when all the
  56. references to the lock are released via unlock.
  57. The owner of a write lock may atomically convert the lock into a read lock
  58. (which will wake up other processes waiting for a read lock) without first
  59. releasing the lock. The owner would simply issue a new request for a read lock.
  60. However, the owner of a read lock cannot convert it into a write lock in the
  61. same manner. To switch from a read lock to a write lock, the owner must
  62. release the lock and then try to reacquire it.
  63. These are the in-kernel API calls that drivers can use to create and
  64. manipulate handles and locks. Handles can either be created and managed
  65. completely inside of kernel space, or shared from user space via a file
  66. descriptor.
  67. * struct genlock_handle *genlock_get_handle(void)
  68. Create a new handle.
  69. * struct genlock_handle * genlock_get_handle_fd(int fd)
  70. Given a valid file descriptor, return the handle associated with that
  71. descriptor.
  72. * void genlock_put_handle(struct genlock_handle *)
  73. Release a handle.
  74. * struct genlock * genlock_create_lock(struct genlock_handle *)
  75. Create a new lock and attach it to the handle. Once a lock is attached to a
  76. handle it stays attached until the handle is destroyed.
  77. * struct genlock * genlock_attach_lock(struct genlock_handle *handle, int fd)
  78. Given a valid file descriptor, get the lock associated with it and attach it to
  79. the handle.
  80. * int genlock_lock(struct genlock_handle *, int op, int flags, u32 timeout)
  81. Lock or unlock the lock attached to the handle. A zero timeout value will
  82. be treated just like if the GENOCK_NOBLOCK flag is passed; if the lock
  83. can be acquired without blocking then do so otherwise return -EAGAIN.
  84. Function returns -ETIMEDOUT if the timeout expired or 0 if the lock was
  85. acquired.
  86. * int genlock_wait(struct genloc_handle *, u32 timeout)
  87. Wait for a lock held by the handle to go to the unlocked state. A non-zero
  88. timeout value must be passed. Returns -ETIMEDOUT if the timeout expired or
  89. 0 if the lock is in an unlocked state.
  90. Character Device
  91. Opening an instance to the /dev/genlock character device will automatically
  92. create a new handle. All ioctl functions with the exception of NEW and
  93. RELEASE use the following parameter structure:
  94. struct genlock_lock {
  95. int fd; /* Returned by EXPORT, used by ATTACH */
  96. int op; /* Used by LOCK */
  97. int flags; /* used by LOCK */
  98. u32 timeout; /* Used by LOCK and WAIT */
  99. }
  100. *GENLOCK_IOC_NEW
  101. Create a new lock and attaches it to the handle. Returns -EINVAL if the handle
  102. already has a lock attached (use GENLOCK_IOC_RELEASE to remove it). Returns
  103. -ENOMEM if the memory for the lock can not be allocated. No data is passed
  104. from the user for this ioctl.
  105. *GENLOCK_IOC_EXPORT
  106. Export the currently attached lock to a file descriptor. The file descriptor
  107. is returned in genlock_lock.fd.
  108. *GENLOCK_IOC_ATTACH
  109. Attach an exported lock file descriptor to the current handle. Return -EINVAL
  110. if the handle already has a lock attached (use GENLOCK_IOC_RELEASE to remove
  111. it). Pass the file descriptor in genlock_lock.fd.
  112. *GENLOCK_IOC_LOCK
  113. Lock or unlock the attached lock. Pass the desired operation in
  114. genlock_lock.op:
  115. * GENLOCK_WRLOCK - write lock
  116. * GENLOCK_RDLOCK - read lock
  117. * GENLOCK_UNLOCK - unlock an existing lock
  118. Pass flags in genlock_lock.flags:
  119. * GENLOCK_NOBLOCK - Do not block if the lock is already taken
  120. * GENLOCK_WRITE_TO_READ - Convert a write lock that the handle owns to a read
  121. lock. For instance graphics may hold a write lock
  122. while rendering the back buffer then when swapping
  123. convert the lock to a read lock to copy the front
  124. buffer in the next frame for preserved buffers.
  125. Pass a timeout value in milliseconds in genlock_lock.timeout.
  126. genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
  127. Returns -EINVAL if no lock is attached, -EAGAIN if the lock is taken and
  128. NOBLOCK is specified or if the timeout value is zero, -ETIMEDOUT if the timeout
  129. expires or 0 if the lock was successful.
  130. * GENLOCK_IOC_WAIT
  131. Wait for the lock attached to the handle to be released (i.e. goes to unlock).
  132. This is mainly used for a thread that needs to wait for a peer to release a
  133. lock on the same shared handle. A non-zero timeout value in milliseconds is
  134. passed in genlock_lock.timeout. Returns 0 when the lock has been released,
  135. -EINVAL if a zero timeout is passed, or -ETIMEDOUT if the timeout expires.
  136. * GENLOCK_IOC_RELEASE
  137. This ioctl has been deprecated. Do not use.