fixes for bc_cat
[sgx.git] / pvr / perproc.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include "services_headers.h"
28 #include "resman.h"
29 #include "handle.h"
30 #include "perproc.h"
31 #include "osperproc.h"
32
33 #define HASH_TAB_INIT_SIZE 32
34
35 static struct HASH_TABLE *psHashTab;
36
37 static enum PVRSRV_ERROR FreePerProcessData(
38                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc)
39 {
40         enum PVRSRV_ERROR eError;
41         u32 uiPerProc;
42
43         PVR_ASSERT(psPerProc != NULL);
44
45         if (psPerProc == NULL) {
46                 PVR_DPF(PVR_DBG_ERROR,
47                          "FreePerProcessData: invalid parameter");
48                 return PVRSRV_ERROR_INVALID_PARAMS;
49         }
50
51         uiPerProc = HASH_Remove(psHashTab, (u32)psPerProc->ui32PID);
52         if (uiPerProc == 0) {
53                 PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
54                         "Couldn't find process in per-process data hash table");
55
56                 PVR_ASSERT(psPerProc->ui32PID == 0);
57         } else {
58                 PVR_ASSERT((struct PVRSRV_PER_PROCESS_DATA *)
59                                 uiPerProc == psPerProc);
60                 PVR_ASSERT(((struct PVRSRV_PER_PROCESS_DATA *)uiPerProc)->
61                                 ui32PID == psPerProc->ui32PID);
62         }
63
64         if (psPerProc->psHandleBase != NULL) {
65                 eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
66                 if (eError != PVRSRV_OK) {
67                         PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
68                                 "Couldn't free handle base for process (%d)",
69                                  eError);
70                         return eError;
71                 }
72         }
73
74         if (psPerProc->hPerProcData != NULL) {
75                 eError =
76                     PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
77                                         psPerProc->hPerProcData,
78                                         PVRSRV_HANDLE_TYPE_PERPROC_DATA);
79
80                 if (eError != PVRSRV_OK) {
81                         PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
82                                 "Couldn't release per-process data handle (%d)",
83                                  eError);
84                         return eError;
85                 }
86         }
87
88         eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData);
89         if (eError != PVRSRV_OK) {
90                 PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
91                                 "OSPerProcessPrivateDataDeInit failed (%d)",
92                          eError);
93                 return eError;
94         }
95
96         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), psPerProc,
97                   psPerProc->hBlockAlloc);
98
99         return PVRSRV_OK;
100 }
101
102 struct PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(u32 ui32PID)
103 {
104         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
105
106         PVR_ASSERT(psHashTab != NULL);
107
108         psPerProc =
109             (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
110                                                       (u32) ui32PID);
111         return psPerProc;
112 }
113
114 enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID)
115 {
116         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
117         void *hBlockAlloc;
118         enum PVRSRV_ERROR eError = PVRSRV_OK;
119
120         PVR_ASSERT(psHashTab != NULL);
121
122         psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
123                                                       (u32)ui32PID);
124         if (psPerProc == NULL) {
125                 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
126                                     sizeof(*psPerProc), (void **)&psPerProc,
127                                     &hBlockAlloc);
128                 if (eError != PVRSRV_OK) {
129                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
130                                 "Couldn't allocate per-process data (%d)",
131                                  eError);
132                         return eError;
133                 }
134                 OSMemSet(psPerProc, 0, sizeof(*psPerProc));
135                 psPerProc->hBlockAlloc = hBlockAlloc;
136
137                 get_proc_name(ui32PID, psPerProc->name,
138                               sizeof(psPerProc->name));
139
140                 if (!HASH_Insert(psHashTab, (u32) ui32PID, (u32)psPerProc)) {
141                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
142                            "Couldn't insert per-process data into hash table");
143                         eError = PVRSRV_ERROR_GENERIC;
144                         goto failure;
145                 }
146
147                 psPerProc->ui32PID = ui32PID;
148                 psPerProc->ui32RefCount = 0;
149
150                 eError =
151                     OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData);
152                 if (eError != PVRSRV_OK) {
153                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
154                                 "OSPerProcessPrivateDataInit failed (%d)",
155                                  eError);
156                         goto failure;
157                 }
158
159                 eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE,
160                                            &psPerProc->hPerProcData,
161                                            psPerProc,
162                                            PVRSRV_HANDLE_TYPE_PERPROC_DATA,
163                                            PVRSRV_HANDLE_ALLOC_FLAG_NONE);
164                 if (eError != PVRSRV_OK) {
165                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
166                            "Couldn't allocate handle for per-process data (%d)",
167                            eError);
168                         goto failure;
169                 }
170
171                 eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase);
172                 if (eError != PVRSRV_OK) {
173                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
174                                "Couldn't allocate handle base for process (%d)",
175                                eError);
176                         goto failure;
177                 }
178
179                 eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase);
180                 if (eError != PVRSRV_OK) {
181                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
182                                         "Couldn't set handle options (%d)",
183                                  eError);
184                         goto failure;
185                 }
186
187                 eError =
188                     PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext);
189                 if (eError != PVRSRV_OK) {
190                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
191                                 "Couldn't register with the resource manager");
192                         goto failure;
193                 }
194         }
195
196         psPerProc->ui32RefCount++;
197         PVR_DPF(PVR_DBG_MESSAGE,
198                  "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d",
199                  ui32PID, psPerProc->ui32RefCount);
200
201         return eError;
202
203 failure:
204         (void)FreePerProcessData(psPerProc);
205         return eError;
206 }
207
208 void PVRSRVPerProcessDataDisconnect(u32 ui32PID)
209 {
210         enum PVRSRV_ERROR eError;
211         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
212
213         PVR_ASSERT(psHashTab != NULL);
214
215         psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
216                                                               (u32)ui32PID);
217         if (psPerProc == NULL) {
218                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDealloc: "
219                                 "Couldn't locate per-process data for PID %u",
220                          ui32PID);
221         } else {
222                 psPerProc->ui32RefCount--;
223                 if (psPerProc->ui32RefCount == 0) {
224                         PVR_DPF(PVR_DBG_MESSAGE,
225                                  "PVRSRVPerProcessDataDisconnect: "
226                                  "Last close from process 0x%x received",
227                                  ui32PID);
228
229                         PVRSRVResManDisconnect(psPerProc->hResManContext,
230                                                IMG_FALSE);
231
232                         eError = FreePerProcessData(psPerProc);
233                         if (eError != PVRSRV_OK)
234                                 PVR_DPF(PVR_DBG_ERROR,
235                                         "PVRSRVPerProcessDataDisconnect: "
236                                         "Error freeing per-process data");
237                 }
238         }
239
240         eError = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE);
241         if (eError != PVRSRV_OK)
242                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: "
243                                 "Purge of global handle pool failed (%d)",
244                          eError);
245 }
246
247 enum PVRSRV_ERROR PVRSRVPerProcessDataInit(void)
248 {
249         PVR_ASSERT(psHashTab == NULL);
250
251         psHashTab = HASH_Create(HASH_TAB_INIT_SIZE);
252         if (psHashTab == NULL) {
253                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataInit: "
254                                 "Couldn't create per-process data hash table");
255                 return PVRSRV_ERROR_GENERIC;
256         }
257
258         return PVRSRV_OK;
259 }
260
261 enum PVRSRV_ERROR PVRSRVPerProcessDataDeInit(void)
262 {
263         if (psHashTab != NULL) {
264                 HASH_Delete(psHashTab);
265                 psHashTab = NULL;
266         }
267
268         return PVRSRV_OK;
269 }