SDOCM114476 Ipc_start is not thread safe (Linux)
[ipc/ipcdev.git] / linux / src / api / Ipc.c
1 /*
2  * Copyright (c) 2012-2015 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  */
33 /*!
34  *  @file       Ipc.c
35  *
36  *  @brief      Starts and stops user side Ipc
37  *              All setup/destroy APIs on user side will be call from this
38  *              module.
39  */
41 /* standard headers */
42 #include <pthread.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <signal.h>
47 /* package headers */
48 #include <ti/ipc/Std.h>
49 #include <ti/ipc/Ipc.h>
50 #include <ti/ipc/NameServer.h>
51 #include <IMessageQTransport.h>
52 #include <TransportRpmsg.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 <_MultiProc.h>
62 #include <_MessageQ.h>
63 #include <_NameServer.h>
65 /* module definition */
66 typedef struct {
67     Int                 refCount;
68     pthread_mutex_t     gate;
69 } Ipc_Module;
72 /* =============================================================================
73  *  Globals
74  * =============================================================================
75  */
76 static Ipc_Module Ipc_module = {
77     .refCount   = 0,
78     .gate       = PTHREAD_MUTEX_INITIALIZER
79 };
81 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
82 static LAD_ClientHandle ladHandle;
85 /** ============================================================================
86  *  Functions
87  *  ============================================================================
88  */
89 static void cleanup(int arg);
92 /*
93  *  ======== Ipc_start ========
94  */
95 Int Ipc_start(Void)
96 {
97     TransportRpmsg_Handle  transport;
98     TransportRpmsg_Params  params;
99     IMessageQTransport_Handle iMsgQTrans;
100     MessageQ_Config        msgqCfg;
101     MultiProc_Config       mpCfg;
102 #if defined(GATEMP_SUPPORT)
103     GateHWSpinlock_Config  gateHWCfg;
104 #endif
105     Int                    attachStatus;
106     Int32                  status;
107     LAD_Status             ladStatus;
108     UInt16                 rprocId;
109     Int32                  attachedAny;
111     /* function must be serialized */
112     pthread_mutex_lock(&Ipc_module.gate);
114     /* ensure only first thread performs startup procedure */
115     if (++Ipc_module.refCount > 1) {
116         status = Ipc_S_ALREADYSETUP;
117         goto exit;
118     }
120     /* Catch ctrl-C, and cleanup: */
121     (void) signal(SIGINT, cleanup);
123     if (getenv("IPC_DEBUG") != NULL) {
124         /* turn on tracing */
125         if (getenv("IPC_DEBUG")[0] == '1') {
126             /* level 1 enables typical user API tracing */
127             _MessageQ_verbose = TRUE;
128             _MultiProc_verbose = TRUE;
129             _NameServer_verbose = TRUE;
130 #if defined(GATEMP_SUPPORT)
131             _GateMP_verbose = TRUE;
133             _GateHWSpinlock_verbose = TRUE;
134 #endif
135         }
136         else if ((getenv("IPC_DEBUG")[0] == '2') ||
137                 (getenv("IPC_DEBUG")[0] == '3')) {
138             /* levels 2 and 3 add socket and LAD client tracing */
139             _MessageQ_verbose = TRUE;
140             _MultiProc_verbose = TRUE;
141             _NameServer_verbose = TRUE;
143 #if defined(GATEMP_SUPPORT)
144             _GateMP_verbose = TRUE;
146             _GateHWSpinlock_verbose = TRUE;
147 #endif
149             /* internals - should be declared in respective _*.h files */
150             extern Bool _SocketFxns_verbose;
151             extern Bool _LAD_Client_verbose;
153             _SocketFxns_verbose = TRUE;
154             _LAD_Client_verbose = TRUE;
155         }
156     }
158     ladStatus = LAD_connect(&ladHandle);
159     if (ladStatus != LAD_SUCCESS) {
160         printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
161         status = Ipc_E_FAIL;
162         goto exit;
163     }
165     /*
166      * Get MultiProc configuration from LAD and initialize local MultiProc
167      * config structure.
168      */
169     MultiProc_getConfig(&mpCfg);
170     _MultiProc_initCfg(&mpCfg);
172     status = NameServer_setup();
173     if (status >= 0) {
174         MessageQ_getConfig(&msgqCfg);
175         MessageQ_setup(&msgqCfg);
177         /*
178          * Attach to all remote processors.  We need to attach to
179          * at least one, so tolerate MessageQ_E_RESOURCE failures for
180          * now.
181          */
182         status = Ipc_S_SUCCESS;
183         attachedAny = FALSE;
185         for (rprocId = 0; rprocId < MultiProc_getNumProcessors(); rprocId++) {
186             if (0 == rprocId) {
187                 /* Skip host, which should always be 0th entry. */
188                 continue;
189             }
191             params.rprocId = rprocId;
192             transport = TransportRpmsg_create(&params, &attachStatus);
194             if (transport) {
195                 iMsgQTrans = TransportRpmsg_upCast(transport);
196                 MessageQ_registerTransport(iMsgQTrans, rprocId, 0);
198                 attachedAny = TRUE;
199             }
200             else {
201                 if (attachStatus == MessageQ_E_RESOURCE) {
202                     continue;
203                 }
205                 printf("Ipc_start: failed to attach to %d: %d\n",
206                        rprocId, attachStatus);
208                 status = Ipc_E_FAIL;
210                 break;
211             }
212         }
213         if (!attachedAny) {
214             status = Ipc_E_FAIL;
215         }
216     }
217     else {
218         printf("Ipc_start: NameServer_setup() failed: %d\n", status);
219         status = Ipc_E_FAIL;
220     }
222     /* Start GateMP only if device has support */
223 #if defined(GATEMP_SUPPORT)
224     if (GateMP_isSetup()) {
225         /*
226          * Get HWSpinlock base address and size from LAD and
227          * initialize the local config structure.
228          */
229         GateHWSpinlock_getConfig(&gateHWCfg);
230         _GateHWSpinlock_cfgParams = gateHWCfg;
232         status = GateHWSpinlock_start();
233         if (status < 0) {
234             printf("Ipc_start: GateHWSpinlock_start failed: %d\n",
235                 status);
236             status = Ipc_E_FAIL;
237             goto gatehwspinlockstart_fail;
238         }
239         else {
240             status = GateMP_start();
241             if (status < 0) {
242                 printf("Ipc_start: GateMP_start failed: %d\n",
243                 status);
244                 status = Ipc_E_FAIL;
245                 goto gatempstart_fail;
246             }
247         }
248     }
249 #endif
250     /* Success */
251     goto exit;
252 #if defined(GATEMP_SUPPORT)
253 gatempstart_fail:
254     GateHWSpinlock_stop();
255 gatehwspinlockstart_fail:
256 #if 0
257     for (rprocId = rprocId - 1; (rprocId > 0) && (status >= 0); rprocId--) {
258         MessageQ_detach(rprocId);
259     }
260 #endif
261 #endif
263 exit:
264     /* if error, must decrement reference count */
265     if (status < 0) {
266         Ipc_module.refCount--;
267     }
269     pthread_mutex_unlock(&Ipc_module.gate);
271     return (status);
274 /*
275  *  ======== Ipc_stop ========
276  */
277 Int Ipc_stop(Void)
279     Int32             status = Ipc_S_SUCCESS;
280     LAD_Status        ladStatus;
281     UInt16            rprocId;
283     /* function must be serialized */
284     pthread_mutex_lock(&Ipc_module.gate);
286     /* ensure only last thread performs stop procedure */
287     if (--Ipc_module.refCount > 0) {
288         goto exit;
289     }
291     /* Now detach from all remote processors, assuming they are up. */
292     for (rprocId = 0;
293          (rprocId < MultiProc_getNumProcessors()) && (status >= 0);
294          rprocId++) {
295         if (0 == rprocId) {
296           /* Skip host, which should always be 0th entry. */
297           continue;
298         }
299 #if 0
300         status = MessageQ_detach(rprocId);
301         if (status < 0) {
302             printf("Ipc_stop: MessageQ_detach(%d) failed: %d\n",
303                 rprocId, status);
304             status = Ipc_E_FAIL;
305             goto exit;
306        }
307 #endif
308     }
310     status = MessageQ_destroy();
311     if (status < 0) {
312         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
313         status = Ipc_E_FAIL;
314         goto exit;
315     }
317     status = NameServer_destroy();
318     if (status < 0) {
319         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
320         status = Ipc_E_FAIL;
321         goto exit;
322     }
324     ladStatus = LAD_disconnect(ladHandle);
325     if (ladStatus != LAD_SUCCESS) {
326         printf("LAD_disconnect() failed: %d\n", ladStatus);
327         status = Ipc_E_FAIL;
328         goto exit;
329     }
331 exit:
332     pthread_mutex_unlock(&Ipc_module.gate);
334     return (status);
337 static void cleanup(int arg)
339     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
340     Ipc_stop();
341     exit(0);