Linux/Android: Refactor MessageQ_create to Register Later with NameServer
[ipc/ipcdev.git] / linux / src / api / Ipc.c
1 /*
2  * Copyright (c) 2012-2016 Texas Instruments Incorporated - http://www.ti.com
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  *  @file       Ipc.c
34  *
35  *  @brief      Starts and stops user side Ipc
36  *              All setup/destroy APIs on user side will be call from this
37  *              module.
38  */
40 /* standard headers */
41 #include <pthread.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <signal.h>
45 #include <string.h>
47 /* package headers */
48 #include <ti/ipc/Std.h>
49 #include <ti/ipc/Ipc.h>
50 #include <ti/ipc/NameServer.h>
51 #include <ti/ipc/heaps/HeapStd.h>
52 #include <ti/ipc/interfaces/IHeap.h>
54 /* User side headers */
55 #include <ladclient.h>
57 /* IPC startup/shutdown stuff: */
58 #include <ti/ipc/MultiProc.h>
59 #include <GateHWSpinlock.h>
60 #include <_GateMP.h>
61 #include <_Ipc.h>
62 #include <_MultiProc.h>
63 #include <_MessageQ.h>
64 #include <_NameServer.h>
66 /* module definition */
67 typedef struct {
68     Int                         refCount;
69     pthread_mutex_t             gate;
70     Ipc_TransportFactoryFxns   *transportFactory;
71     Ipc_Config                  config;
72     Int                         attached[MultiProc_MAXPROCESSORS];
73 } Ipc_Module;
75 /* hack: rpmsgproto driver work around */
76 Void MessageQ_bind(UInt16 procId);
77 Void MessageQ_unbind(UInt16 procId);
80 /* =============================================================================
81  *  Globals
82  * =============================================================================
83  */
84 static Ipc_Module Ipc_module = {
85     .refCount           = 0,
86 #if defined(IPC_BUILDOS_ANDROID) && (PLATFORM_SDK_VERSION < 23)
87     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
88 #else
89 // only _NP (non-portable) type available in CG tools which we're using
90     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
91 #endif
92     .transportFactory   = NULL,
93     .config.procSync    = Ipc_ProcSync_NONE,
94     .config.idHeapStd   = 0
95 };
97 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
98 static LAD_ClientHandle ladHandle;
100 /* traces in this file are controlled via _Ipc_verbose */
101 Bool _Ipc_verbose = FALSE;
102 #define verbose _Ipc_verbose
104 /** ============================================================================
105  *  Functions
106  *  ============================================================================
107  */
108 static void cleanup(int arg);
111 /*
112  *  ======== Ipc_start ========
113  */
114 Int Ipc_start(Void)
116     MessageQ_Config         msgqCfg;
117     MultiProc_Config        mpCfg;
118 #if defined(GATEMP_SUPPORT)
119     GateHWSpinlock_Config   gateHWCfg;
120 #endif
121     Int         status;
122     LAD_Status  ladStatus;
123     UInt16      procId;
124     UInt16      clusterSize;
125     UInt16      baseId;
126     UInt16      clusterId;
127     Int         i;
128     HeapStd_Handle heap;
129     IHeap_Handle iheap;
131     /* function must be serialized */
132     pthread_mutex_lock(&Ipc_module.gate);
134     /* ensure only first thread performs startup procedure */
135     if (Ipc_module.refCount >= 1) {
136         Ipc_module.refCount++;
137         status = Ipc_S_ALREADYSETUP;
138         goto exit;
139     }
141     /* make sure transport factory has been configured */
142     if (Ipc_module.transportFactory == NULL) {
143         status = Ipc_E_INVALIDSTATE;
144         goto exit;
145     }
147     /* initialize module object */
148     for (i = 0; i < MultiProc_MAXPROCESSORS; i++) {
149         Ipc_module.attached[i] = 0;
150     }
152     /* Catch ctrl-C, and cleanup: */
153     (void) signal(SIGINT, cleanup);
155     if (getenv("IPC_DEBUG") != NULL) {
156         /* turn on tracing */
157         if (getenv("IPC_DEBUG")[0] == '1') {
158             /* level 1 enables typical user API tracing */
159             _MessageQ_verbose = TRUE;
160             _MultiProc_verbose = TRUE;
161             _NameServer_verbose = TRUE;
162 #if defined(GATEMP_SUPPORT)
163             _GateMP_verbose = TRUE;
165             _GateHWSpinlock_verbose = TRUE;
166 #endif
167         }
168         else if ((getenv("IPC_DEBUG")[0] == '2') ||
169                 (getenv("IPC_DEBUG")[0] == '3')) {
170             /* levels 2 and 3 add socket and LAD client tracing */
171             _MessageQ_verbose = TRUE;
172             _MultiProc_verbose = TRUE;
173             _NameServer_verbose = TRUE;
175 #if defined(GATEMP_SUPPORT)
176             _GateMP_verbose = TRUE;
178             _GateHWSpinlock_verbose = TRUE;
179 #endif
181             /* internals - should be declared in respective _*.h files */
182             extern Bool _SocketFxns_verbose;
183             extern Bool _LAD_Client_verbose;
185             _SocketFxns_verbose = TRUE;
186             _LAD_Client_verbose = TRUE;
187         }
188     }
190     /* establish a communication link to the LAD daemon */
191     ladStatus = LAD_connect(&ladHandle);
193     if (ladStatus != LAD_SUCCESS) {
194         fprintf(stderr, "Ipc_start: LAD_connect() failed: %d\n", ladStatus);
195         status = Ipc_E_FAIL;
196         goto exit;
197     }
199     /* get global configuration from LAD */
200     Ipc_getConfig(&Ipc_module.config);
202     /* get global configuration from LAD */
203     MultiProc_getConfig(&mpCfg);
204     _MultiProc_initCfg(&mpCfg);
206     /* setup name server thread in LAD daemon */
207     status = NameServer_setup();
209     if (status < 0) {
210         fprintf(stderr, "Ipc_start: NameServer_setup() failed: %d\n", status);
211         status = Ipc_E_FAIL;
212         goto exit;
213     }
215     /* get global configuration from LAD */
216     MessageQ_getConfig(&msgqCfg);
217     MessageQ_setup(&msgqCfg);
219     /* register the standard heap */
220     heap = HeapStd_handle();
221     iheap = HeapStd_upCast(heap);
222     MessageQ_registerHeap((Ptr)iheap, Ipc_module.config.idHeapStd);
224     /* invoke the transport factory create method */
225     status = Ipc_module.transportFactory->createFxn();
227     if (status < 0) {
228         goto exit;
229     }
231     /* if using ProcSync_ALL, then attach to all processors in the cluster */
232     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
233         clusterSize = MultiProc_getNumProcsInCluster();
234         baseId = MultiProc_getBaseIdOfCluster();
236         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
237             procId = baseId + clusterId;
239             if (procId == MultiProc_self()) {
240                 continue;
241             }
243             status = Ipc_attach(procId);
245             /*  For backward compatibility, it is okay for attach to fail.
246              *  We don't expect all remote processors to be running.
247              */
248             if (status < 0) {
249                 status = 0;
250                 /* do nothing */
251             }
252         }
253     }
255     /* Start GateMP only if device has support */
256 #if defined(GATEMP_SUPPORT)
257     if (GateMP_isSetup()) {
258         /*
259          * Get HWSpinlock base address and size from LAD and
260          * initialize the local config structure.
261          */
262         GateHWSpinlock_getConfig(&gateHWCfg);
263         _GateHWSpinlock_cfgParams = gateHWCfg;
265         status = GateHWSpinlock_start();
266         if (status < 0) {
267             fprintf(stderr, "Ipc_start: GateHWSpinlock_start failed: %d\n",
268                     status);
269             status = Ipc_E_FAIL;
270             goto exit;
271         }
273         status = GateMP_start();
274         if (status < 0) {
275             if (status == GateMP_E_NOTFOUND) {
276                 /* Ignore if Gate not found */
277                 PRINTVERBOSE1(
278                     "Ipc_start: GateMP_start: gate not found, ignored %d\n",
279                     status);
280                 status = 0;
281             } else {
282                 fprintf(stderr, "Ipc_start: GateMP_start failed: %d\n", status);
283                 status = Ipc_E_FAIL;
284                 GateHWSpinlock_stop();
285                 goto exit;
286             }
287         }
288     }
289 #endif
291     /* getting here means we have successfully started */
292     Ipc_module.refCount++;
294 exit:
295     pthread_mutex_unlock(&Ipc_module.gate);
297     return (status);
300 /*
301  *  ======== Ipc_stop ========
302  */
303 Int Ipc_stop(Void)
305     Int32       status = Ipc_S_SUCCESS;
306     LAD_Status  ladStatus;
307     UInt16      procId;
308     UInt16      clusterSize;
309     UInt16      baseId;
310     UInt16      clusterId;
312     /* function must be serialized */
313     pthread_mutex_lock(&Ipc_module.gate);
315     if (Ipc_module.refCount == 0) {
316         status = Ipc_E_INVALIDSTATE;
317         goto exit;
318     }
320     /* ensure only last thread performs stop procedure */
321     if (--Ipc_module.refCount > 0) {
322         goto exit;
323     }
325     /* if using ProcSync_ALL, then detach from all processors in the cluster */
326     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
327         clusterSize = MultiProc_getNumProcsInCluster();
328         baseId = MultiProc_getBaseIdOfCluster();
330         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
331             procId = baseId + clusterId;
333             if (MultiProc_self() == procId) {
334                 continue;
335             }
337             /*  For backward compatibility, we might not be attached to
338              *  all cluster members. Skip unattached processors.
339              */
340             if (!Ipc_isAttached(procId)) {
341                 continue;
342             }
344             status = Ipc_detach(procId);
346             if (status < 0) {
347                 /* Should we keep going or stop? */
348             }
349         }
350     }
352     Ipc_module.transportFactory->deleteFxn();
354     /* unregister the standard heap */
355     MessageQ_unregisterHeap(Ipc_module.config.idHeapStd);
357     status = MessageQ_destroy();
358     if (status < 0) {
359         fprintf(stderr, "Ipc_stop: MessageQ_destroy() failed: %d\n", status);
360         status = Ipc_E_FAIL;
361         goto exit;
362     }
364     status = NameServer_destroy();
365     if (status < 0) {
366         fprintf(stderr, "Ipc_stop: NameServer_destroy() failed: %d\n", status);
367         status = Ipc_E_FAIL;
368         goto exit;
369     }
371     ladStatus = LAD_disconnect(ladHandle);
372     if (ladStatus != LAD_SUCCESS) {
373         fprintf(stderr, "LAD_disconnect() failed: %d\n", ladStatus);
374         status = Ipc_E_FAIL;
375         goto exit;
376     }
378 exit:
379     pthread_mutex_unlock(&Ipc_module.gate);
381     return (status);
384 /*
385  *  ======== Ipc_transportConfig ========
386  */
387 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
389     Int status = Ipc_S_SUCCESS;
391     pthread_mutex_lock(&Ipc_module.gate);
393     /*  Only the first caller can actually set the transport factory.
394      *  Subsequent callers (e.g. multi-threaded application) must be
395      *  using the same factory. Otherwise, it is an error.
396      */
397     if (Ipc_module.transportFactory == NULL) {
398         Ipc_module.transportFactory = factory;
399     }
400     else if (Ipc_module.transportFactory != factory) {
401         status = Ipc_E_INVALIDARG;
402         goto exit;
403     }
405 exit:
406     pthread_mutex_unlock(&Ipc_module.gate);
408     return (status);
411 static void cleanup(int arg)
413     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
414     Ipc_stop();
415     exit(0);
418 /*
419  *  ======== Ipc_attach ========
420  */
421 Int Ipc_attach(UInt16 procId)
423     Int status = Ipc_S_SUCCESS;
424     UInt16 clusterId;
425 #if defined(GATEMP_SUPPORT)
426     Int ret;
427 #endif
429     /* cannot attach to yourself */
430     if (MultiProc_self() == procId) {
431         status =  Ipc_E_INVALIDARG;
432         goto done;
433     }
435     /* processor must be a member of the cluster */
436     clusterId = procId - MultiProc_getBaseIdOfCluster();
438     if (clusterId >= MultiProc_getNumProcsInCluster()) {
439         status =  Ipc_E_INVALIDARG;
440         goto done;
441     }
443     /* function must be serialized */
444     pthread_mutex_lock(&Ipc_module.gate);
446     /* if already attached, just increment reference count */
447     if (Ipc_module.attached[clusterId] > 0) {
448         Ipc_module.attached[clusterId]++;
449         goto done;
450     }
452     /* establish name server connection to remote processor */
453     status = NameServer_attach(procId);
455     if (status < 0) {
456         status = Ipc_E_FAIL;
457         goto done;
458     }
460     /* attach the transport to remote processor */
461     status = Ipc_module.transportFactory->attachFxn(procId);
463     if (status < 0) {
464         NameServer_detach(procId);
465         status = Ipc_E_FAIL;
466         goto done;
467     }
469     /* hack: bind all existing message queues to remote processor */
470     MessageQ_bind(procId);
472 #if defined(GATEMP_SUPPORT)
473     if (GateMP_isSetup()) {
474         /* establish GateMP connection to remote processor */
475         ret = GateMP_attach(procId);
477         if (ret < 0) {
478             PRINTVERBOSE1("Ipc_attach: failed to GateMP_attach to procId %d\n",
479                           procId);
480         }
481     }
482 #endif
484     /* getting here means we have successfully attached */
485     Ipc_module.attached[clusterId]++;
487 done:
488     pthread_mutex_unlock(&Ipc_module.gate);
490     return (status);
493 /*
494  *  ======== Ipc_detach ========
495  */
496 Int Ipc_detach(UInt16 procId)
498     Int status = Ipc_S_SUCCESS;
499     UInt16 clusterId;
500 #if defined(GATEMP_SUPPORT)
501     Int ret;
502 #endif
504     /* cannot detach from yourself */
505     if (MultiProc_self() == procId) {
506         status =  Ipc_E_INVALIDARG;
507         goto done;
508     }
510     /* processor must be a member of the cluster */
511     clusterId = procId - MultiProc_getBaseIdOfCluster();
513     if (clusterId >= MultiProc_getNumProcsInCluster()) {
514         status =  Ipc_E_INVALIDARG;
515         goto done;
516     }
518     /* function must be serialized */
519     pthread_mutex_lock(&Ipc_module.gate);
521     if (Ipc_module.attached[clusterId] == 0) {
522         status = Ipc_E_INVALIDSTATE;
523         goto done;
524     }
526     if (--Ipc_module.attached[clusterId] > 0) {
527         goto done;
528     }
530 #if defined(GATEMP_SUPPORT)
531     if (GateMP_isSetup()) {
532         /* establish GateMP connection to remote processor */
533         ret = GateMP_detach(procId);
535         if (ret < 0) {
536             PRINTVERBOSE1("Ipc_detach: failed to GateMP_detach from procId %d\n",
537                           procId);
538         }
539     }
540 #endif
542     /* hack: unbind all existing message queues from remote processor */
543     MessageQ_unbind(procId);
545     /* detach transport from remote processor */
546     status = Ipc_module.transportFactory->detachFxn(procId);
548     if (status < 0) {
549         status = Ipc_E_FAIL;
550         /* report the error */
551         goto done;
552     }
554     /* remove connection to remote processor */
555     status = NameServer_detach(procId);
557     if (status < 0) {
558         status = Ipc_E_FAIL;
559         /* report the error */
560         goto done;
561     }
563 done:
564     if (status < 0) {
565         /* report error */
566         fprintf(stderr, "Ipc_detach: Error %d, procId %d\n", status, procId);
567     }
568     pthread_mutex_unlock(&Ipc_module.gate);
570     return (status);
573 /*
574  *  ======== Ipc_isAttached ========
575  */
576 Bool Ipc_isAttached(UInt16 procId)
578     Bool attached;
579     UInt16 clusterId;
581     /* cannot be attached to yourself */
582     if (MultiProc_self() == procId) {
583         return (FALSE);
584     }
586     /* processor must be a member of the cluster */
587     clusterId = procId - MultiProc_getBaseIdOfCluster();
589     if (clusterId >= MultiProc_getNumProcsInCluster()) {
590         return (FALSE);
591     }
593     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
594     return (attached);
597 /*
598  *  ======== Ipc_getConfig ========
599  *  Get the run-time configuration for the Ipc module
600  *
601  *  This is an IPC internal function. It is used to acquire
602  *  the global Ipc module configuration values from LAD.
603  */
604 Void Ipc_getConfig(Ipc_Config *cfg)
606     Int status;
607     LAD_ClientHandle handle;
608     struct LAD_CommandObj cmd;
609     union LAD_ResponseObj rsp;
611     handle = LAD_findHandle();
612     if (handle == LAD_MAXNUMCLIENTS) {
613         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
614         return;
615     }
617     cmd.cmd = LAD_IPC_GETCONFIG;
618     cmd.clientId = handle;
620     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
621         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
622                 "status=%d\n", status);
623         return;
624     }
626     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
627         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
628         return;
629     }
631     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
632     return;