9641dfb6c7dac711c2d35f10cfa988356a564f1c
[ipc/ipcdev.git] / qnx / src / api / gates / GateMP.c
1 /*
2  * Copyright (c) 2013-2014, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== GateMP.c ========
34  */
35 #include <ti/ipc/Std.h>
37 #include <stdlib.h>
38 #include <string.h>
40 #include <pthread.h>
41 #include <assert.h>
43 #include <ti/ipc/GateMP.h>
44 #include <ti/ipc/NameServer.h>
45 #include <ti/ipc/MultiProc.h>
47 #include <GateMP_config.h>
49 #include <_GateMP.h>
50 #include <_IpcLog.h>
52 #include <_GateMP_usr.h>
54 #include <ti/syslink/inc/IoctlDefs.h>
55 #include <ti/syslink/inc/usr/Qnx/GateMPDrv.h>
56 #include <ti/syslink/inc/GateMPDrvDefs.h>
58 /* structure for GateMP module state */
59 typedef struct {
60     GateMP_Params       defaultInstParams;
61     /* Default instance creation parameters */
62     GateMP_Handle       defaultGate;
63     /* Handle to default gate */
64     NameServer_Handle   nameServer;
65     /* NameServer for GateMP instances */
66     Bool                isStarted;
67     /* Has GateMP been started */
68     pthread_mutex_t     mutex;
69     /* Mutex for use on local process to serialize access to gate obj */
70     GateMP_Object **    remoteSystemGates;
71     /* Remote system gates */
72     Int                 numRemoteSystem;
73     /* Number of remote system gates */
74 } GateMP_ModuleObject;
77 static Bool verbose = FALSE;
79 /* Internal structure defining parameters for GateMP_Instance_init */
80 typedef struct {
81     String name;                        /* Name of instance */
82     UInt16 regionId;                    /* not used on host*/
83     Ptr sharedAddr;                     /* not used on host*/
84     GateMP_LocalProtect localProtect;   /* Local protection level  */
85     GateMP_RemoteProtect remoteProtect; /* Remote protection level */
86     UInt32 resourceId;                  /* resource id */
87     Bool openFlag;                      /* Is this open or create? */
88 } _GateMP_Params;
90 static Int GateMP_getNumResources(GateMP_RemoteProtect type);
91 static Int GateMP_getFreeResource(GateMP_RemoteProtect type);
92 static Int GateMP_releaseResource(UInt id, GateMP_RemoteProtect type);
93 static GateMP_Handle _GateMP_create (const _GateMP_Params * params);
94 static Int GateMP_Instance_init(GateMP_Object *obj,
95     const _GateMP_Params *params);
96 static Void GateMP_Instance_finalize(GateMP_Object *obj, Int status);
98 /* -----------------------------------------------------------------------------
99  * Globals
100  * -----------------------------------------------------------------------------
101  */
102 static GateMP_ModuleObject GateMP_state =
104     .remoteSystemGates  = NULL,
105     .defaultGate        = NULL,
106     .nameServer         = NULL,
107     .mutex              = PTHREAD_MUTEX_INITIALIZER,
108 //    .gateMutex          = NULL,
109 //    .gateProcess        = NULL
110 };
112 static GateMP_ModuleObject *GateMP_module = &GateMP_state;
114 static GateMP_Params GateMP_defInstParams =
116     .name           = NULL,
117     .regionId       = 0,
118     .sharedAddr     = NULL,
119     .localProtect   = GateMP_LocalProtect_PROCESS,
120     .remoteProtect  = GateMP_RemoteProtect_SYSTEM
121 };
123 Int GateMP_start(Void)
125     Int status;
126     GateMPDrv_CmdArgs cmdArgs;
128     status = GateMPDrv_ioctl(CMD_GATEMP_START, &cmdArgs);
129     if (status < 0) {
130         PRINTVERBOSE1("GateMP_start: API (through IOCTL) failed, \
131             status=%d\n", status)
132     }
133     else {
134         /*
135          * Initialize module state. Note that Nameserver handles are compatible
136          * across processes.
137          */
138         GateMP_module->nameServer = cmdArgs.args.start.nameServerHandle;
139     }
141     /* allocate memory for remote system gate handles */
142     if (status == GateMP_S_SUCCESS) {
143         GateMP_module->numRemoteSystem =
144             GateMP_getNumResources(GateMP_RemoteProtect_SYSTEM);
145         if (GateMP_module->numRemoteSystem > 0) {
146             GateMP_module->remoteSystemGates = calloc(1,
147                 GateMP_module->numRemoteSystem *
148                 sizeof(IGateProvider_Handle));
150             if (GateMP_module->remoteSystemGates == NULL) {
151                 status = GateMP_E_MEMORY;
152                 PRINTVERBOSE0("GateMP_start: memory allocation failed")
153             }
154         }
155         else {
156             GateMP_module->remoteSystemGates = NULL;
157         }
158     }
160     if (status == GateMP_S_SUCCESS) {
161         /* Open default gate */
162         status = GateMP_open("_GateMP_TI_dGate", &GateMP_module->defaultGate);
163         if (status < 0) {
164             PRINTVERBOSE1("GateMP_start: could not open default gate, \
165                 status=%d\n", status)
166         }
167     }
169     /* in failure case, release acquired resources in reverse order */
170     if (status < 0) {
171         GateMP_stop();
172     }
174     GateMP_module->isStarted = TRUE;
176     return status;
179 Int GateMP_stop(Void)
181     Int status = GateMP_S_SUCCESS;
182     GateMPDrv_CmdArgs cmdArgs;
184     PRINTVERBOSE0("GateMP_stop: entered\n")
186     /* close the default gate */
187     if (GateMP_module->defaultGate) {
188         GateMP_close(&GateMP_module->defaultGate);
189         GateMP_module->defaultGate = NULL;
190     }
192     /* free system gate array */
193     if (GateMP_module->remoteSystemGates != NULL) {
194         free(GateMP_module->remoteSystemGates);
195         GateMP_module->remoteSystemGates = NULL;
196     }
198     /* Call stop in resource manager if necessary */
199     if (GateMP_module->nameServer != NULL) {
200         GateMP_module->nameServer = NULL;
201         status = GateMPDrv_ioctl(CMD_GATEMP_STOP, &cmdArgs);
202         if (status < 0) {
203             PRINTVERBOSE1("GateMP_stop: API (through IOCTL) failed, \
204                 status=%d\n", status)
205         }
206     }
208     GateMP_module->isStarted = FALSE;
210     return status;
213 Void GateMP_Params_init(GateMP_Params *params)
215     if (params != NULL) {
216         memcpy(params, &GateMP_defInstParams, sizeof(GateMP_Params));
217     }
218     else {
219         PRINTVERBOSE0("GateMP_Params_init: Params argument cannot be NULL")
220     }
222     return;
225 GateMP_Handle GateMP_create(const GateMP_Params *params)
227     _GateMP_Params      _params;
228     GateMP_Handle       handle = NULL;
230     if (GateMP_module->isStarted == FALSE) {
231         PRINTVERBOSE0("GateMP_create: GateMP module has not been started!")
232     }
233     else {
234         memset(&_params, 0, sizeof(_GateMP_Params));
235         memcpy(&_params, params, sizeof(GateMP_Params));
237         handle = _GateMP_create(&_params);
238     }
240     return(handle);
243 static GateMP_Handle _GateMP_create(const _GateMP_Params *params)
245     GateMP_Handle       handle = NULL;
246     GateMP_Object *     obj = NULL;
247     Int                 status;
249     /* allocate the instance object */
250     obj = (GateMP_Object *)calloc(1, sizeof(GateMP_Object));
252     if (obj != NULL) {
253         status = GateMP_Instance_init(obj, params);
254         if (status < 0) {
255             free(obj);
256         }
257         else {
258             handle = (GateMP_Handle)obj;
259         }
260     }
261     else {
262         PRINTVERBOSE0("GateMP_create: Memory allocation failed")
263     }
265     return(handle);
268 Int GateMP_open(String name, GateMP_Handle *handle)
270     Int             status = GateMP_S_SUCCESS;
271     UInt32          len;
272     UInt32          nsValue[4];
273     GateMP_Object * obj = NULL;
274     UInt32          arg;
275     UInt32          mask;
276     UInt32          creatorProcId;
277     _GateMP_Params  params;
279     /* assert that a valid pointer has been supplied */
280     if (handle == NULL) {
281         PRINTVERBOSE0("GateMP_open: handle cannot be null")
282         status = GateMP_E_INVALIDARG;
283     }
285     if (GateMP_module->nameServer == NULL) {
286         PRINTVERBOSE0("GateMP_open: NameServer handle is null")
287         PRINTVERBOSE0("GateMP_open: Make sure GateMP_start is called")
288         status = GateMP_E_INVALIDSTATE;
289     }
291     if (status == GateMP_S_SUCCESS) {
292         len = sizeof(nsValue);
294         status = NameServer_get(GateMP_module->nameServer, name, &nsValue,
295             &len, NULL);
297         if (status < 0) {
298             *handle = NULL;
299             status = GateMP_E_NOTFOUND;
300         }
301         else {
302             arg = nsValue[2];
303             mask = nsValue[3];
304             creatorProcId = nsValue[1] >> 16;
305         }
306     }
308     if (status == GateMP_S_SUCCESS) {
309         /*
310          * The least significant bit of nsValue[1] == 0 means its a
311          * local (private) GateMP, otherwise its a remote (shared) GateMP.
312          */
313         if ((nsValue[1] & 0x1) == 0) {
314             if ((nsValue[1] >> 16) != MultiProc_self()) {
315                 /* error: trying to open another processor's private gate */
316                 *handle = NULL;
317                 PRINTVERBOSE0("GateMP_open: cannot open private gate from \
318                     another processor")
319                 status = GateMP_E_FAIL;
320             }
321             else if (nsValue[0] != getpid()) {
322                 /* error: trying to open another process's private gate */
323                 *handle = NULL;
324                 PRINTVERBOSE0("GateMP_open: cannot open private gate from \
325                     another process")
326                 status = GateMP_E_FAIL;
327             }
328         }
329     }
331     if (status == GateMP_S_SUCCESS) {
332         /* local gate */
333         if (GETREMOTE(mask) == GateMP_RemoteProtect_NONE) {
334             if (creatorProcId != MultiProc_self()) {
335                 status = GateMP_E_FAIL;
336             }
337             else {
338                 *handle = (GateMP_Handle)arg;
339                 obj = (GateMP_Object *)(*handle);
340                 pthread_mutex_lock(&GateMP_module->mutex);
341                 obj->numOpens++;
342                 pthread_mutex_unlock(&GateMP_module->mutex);
343             }
344         }
345         else {
346             /* remote case */
347             switch (GETREMOTE(mask)) {
348                 case GateMP_RemoteProtect_SYSTEM:
349                 case GateMP_RemoteProtect_CUSTOM1:
350                 case GateMP_RemoteProtect_CUSTOM2:
351                     obj = GateMP_module->remoteSystemGates[arg];
352                     break;
354                 default:
355                     status = GateMP_E_FAIL;
356                     PRINTVERBOSE0("GateMP_open: unsupported remote protection \
357                         type")
358                     break;
359             }
361             /*  If the object is NULL, then it must have been created
362              *  on a remote processor or in another process on the
363              *  local processor. Need to create a local object. This is
364              *  accomplished by setting the openFlag to TRUE.
365              */
366             if (status == GateMP_S_SUCCESS) {
367                 if (obj == NULL) {
368                     /* create a GateMP object with the openFlag set to true */
369                     params.name = NULL;
370                     params.openFlag = TRUE;
371                     params.sharedAddr = NULL;
372                     params.resourceId = arg;
373                     params.localProtect = GETLOCAL(mask);
374                     params.remoteProtect = GETREMOTE(mask);
376                     obj = (GateMP_Object *)_GateMP_create(&params);
378                     if (obj == NULL) {
379                         status = GateMP_E_FAIL;
380                     }
381                 }
382                 else {
383                     pthread_mutex_lock(&GateMP_module->mutex);
384                     obj->numOpens++;
385                     pthread_mutex_unlock(&GateMP_module->mutex);
386                 }
387             }
389             /* Return the "opened" GateMP instance  */
390             *handle = (GateMP_Handle)obj;
391         }
392     }
394     return status;
397 GateMP_Handle GateMP_getDefaultRemote()
399     return (GateMP_module->defaultGate);
402 GateMP_LocalProtect GateMP_getLocalProtect(GateMP_Handle handle)
404     GateMP_Object *obj;
406     obj = (GateMP_Object *)handle;
407     return (obj->localProtect);
410 GateMP_RemoteProtect GateMP_getRemoteProtect(GateMP_Handle handle)
412     GateMP_Object *obj;
414     obj = (GateMP_Object *)handle;
415     return (obj->remoteProtect);
418 static Int GateMP_getNumResources(GateMP_RemoteProtect type)
420     Int status;
421     GateMPDrv_CmdArgs cmdArgs;
423     cmdArgs.args.getNumResources.type = type;
424     status = GateMPDrv_ioctl(CMD_GATEMP_GETNUMRES, &cmdArgs);
426     if (status < 0) {
427         PRINTVERBOSE1("GateMP_getNumResources: API (through IOCTL) failed, \
428             status=%d\n", status)
429         return -1;
430     }
432     return (cmdArgs.args.getNumResources.value);
435 static Int GateMP_getFreeResource(GateMP_RemoteProtect type)
437     Int status;
438     GateMPDrv_CmdArgs cmdArgs;
440     cmdArgs.args.getFreeResource.type = type;
441     status = GateMPDrv_ioctl(CMD_GATEMP_GETFREERES, &cmdArgs);
443     if (status < 0) {
444         PRINTVERBOSE1("GateMP_getFreeResource: API (through IOCTL) failed, \
445             status=%d\n", status)
446         return -1;
447     }
449     return (cmdArgs.args.getFreeResource.id);
452 static Int GateMP_releaseResource(UInt id, GateMP_RemoteProtect type)
454     Int status;
455     GateMPDrv_CmdArgs cmdArgs;
457     cmdArgs.args.releaseResource.type = type;
458     cmdArgs.args.releaseResource.id   = id;
459     status = GateMPDrv_ioctl(CMD_GATEMP_RELRES, &cmdArgs);
461     if (status < 0) {
462         PRINTVERBOSE1("GateMP_releaseResource: API (through IOCTL) failed, \
463             status=%d\n", status)
464     }
466     return (status);
469 Bool GateMP_isSetup(Void)
471     Int status;
472     GateMPDrv_CmdArgs cmdArgs;
474     cmdArgs.args.isSetup.result = FALSE;
475     status = GateMPDrv_ioctl(CMD_GATEMP_ISSETUP, &cmdArgs);
477     if (status < 0) {
478         PRINTVERBOSE1("GateMP_isSetup: API (through IOCTL) failed, \
479             status=%d\n", status)
480     }
482     assert(status == GateMP_S_SUCCESS);
484     return (cmdArgs.args.isSetup.result);
487 Int GateMP_close(GateMP_Handle *handle)
489     GateMP_Object * obj;
490     Int             status = GateMP_S_SUCCESS;
492     obj = (GateMP_Object *)(*handle);
494     pthread_mutex_lock(&GateMP_module->mutex);
496     /*  Cannot call with the numOpens equal to zero.  This is either
497      *  a created handle or been closed already.
498      */
499     if (obj->numOpens == 0) {
500         status = GateMP_E_INVALIDSTATE;
501     }
503     if (status == GateMP_S_SUCCESS) {
504         obj->numOpens--;
506         /*  If the count is zero and the gate is opened, then this
507          *  object was created in the open (i.e. the create happened
508          *  on a remote processor or another process).
509          */
510         if ((obj->numOpens == 0) && (obj->objType == Ipc_ObjType_OPENDYNAMIC)) {
511             GateMP_delete(handle);
512         }
513         else {
514             *handle = NULL;
515         }
516     }
518     pthread_mutex_unlock(&GateMP_module->mutex);
520     return(status);
523 Int GateMP_delete(GateMP_Handle *handlePtr)
525     Int               status = GateMP_S_SUCCESS;
527     if ((handlePtr == NULL) || (*handlePtr == NULL)) {
528         status =  GateMP_E_INVALIDARG;
529     }
530     else {
531         GateMP_Instance_finalize((GateMP_Object *)(*handlePtr), 0);
532         free(*handlePtr);
533         *handlePtr = NULL;
534     }
536     return status;
539 static Int GateMP_Instance_init(GateMP_Object *obj,
540     const _GateMP_Params *params)
542     GateMP_RemoteSystemProxy_Params     systemParams;
543     UInt32                              nsValue[4];
545     obj->resourceId = (UInt)-1;
547     /* TODO: create/open the local gate instance */
548     obj->localGate = NULL;
550     /* open GateMP instance */
551     if (params->openFlag == TRUE) {
552         /* all open work done here except for remote gateHandle */
553         obj->localProtect  = params->localProtect;
554         obj->remoteProtect = params->remoteProtect;
555         obj->nsKey         = 0;
556         obj->numOpens      = 1;
558         obj->objType       = Ipc_ObjType_OPENDYNAMIC;
559     }
561     /* create GateMP instance */
562     else {
563         obj->localProtect  = params->localProtect;
564         obj->remoteProtect = params->remoteProtect;
565         obj->nsKey         = 0;
566         obj->numOpens      = 0;
568         if (obj->remoteProtect == GateMP_RemoteProtect_NONE) {
569             /* TODO: create a local gate */
570             obj->gateHandle = obj->localGate;
572             /* create a local gate allocating from the local heap */
573             obj->objType = Ipc_ObjType_LOCAL;
574             obj->arg = (Bits32)obj;
575             obj->mask = SETMASK(obj->remoteProtect, obj->localProtect);
576             obj->creatorProcId = MultiProc_self();
578             if (params->name != NULL) {
579                 /*  nsv[0]       : creator process id
580                  *  nsv[1](31:16): creator procId
581                  *  nsv[1](15:0) : 0 = local gate, 1 = remote gate
582                  *  nsv[2]       : local gate object
583                  *  nsv[3]       : protection mask
584                  */
585                 nsValue[0] = getpid();
586                 nsValue[1] = MultiProc_self() << 16;
587                 nsValue[2] = obj->arg;
588                 nsValue[3] = obj->mask;
589                 obj->nsKey = NameServer_add(GateMP_module->nameServer,
590                         params->name, &nsValue, sizeof(nsValue));
591                 if (obj->nsKey == NULL) {
592                     PRINTVERBOSE0("GateMP_Instance_init: NameServer_add failed")
593                     return (GateMP_E_FAIL);
594                 }
595             }
597             /* nothing else to do for local gates */
598             return(0);
599         }
601         obj->objType = Ipc_ObjType_CREATEDYNAMIC;
602     }
604     /* proxy work for open and create done here */
605     switch (obj->remoteProtect) {
606         /* TODO: implement other types of remote protection */
607         case GateMP_RemoteProtect_SYSTEM:
608         case GateMP_RemoteProtect_CUSTOM1:
609         case GateMP_RemoteProtect_CUSTOM2:
610             if (obj->objType == Ipc_ObjType_OPENDYNAMIC) {
611                 /* resourceId set by open call */
612                 obj->resourceId = params->resourceId;
613             }
614             else {
615                 /* created instance */
616                 obj->resourceId = GateMP_getFreeResource(obj->remoteProtect);
617                 if (obj->resourceId == -1) {
618                     return (GateMP_E_RESOURCE);
619                 }
620             }
622             /* create the proxy object */
623             GateMP_RemoteSystemProxy_Params_init(&systemParams);
624             systemParams.resourceId = obj->resourceId;
625             systemParams.openFlag = (obj->objType == Ipc_ObjType_OPENDYNAMIC);
626             //systemParams.sharedAddr = obj->proxyAttrs;
628             /*
629              * TODO: Currently passing in localProtect instead of localGate,
630              * since existing GateHWSpinlock.h defines it this way
631              */
632             obj->gateHandle = (IGateProvider_Handle)
633                 GateMP_RemoteSystemProxy_create(obj->localProtect,
634                     &systemParams);
636             if (obj->gateHandle == NULL) {
637                 PRINTVERBOSE0("GateMP_Instance_init: failed to create proxy\n");
638                 return(GateMP_E_FAIL);
639             }
641             /* store the object handle in the gate array */
642             GateMP_module->remoteSystemGates[obj->resourceId] = obj;
643             break;
645         default:
646             break;
647     }
649     /* add name/attrs to NameServer table */
650     if (obj->objType != Ipc_ObjType_OPENDYNAMIC) {
651         obj->arg = obj->resourceId;
652         obj->mask = SETMASK(obj->remoteProtect, obj->localProtect);
654         if (params->name != NULL) {
655             /*  nsv[0]       : creator pid
656              *  nsv[1](31:16): creator procId
657              *  nsv[1](15:0) : 0 = local gate, 1 = remote gate
658              *  nsv[2]       : resource id
659              *  nsv[3]       : protection mask
660              */
661             nsValue[0] = getpid();
662             nsValue[1] = MultiProc_self() << 16 | 1;
663             nsValue[2] = obj->resourceId;
664             nsValue[3] = obj->mask;
665             obj->nsKey = NameServer_add(GateMP_module->nameServer,
666                     params->name, &nsValue, sizeof(nsValue));
668             if (obj->nsKey == NULL) {
669                 PRINTVERBOSE0("GateMP_Instance_init: NameServer_add failed")
670                 return (GateMP_E_FAIL);
671             }
672         }
673     }
675     return (GateMP_S_SUCCESS);
678 static Void GateMP_Instance_finalize(GateMP_Object *obj, Int status)
680     GateMP_Object ** remoteGates = NULL;
682     /* remove from NameServer */
683     if (obj->nsKey != 0) {
684         NameServer_removeEntry(GateMP_module->nameServer, obj->nsKey);
685         obj->nsKey = 0;
686     }
688     /* delete the remote gate */
689     switch (obj->remoteProtect) {
691         case GateMP_RemoteProtect_SYSTEM:
692         case GateMP_RemoteProtect_CUSTOM1:
693         case GateMP_RemoteProtect_CUSTOM2:
694             if (obj->gateHandle != NULL) {
695                 GateMP_RemoteSystemProxy_delete(
696                         (GateMP_RemoteSystemProxy_Handle *)&obj->gateHandle);
697             }
698             remoteGates = GateMP_module->remoteSystemGates;
699             break;
701         case GateMP_RemoteProtect_NONE:
702             /*  nothing else to finalize */
703             return;
705         default:
706             /* Nothing to do */
707             break;
708     }
710     /* TODO: close/delete local gate */
712     /* clear the handle array entry in local memory */
713     if (obj->resourceId != (UInt)-1) {
714         remoteGates[obj->resourceId] = NULL;
715     }
717     if ((obj->objType != Ipc_ObjType_OPENDYNAMIC)
718         && (obj->resourceId != (UInt)-1)) {
719         GateMP_releaseResource(obj->resourceId, obj->remoteProtect);
720     }
724 IArg GateMP_enter(GateMP_Handle handle)
726     GateMP_Object * obj;
727     IArg            key;
729     obj = (GateMP_Object *)handle;
730     key = IGateProvider_enter(obj->gateHandle);
732     return(key);
735 Void GateMP_leave(GateMP_Handle handle, IArg key)
737     GateMP_Object *obj;
739     obj = (GateMP_Object *)handle;
740     IGateProvider_leave(obj->gateHandle, key);