1 /*
2  * Copyright (C) 2000-2018 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  */
20 
21 #ifndef HAVE_XINE_TICKETS_H
22 #define HAVE_XINE_TICKETS_H
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 /*
29  * xine thread tickets.
30  * This is similar to a rw lock in "prefer writers" mode.
31  * - Shared recursive read lock: acquire () / release ()
32  * - Recursive write lock:       revoke ()  / issue ()
33  * plus there are a few special hacks.
34  * - Low overhead temporary read unlock: renew ()
35  *   (better than release () + acquire ()).
36  *   Mutex less check ticket_revoked whether it is time to do so.
37  *   Yes this may delay writers a bit due to multicore data cache
38  *   sync issues (and your check interval, of course) but since
39  *   writing is rare we accept that.
40  *   Alternatively, register a revoke notify callback that stops
41  *   waiting for something else.
42  * - Read lock with priority over writers: "irrevocable"
43  *   (use for known quick actions only).
44  * - Top level uninterruptible write lock: "atomic".
45  * Note that the write side is for engine internal use.
46  * It now also supports turning an already held read into write
47  * temporarily.
48  */
49 
50 typedef void xine_ticket_revoke_cb_t (void *user_data, int flags);
51 typedef struct xine_ticket_s xine_ticket_t;
52 
53 struct xine_ticket_s {
54 
55   /* the ticket owner must assure to check for ticket revocation in
56    * intervals of finite length; this means that you must release
57    * the ticket before any operation that might block
58    *
59    * you must never write to this member directly
60    */
61   int    ticket_revoked;
62 
63   /* apply for a ticket; between acquire and relese of an irrevocable
64    * ticket (be sure to pair them properly!), it is guaranteed that you
65    * will never be blocked by ticket revocation */
66   void (*acquire)(xine_ticket_t *self, int irrevocable);
67 
68   /* give a ticket back */
69   void (*release)(xine_ticket_t *self, int irrevocable);
70 
71   /* renew a ticket, when it has been revoked, see ticket_revoked above;
72    * irrevocable must be set to one, if your thread might have acquired
73    * irrevocable tickets you don't know of; set it to zero only when
74    * you know that this is impossible. */
75   void (*renew)(xine_ticket_t *self, int irrevocable);
76 
77 #ifdef XINE_ENGINE_INTERNAL
78   /* XXX: port rewiring in the middle of a decoder loop iteration is a bad idea.
79    * We could make that halfway safe by (un)referencing post ports consistently.
80    * Unfortunately, post plugins intercept our calls at will.
81    * Even worse, we ourselves told them to inline _x_post_rewire () then
82    * still use the previous port :-/
83    * KLUDGE:
84    * - We now have 2 levels of revocation, plain and rewire.
85    * - If there is a pending rewire, ticket_revoked has the rewire flag set.
86    * - A pending or incoming rewire revoke repels plain renewers, so they
87    *   can advance to a code location more suitable for a rewire, then
88    *   renew again with rewire flag set.
89    * - Output layer get funcs return an emergency buffer/frame if engine is paused.
90    *   Why the f**k didnt we allow NULL there??
91    * - Decoder loops let the full thing go right before next iteration. */
92 #define XINE_TICKET_FLAG_ATOMIC 1
93 #define XINE_TICKET_FLAG_REWIRE 2
94 
95   /* allow handing out new tickets. atomic needs to be same as below. */
96   void (*issue)(xine_ticket_t *self, int flags);
97 
98   /* revoke all tickets and deny new ones;
99    * a pair of atomic revoke and issue cannot be interrupted by another
100    * revocation or by other threads acquiring tickets.
101    * set rewire flag to also do that lock. */
102   void (*revoke)(xine_ticket_t *self, int flags);
103 
104   /* behaves like acquire() but doesn't block the calling thread; when
105    * the thread would have been blocked, 0 is returned otherwise 1
106    * this function acquires a ticket even if ticket revocation is active */
107   int (*acquire_nonblocking)(xine_ticket_t *self, int irrevocable);
108 
109   /* behaves like release() but doesn't block the calling thread; should
110    * be used in combination with acquire_nonblocking() */
111   void (*release_nonblocking)(xine_ticket_t *self, int irrevocable);
112 
113   /* forbid port rewiring for critical code sections. */
114   int (*lock_port_rewiring)(xine_ticket_t *self, int ms_timeout);
115   void (*unlock_port_rewiring)(xine_ticket_t *self);
116 
117   void (*dispose)(xine_ticket_t *self);
118 
119   /* (un)register a revoke notify callback, telling the current revoke flags.
120    * Return from it does not * imply anything about the ticket itself,
121    * it just shall shorten wait.
122    * Note that unregister needs the same data pointer as well to
123    * handle multiple instances of the same object. */
124   void (*revoke_cb_register)  (xine_ticket_t *self, xine_ticket_revoke_cb_t *cb, void *user_data);
125   void (*revoke_cb_unregister)(xine_ticket_t *self, xine_ticket_revoke_cb_t *cb, void *user_data);
126 #endif
127 };
128 
129 #ifdef __cplusplus
130 }
131 #endif
132 
133 #endif
134