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