Improve MessageQ recovery on DRA7xx QNX
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / ti-ipc / ti-ipc.c
1 /*
2  *  @file       ti-ipc.c
3  *
4  *  @brief      fileops handler for ti-ipc component.
5  *
6  *
7  *  @ver
8  *
9  *  ============================================================================
10  *
11  *  Copyright (c) 2013-2015, Texas Instruments Incorporated
12  *
13  *  Redistribution and use in source and binary forms, with or without
14  *  modification, are permitted provided that the following conditions
15  *  are met:
16  *
17  *  *  Redistributions of source code must retain the above copyright
18  *     notice, this list of conditions and the following disclaimer.
19  *
20  *  *  Redistributions in binary form must reproduce the above copyright
21  *     notice, this list of conditions and the following disclaimer in the
22  *     documentation and/or other materials provided with the distribution.
23  *
24  *  *  Neither the name of Texas Instruments Incorporated nor the names of
25  *     its contributors may be used to endorse or promote products derived
26  *     from this software without specific prior written permission.
27  *
28  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35  *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37  *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *  Contact information for paper mail:
40  *  Texas Instruments
41  *  Post Office Box 655303
42  *  Dallas, Texas 75265
43  *  Contact information:
44  *  http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
45  *  DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
46  *  ============================================================================
47  *
48  */
51 /* Standard headers */
52 #include <ti/syslink/Std.h>
54 /* OSAL & Utils headers */
55 #include <ti/syslink/utils/List.h>
56 #include <ti/syslink/utils/String.h>
57 #include <ti/syslink/utils/Trace.h>
58 #include <ti/syslink/utils/Memory.h>
59 #include <ti/syslink/utils/IGateProvider.h>
60 #include <ti/syslink/utils/GateSpinlock.h>
61 #include <_MultiProc.h>
63 /*QNX specific header include */
64 #include <errno.h>
65 #include <unistd.h>
66 #include <sys/iofunc.h>
67 #include <sys/dispatch.h>
68 #include <sys/netmgr.h>
69 #include <devctl.h>
71 /* Module headers */
72 #include <ti/ipc/ti_ipc.h>
73 #include <ti/ipc/MessageQCopy.h>
74 #include <_MessageQCopy.h>
75 #include <_MessageQCopyDefs.h>
76 #include "OsalSemaphore.h"
77 #include "std_qnx.h"
78 #include <pthread.h>
80 #include "ti-ipc.h"
82 #define PRIORITY_REALTIME_LOW 29
84 /* Rate (in us) at which to check if setup is completed during recovery */
85 #define RECOVERY_POLL_RATE    100000
87 #define TIIPC_DEVICE_NAME "/dev/tiipc"
90 /* structure to hold rpmsg-rpc device information */
91 typedef struct named_device {
92     iofunc_mount_t      mattr;
93     iofunc_attr_t       cattr;
94     int                 resmgr_id;
95     iofunc_funcs_t      mfuncs;
96     resmgr_connect_funcs_t  cfuncs;
97     resmgr_io_funcs_t   iofuncs;
98 } named_device_t;
100 /* ti-ipc device structure */
101 typedef struct ti_ipc_dev {
102     dispatch_t       * dpp;
103     thread_pool_t    * tpool;
104     named_device_t     ti_ipc;
105 } ti_ipc_dev_t;
107 /*!
108  *  @brief  ti ipc instance object
109  */
110 typedef struct ti_ipc_object_tag {
111     MessageQCopy_Handle     mq;
112     UInt32                  addr;
113     UInt32                  remoteAddr;
114     UInt16                  procId;
115     pid_t                   pid;
116     bool                    isValid;
117     iofunc_notify_t         notify[3];
118 } ti_ipc_object;
120 /*!
121  *  @brief  Keeps the information related to Event.
122  */
123 typedef struct ipc_EventState_tag {
124     List_Handle            bufList;
125     /*!< Head of received event list. */
126     ti_ipc_object         *ipc;
127     /*!< ipc instacne. */
128     UInt32                 refCount;
129     /*!< Reference count, used when multiple Notify_registerEvent are called
130          from same process space (multi threads/processes). */
131     WaitingReaders_t *     head;
132     /*!< Waiting readers head. */
133     WaitingReaders_t *     tail;
134     /*!< Waiting readers tail. */
135 } ipc_EventState;
137 /*!
138  *  @brief  Per-connection information
139  */
140 typedef struct ti_ipc_ocb {
141     iofunc_ocb_t      hdr;
142     pid_t             pid;
143     ti_ipc_object *   ipc;
144 } ti_ipc_ocb_t;
146 /*!
147  *  @brief  ti_ipc Module state object
148  */
149 typedef struct ti_ipc_ModuleObject_tag {
150     Bool                 isSetup;
151     /*!< Indicates whether the module has been already setup */
152     IGateProvider_Handle gateHandle;
153     /*!< Handle of gate to be used for local thread safety */
154     ipc_EventState eventState [MAX_PROCESSES];
155     /*!< List for all user processes registered. */
156     pthread_t nt;
157     /*!< notifier thread */
158     pthread_mutex_t lock;
159     /*!< protection between notifier and event */
160     pthread_cond_t  cond;
161     /*!< protection between notifier and event */
162     MsgList_t *head;
163     /*!< list head */
164     MsgList_t *tail;
165     /*!< list tail */
166     int run;
167     /*!< notifier thread must keep running */
168     ti_ipc_dev_t *dev;
169     /*!< device for this module */
170 } ti_ipc_ModuleObject;
172 /*!
173  *  @brief  Structure of Event Packet read from notify kernel-side.
174  */
175 typedef struct ipc_EventPacket_tag {
176     List_Elem          element;
177     /*!< List element header */
178     UInt32             pid;
179     /* Processor identifier */
180     ti_ipc_object *    obj;
181     /*!< Pointer to the channel associated with this callback */
182     UInt32             len;
183     /*!< Length of the data associated with event. */
184     UInt8              data[MessageQCopy_BUFSIZE];
185     /*!< Data associated with event. */
186     UInt32             src;
187     /*!< Src endpoint associated with event. */
188     struct ipc_EventPacket * next;
189     struct ipc_EventPacket * prev;
190 } ipc_EventPacket ;
193 /** ============================================================================
194  *  Globals
195  *  ============================================================================
196  */
197 /*!
198  *  @var    ti_ipc_state
199  *
200  *  @brief  ti-ipc state object variable
201  */
202 static ti_ipc_ModuleObject ti_ipc_state =
204     .gateHandle = NULL,
205     .isSetup = FALSE,
206     .nt = 0,
207     .lock = PTHREAD_MUTEX_INITIALIZER,
208     .cond = PTHREAD_COND_INITIALIZER,
209     .head = NULL,
210     .tail = NULL,
211     .run  = 0,
212     .dev  = NULL
213 };
215 static MsgList_t *nl_cache;
216 static int num_nl = 0;
217 static WaitingReaders_t *wr_cache;
218 static int num_wr = 0;
220 extern dispatch_t * ipc_dpp;
223 /** ============================================================================
224  *  Internal functions
225  *  ============================================================================
226  */
228 /*
229  * Instead of constantly allocating and freeing the uBuf structures
230  * we just cache a few of them, and recycle them instead.
231  * The cache count is set with CACHE_NUM in rpmsg-omxdrv.h.
232  */
233 static ipc_EventPacket *uBuf_cache;
234 static int num_uBuf = 0;
236 static void flush_uBuf()
238     ipc_EventPacket *uBuf = NULL;
240     while(uBuf_cache) {
241         num_uBuf--;
242         uBuf = uBuf_cache;
243         uBuf_cache = (ipc_EventPacket *)uBuf_cache->next;
244         Memory_free(NULL, uBuf, sizeof(*uBuf));
245     }
248 static ipc_EventPacket *get_uBuf()
250     ipc_EventPacket *uBuf;
251     uBuf = uBuf_cache;
252     if (uBuf != NULL) {
253         uBuf_cache = (ipc_EventPacket *)uBuf_cache->next;
254         num_uBuf--;
255     } else {
256         uBuf = Memory_alloc(NULL, sizeof(ipc_EventPacket), 0, NULL);
257     }
258     return(uBuf);
261 static void put_uBuf(ipc_EventPacket * uBuf)
263     if (num_uBuf >= CACHE_NUM) {
264         Memory_free(NULL, uBuf, sizeof(*uBuf));
265     } else {
266         uBuf->next = (struct ipc_EventPacket *)uBuf_cache;
267         uBuf_cache = uBuf;
268         num_uBuf++;
269     }
270     return;
273 /*
274  * Instead of constantly allocating and freeing the notifier structures
275  * we just cache a few of them, and recycle them instead.
276  * The cache count is set with CACHE_NUM in ti-ipc.h.
277  */
279 static MsgList_t *get_nl()
281     MsgList_t *item;
282     item = nl_cache;
283     if (item != NULL) {
284         nl_cache = nl_cache->next;
285         num_nl--;
286     } else {
287         item = Memory_alloc(NULL, sizeof(MsgList_t), 0, NULL);
288     }
289     return(item);
292 static void put_nl(MsgList_t *item)
294     if (num_nl >= CACHE_NUM) {
295         Memory_free(NULL, item, sizeof(*item));
296     } else {
297         item->next = nl_cache;
298         nl_cache = item;
299         num_nl++;
300     }
301     return;
304 static WaitingReaders_t *get_wr()
306     WaitingReaders_t *item;
307     item = wr_cache;
308     if (item != NULL) {
309         wr_cache = wr_cache->next;
310         num_wr--;
311     } else {
312         item = Memory_alloc(NULL, sizeof(WaitingReaders_t), 0, NULL);
313     }
314     return(item);
317 static void put_wr(WaitingReaders_t *item)
319     if (num_wr >= CACHE_NUM) {
320         Memory_free(NULL, item, sizeof(*item));
321     } else {
322         item->next = wr_cache;
323         wr_cache = item;
324         num_wr++;
325     }
326     return;
328 /* The following functions are used for list/waiting reader management */
329 static MsgList_t *find_nl(int index)
331     MsgList_t *item=NULL;
332     item = ti_ipc_state.head;
333     while (item) {
334         if (item->index == index)
335             return(item);
336         item = item->next;
337     }
338     return(item);
341 /* we have the right locks when calling this function */
342 /*!
343  *  @brief      Function to enqueue a notify list item.
344  *
345  *  @param      index    Index of the client process associated with the item.
346  *
347  *  @sa         find_nl
348  *              get_nl
349  */
350 static int enqueue_notify_list(int index)
352     MsgList_t *item;
353     item = find_nl(index);
354     if (item == NULL) {
355         item = get_nl();
356         if (item == NULL) {
357             return(-1);
358         }
359         item->next = NULL;
360         item->index = index;
361         item->num_events=1;
362         if (ti_ipc_state.head == NULL) {
363             ti_ipc_state.head = item;
364             ti_ipc_state.tail = item;
365             item->prev = NULL;
366         }
367         else {
368             item->prev = ti_ipc_state.tail;
369             ti_ipc_state.tail->next = item;
370             ti_ipc_state.tail = item;
371         }
372     }
373     else {
374         item->num_events++;
375     }
376     return(0);
379 /* we have the right locks when calling this function */
380 /*!
381  *  @brief      Function to dequeue a notify list item.
382  *
383  *  @param      item     The item to remove.
384  *
385  *  @sa         put_nl
386  */
387 static inline int dequeue_notify_list_item(MsgList_t *item)
389     int index;
390     if (item == NULL) {
391         return(-1);
392     }
393     index = item->index;
394     item->num_events--;
395     if (item->num_events > 0) {
396         return(index);
397     }
398     if (ti_ipc_state.head == item) {
399         // removing head
400         ti_ipc_state.head = item->next;
401         if (ti_ipc_state.head != NULL) {
402             ti_ipc_state.head->prev = NULL;
403         }
404         else {
405             // removing head and tail
406             ti_ipc_state.tail = NULL;
407         }
408     }
409     else {
410         item->prev->next = item->next;
411         if (item->next != NULL) {
412             item->next->prev = item->prev;
413         }
414         else {
415             // removing tail
416             ti_ipc_state.tail = item->prev;
417         }
418     }
419     put_nl(item);
420     return(index);
423 /* we have the right locks when calling this function */
424 /*!
425  *  @brief      Function to add a waiting reader to the list.
426  *
427  *  @param      index    Index of the client process waiting reader to add.
428  *  @param      rcvid    Receive ID of the client process that was passed
429  *                       when the client called read().
430  *
431  *  @sa         None
432  */
433 static int enqueue_waiting_reader(int index, int rcvid)
435     WaitingReaders_t *item;
436     item = get_wr();
437     if (item == NULL) {
438         return(-1);
439     }
440     item->rcvid = rcvid;
441     item->next = NULL;
442     if (ti_ipc_state.eventState [index].head == NULL) {
443         ti_ipc_state.eventState [index].head = item;
444         ti_ipc_state.eventState [index].tail = item;
445     }
446     else {
447         ti_ipc_state.eventState [index].tail->next = item;
448         ti_ipc_state.eventState [index].tail = item;
449     }
450     return(EOK);
453 /* we have the right locks when calling this function */
454 /* caller frees item */
455 /*!
456  *  @brief      Function to remove a waiting reader from the list.
457  *
458  *  @param      index    Index of the client process waiting reader to dequeue.
459  *
460  *  @sa         None
461  */
462 static WaitingReaders_t *dequeue_waiting_reader(int index)
464     WaitingReaders_t *item = NULL;
465     if (ti_ipc_state.eventState [index].head) {
466         item = ti_ipc_state.eventState [index].head;
467         ti_ipc_state.eventState [index].head =
468                                      ti_ipc_state.eventState [index].head->next;
469         if (ti_ipc_state.eventState [index].head == NULL) {
470             ti_ipc_state.eventState [index].tail = NULL;
471         }
472     }
473     return(item);
476 /*!
477  *  @brief      Function find a specified waiting reader.
478  *
479  *  @param      index    Index of the client process waiting for the message.
480  *  @param      rcvid    Receive ID of the client process that was passed
481  *                       when the client called read().
482  *
483  *  @sa         None
484  */
486 static WaitingReaders_t *find_waiting_reader(int index, int rcvid)
488     WaitingReaders_t *item = NULL;
489     WaitingReaders_t *prev = NULL;
490     if (ti_ipc_state.eventState [index].head) {
491         item = ti_ipc_state.eventState [index].head;
492         while (item) {
493             if (item->rcvid == rcvid) {
494                 /* remove item from list */
495                 if (prev)
496                     prev->next = item->next;
497                 if (item == ti_ipc_state.eventState [index].head)
498                     ti_ipc_state.eventState [index].head = item->next;
499                 break;
500             }
501             else {
502                 prev = item;
503                 item = item->next;
504             }
505         }
506     }
507     return item;
510 /*!
511  *  @brief      Function used to check if there is a waiting reader with an
512  *              event (message) ready to be delivered.
513  *
514  *  @param      index    Index of the client process waiting for the message.
515  *  @param      item     Pointer to the waiting reader.
516  *
517  *  @sa         dequeue_notify_list_item
518  *              dequeue_waiting_reader
519  */
521 static int find_available_reader_and_event(int *index, WaitingReaders_t **item)
523     MsgList_t *temp;
524     if (ti_ipc_state.head == NULL) {
525         return(0);
526     }
527     temp = ti_ipc_state.head;
528     while (temp) {
529         if (ti_ipc_state.eventState [temp->index].head) {
530             // event and reader found
531             if (dequeue_notify_list_item(temp) >= 0) {
532                 *index = temp->index;
533                 *item = dequeue_waiting_reader(temp->index);
534             }
535             else {
536                 /* error occurred, return 0 as item has not been set */
537                 return(0);
538             }
539             return(1);
540         }
541         temp = temp->next;
542     }
543     return(0);
546 /*!
547  *  @brief      Function used to deliver the notification to the client that
548  *              it has received a message.
549  *
550  *  @param      index    Index of the client process receiving hte message.
551  *  @param      rcvid    Receive ID of the client process that was passed
552  *                       when the client called read().
553  *
554  *  @sa         put_uBuf
555  */
557 static void deliver_notification(int index, int rcvid)
559     int err = EOK;
560     ipc_EventPacket * uBuf     = NULL;
562     uBuf = (ipc_EventPacket *) List_get (ti_ipc_state.eventState [index].bufList);
564     /*  Let the check remain at run-time. */
565     if (uBuf != NULL) {
566         err = MsgReply(rcvid, uBuf->len, uBuf->data, uBuf->len);
567         if (err == -1)
568             perror("deliver_notification: MsgReply");
569         /* Free the processed event callback packet. */
570         put_uBuf(uBuf);
571     }
572     else {
573         MsgReply(rcvid, EOK, NULL, 0);
574     }
575     return;
578 /*!
579  *  @brief      Thread used for notifying waiting readers of messages.
580  *
581  *  @param      arg    Thread-specific private arg.
582  *
583  *  @sa         find_available_reader_and_event
584  *              deliver_notification
585  *              put_wr
586  */
587 static void *notifier_thread(void *arg)
589     int status;
590     int index;
591     WaitingReaders_t *item = NULL;
592     pthread_mutex_lock(&ti_ipc_state.lock);
593     while (ti_ipc_state.run) {
594         status = find_available_reader_and_event(&index, &item);
595         if ( (status == 0) || (item == NULL) ) {
596             status = pthread_cond_wait(&ti_ipc_state.cond, &ti_ipc_state.lock);
597             if ((status != EOK) && (status != EINTR)) {
598                 // false wakeup
599                 break;
600             }
601             status = find_available_reader_and_event(&index, &item);
602             if ( (status == 0) || (item == NULL) ) {
603                 continue;
604             }
605         }
606         pthread_mutex_unlock(&ti_ipc_state.lock);
607         // we have unlocked, and now we have an event to deliver
608         // we deliver one event at a time, relock, check and continue
609         deliver_notification(index, item->rcvid);
610         pthread_mutex_lock(&ti_ipc_state.lock);
611         put_wr(item);
612     }
613     pthread_mutex_unlock(&ti_ipc_state.lock);
614     return(NULL);
618 /*!
619  *  @brief      Attach a process to ti-ipc user support framework.
620  *
621  *  @param      obj    TI IPC instance
622  *
623  *  @sa         _ti_ipc_detach
624  */
625 static
626 Int
627 _ti_ipc_attach (ti_ipc_object * obj)
629     Int32                status   = EOK;
630     Bool                 flag     = FALSE;
631     Bool                 isInit   = FALSE;
632     List_Object *        bufList  = NULL;
633     IArg                 key      = 0;
634     List_Params          listparams;
635     UInt32               i;
637     GT_1trace (curTrace, GT_ENTER, "_ti_ipc_attach", obj);
639     key = IGateProvider_enter (ti_ipc_state.gateHandle);
640     for (i = 0 ; (i < MAX_PROCESSES) ; i++) {
641         if (ti_ipc_state.eventState [i].ipc == obj) {
642             ti_ipc_state.eventState [i].refCount++;
643             isInit = TRUE;
644             status = EOK;
645             break;
646         }
647     }
649     if (isInit == FALSE) {
650         List_Params_init (&listparams);
651         bufList = List_create (&listparams) ;
652         /* Search for an available slot for user process. */
653         for (i = 0 ; i < MAX_PROCESSES ; i++) {
654             if (ti_ipc_state.eventState [i].ipc == NULL) {
655                 ti_ipc_state.eventState [i].ipc = obj;
656                 ti_ipc_state.eventState [i].refCount = 1;
657                 ti_ipc_state.eventState [i].bufList = bufList;
658                 flag = TRUE;
659                 break;
660             }
661         }
663         /* No free slots found. Let this check remain at run-time,
664          * since it is dependent on user environment.
665          */
666         if (flag != TRUE) {
667             /*! @retval Notify_E_RESOURCE Maximum number of
668              supported user clients have already been registered. */
669             status = -ENOMEM;
670             GT_setFailureReason (curTrace,
671                               GT_4CLASS,
672                               "_ti_ipc_attach",
673                               status,
674                               "Maximum number of supported user"
675                                   " clients have already been "
676                                   "registered.");
677             if (bufList != NULL) {
678                 List_delete (&bufList);
679             }
680         }
681     }
682     IGateProvider_leave (ti_ipc_state.gateHandle, key);
684     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_attach", status);
686     /*! @retval Notify_S_SUCCESS Operation successfully completed. */
687     return status ;
691  /*!
692  *  @brief      This function adds a data to a registered process.
693  *
694  *  @param      obj       Instance object associated with the client
695  *  @param      src       Source address (endpoint) sending the data
696  *  @param      pid       Process ID associated with the client
697  *  @param      data      Data to be added
698  *  @param      len       Length of data to be added
699  *
700  *  @sa
701  */
702 Int
703 _ti_ipc_addBufByPid (ti_ipc_object *  obj,
704                      UInt32           src,
705                      UInt32           pid,
706                      void *           data,
707                      UInt32           len)
709     Int32                   status = EOK;
710     Bool                    flag   = FALSE;
711     ipc_EventPacket *  uBuf   = NULL;
712     IArg                    key;
713     UInt32                  i;
714     WaitingReaders_t *item;
715     MsgList_t *msgItem;
717     GT_assert (curTrace, (ti_ipc_state.isSetup == TRUE));
719     key = IGateProvider_enter (ti_ipc_state.gateHandle);
720     /* Find the registration for this callback */
721     for (i = 0 ; i < MAX_PROCESSES ; i++) {
722         if (ti_ipc_state.eventState [i].ipc == obj) {
723             flag = TRUE;
724             break;
725         }
726     }
727     IGateProvider_leave (ti_ipc_state.gateHandle, key);
729 #if !defined(IPC_BUILD_OPTIMIZE)
730     if (flag != TRUE) {
731         /*! @retval ENOMEM Could not find a registered handler
732                                       for this process. */
733         status = -ENOMEM;
734         GT_setFailureReason (curTrace,
735                              GT_4CLASS,
736                              "_ti_ipc_addBufByPid",
737                              status,
738                              "Could not find a registered handler "
739                              "for this process.!");
740     }
741     else {
742 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
743         /* Allocate memory for the buf */
744         pthread_mutex_lock(&ti_ipc_state.lock);
745         uBuf = get_uBuf();
746         pthread_mutex_unlock(&ti_ipc_state.lock);
748 #if !defined(IPC_BUILD_OPTIMIZE)
749         if (uBuf == NULL) {
750             /*! @retval Notify_E_MEMORY Failed to allocate memory for event
751                                 packet for received callback. */
752             status = -ENOMEM;
753             GT_setFailureReason (curTrace,
754                                  GT_4CLASS,
755                                  "_ti_ipc_addBufByPid",
756                                  status,
757                                  "Failed to allocate memory for event"
758                                  " packet for received callback.!");
759         }
760         else {
761 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
762             List_elemClear (&(uBuf->element));
763             GT_assert (curTrace,
764                        (ti_ipc_state.eventState [i].bufList != NULL));
766             if (data) {
767                 Memory_copy(uBuf->data, data, len);
768             }
769             uBuf->len = len;
771             List_put (ti_ipc_state.eventState [i].bufList,
772                       &(uBuf->element));
773             pthread_mutex_lock(&ti_ipc_state.lock);
774             item = dequeue_waiting_reader(i);
775             if (item) {
776                 // there is a waiting reader
777                 deliver_notification(i, item->rcvid);
778                 put_wr(item);
779                 pthread_mutex_unlock(&ti_ipc_state.lock);
780                 status = EOK;
781             }
782             else {
783                 if (enqueue_notify_list(i) < 0) {
784                     pthread_mutex_unlock(&ti_ipc_state.lock);
785                     status = -ENOMEM;
786                     GT_setFailureReason (curTrace,
787                                   GT_4CLASS,
788                                   "_ti_ipc_addBufByPid",
789                                   status,
790                                   "Failed to allocate memory for notifier");
791                 }
792                 else {
793                     msgItem = find_nl(i);
794                     /* TODO: obj could be NULL in some cases  */
795                     if (obj && msgItem) {
796                         if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify,
797                                                       msgItem->num_events, 0)) {
798                             iofunc_notify_trigger(obj->notify,
799                                                   msgItem->num_events,
800                                                   IOFUNC_NOTIFY_INPUT);
801                         }
802                     }
803                     status = EOK;
804                     pthread_cond_signal(&ti_ipc_state.cond);
805                     pthread_mutex_unlock(&ti_ipc_state.lock);
806                 }
807             }
808 #if !defined(IPC_BUILD_OPTIMIZE)
809         }
810     }
811 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
813     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_addBufByPid", status);
815     return status;
819 /*!
820  *  @brief      This function implements the callback registered with
821  *              MessageQCopy_create for each client.  This function
822  *              adds the message from the remote proc to a list
823  *              where it is routed to the appropriate waiting reader.
824  *
825  *  @param      handle    Destinatino MessageQCopy_Handle instance for the msg
826  *  @param      data      Message buffer
827  *  @param      len       Length of the message data
828  *  @param      priv      Private information given when callback was registered
829  *  @param      src       Source address of the message
830  *  @param      srcProc   Source proc of the message
831  *
832  *  @sa
833  */
834 Void
835 _ti_ipc_cb (MessageQCopy_Handle handle, void * data, int len, void * priv,
836             UInt32 src, UInt16 srcProc)
838 #if !defined(IPC_BUILD_OPTIMIZE)
839     Int32                   status = 0;
840 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
841     ti_ipc_object * obj = NULL;
843     if (ti_ipc_state.isSetup == FALSE) {
844         /* If module is not setup (e.g. in recovery), drop the received msg */
845         GT_0trace(curTrace, GT_3CLASS,
846             "_ti_ipc_cb: Module not setup. Dropping incoming msg.");
847         return;
848     }
850     obj = (ti_ipc_object *) priv;
852 #if !defined(IPC_BUILD_OPTIMIZE)
853     status =
854 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
855              _ti_ipc_addBufByPid (obj,
856                                   src,
857                                   obj->pid,
858                                   data,
859                                   len);
860 #if !defined(IPC_BUILD_OPTIMIZE)
861     if (status < 0) {
862         GT_setFailureReason (curTrace,
863                              GT_4CLASS,
864                              "_ti_ipc_cb",
865                              status,
866                              "Failed to add callback packet for pid");
867     }
868 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
871  /**
872   * Handler for ocb_calloc() requests.
873   *
874   * Special handler for ocb_calloc() requests that we export for control.  An
875   * open request from the client will result in a call to our special ocb_calloc
876   * handler.  This function allocates client-specific information.
877   *
878   * \param ctp       Thread's associated context information.
879   * \param device    Device attributes structure.
880   *
881   * \return Pointer to an iofunc_ocb_t OCB structure.
882   */
884 IOFUNC_OCB_T *
885 ti_ipc_ocb_calloc (resmgr_context_t * ctp, IOFUNC_ATTR_T * device)
887     ti_ipc_ocb_t * ocb = NULL;
888     ti_ipc_object * obj = NULL;
890     /* Wait for module to be setup during recovery */
891     while (ti_ipc_state.isSetup == FALSE) {
892         usleep(RECOVERY_POLL_RATE);
893     }
895     /* Allocate the OCB */
896     ocb = (ti_ipc_ocb_t *) calloc (1, sizeof (ti_ipc_ocb_t));
897     if (ocb == NULL){
898         errno = ENOMEM;
899         return (NULL);
900     }
902     ocb->pid = ctp->info.pid;
904     /* Allocate memory for the rpmsg object. */
905     obj = Memory_calloc (NULL, sizeof (ti_ipc_object), 0u, NULL);
906     if (obj == NULL) {
907         errno = ENOMEM;
908         free(ocb);
909         return (NULL);
910     }
911     else if (_ti_ipc_attach(obj) < 0) {
912         errno = ENOMEM;
913         Memory_free(NULL, obj, sizeof(ti_ipc_object));
914         free(ocb);
915         return (NULL);
916     }
917     else {
918         ocb->ipc = obj;
919         IOFUNC_NOTIFY_INIT(obj->notify);
920         obj->addr = MessageQCopy_ADDRANY;
921         obj->remoteAddr = MessageQCopy_ADDRANY;
922         obj->procId = MultiProc_INVALIDID;
923         obj->mq = NULL;
924         obj->isValid = TRUE;
925     }
927     return (IOFUNC_OCB_T *)(ocb);
931 /*!
932  *  @brief      Detach a process from ti-ipc user support framework.
933  *
934  *  @param      obj    TI IPC instance
935  *  @param      force  Tells if detach should be forced even if conditions
936  *                     are not met.
937  *
938  *  @sa         _ti_ipc_attach
939  */
940 static
941 Int
942 _ti_ipc_detach (ti_ipc_object * obj, Bool force)
944     Int32                status    = EOK;
945     Int32                tmpStatus = EOK;
946     Bool                 flag      = FALSE;
947     List_Object *        bufList   = NULL;
948     UInt32               i;
949     IArg                 key;
950     MsgList_t          * item;
951     WaitingReaders_t   * wr        = NULL;
952     struct _msg_info     info;
954     GT_1trace (curTrace, GT_ENTER, "_ti_ipc_detach", obj);
956     key = IGateProvider_enter (ti_ipc_state.gateHandle);
958     for (i = 0 ; i < MAX_PROCESSES ; i++) {
959         if (ti_ipc_state.eventState [i].ipc == obj) {
960             if (ti_ipc_state.eventState [i].refCount == 1) {
961                 ti_ipc_state.eventState [i].refCount = 0;
963                 flag = TRUE;
964                 break;
965             }
966             else {
967                 ti_ipc_state.eventState [i].refCount--;
968                 status = EOK;
969                 break;
970             }
971         }
972     }
973     IGateProvider_leave (ti_ipc_state.gateHandle, key);
975     if (flag == TRUE) {
976         key = IGateProvider_enter (ti_ipc_state.gateHandle);
977         /* Last client being unregistered for this process. */
978         ti_ipc_state.eventState [i].ipc = NULL;
980         /* Store in local variable to delete outside lock. */
981         bufList = ti_ipc_state.eventState [i].bufList;
983         ti_ipc_state.eventState [i].bufList = NULL;
985         IGateProvider_leave (ti_ipc_state.gateHandle, key);
986     }
988     if (flag != TRUE) {
989 #if !defined(IPC_BUILD_OPTIMIZE)
990         if (i == MAX_PROCESSES) {
991             /*! @retval Notify_E_NOTFOUND The specified user process was
992                      not found registered with Notify Driver module. */
993             status = -ENOMEM;
994             GT_setFailureReason (curTrace,
995                               GT_4CLASS,
996                               "_ti_ipc_detach",
997                               status,
998                               "The specified user process was not found"
999                               " registered with rpmsg Driver module.");
1000         }
1001 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
1002     }
1003     else {
1004         if (bufList != NULL) {
1005             /* Dequeue waiting readers and reply to them */
1006             pthread_mutex_lock(&ti_ipc_state.lock);
1007             while ((wr = dequeue_waiting_reader(i)) != NULL) {
1008                 /* Check if rcvid is still valid */
1009                 if (MsgInfo(wr->rcvid, &info) != -1) {
1010                     put_wr(wr);
1011                     pthread_mutex_unlock(&ti_ipc_state.lock);
1012                     MsgError(wr->rcvid, EINTR);
1013                     pthread_mutex_lock(&ti_ipc_state.lock);
1014                 }
1015             }
1016             /* Check for pending ionotify/select calls */
1017             if (obj) {
1018                 if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify, 1, 0)) {
1019                     iofunc_notify_trigger(obj->notify, 1, IOFUNC_NOTIFY_INPUT);
1020                 }
1021             }
1023             /* Free event packets for any received but unprocessed events. */
1024             while ((item = find_nl(i)) != NULL) {
1025                 if (dequeue_notify_list_item(item) >= 0) {
1026                     ipc_EventPacket * uBuf = NULL;
1028                     uBuf = (ipc_EventPacket *) List_get (bufList);
1030                     /*  Let the check remain at run-time. */
1031                     if (uBuf != NULL) {
1032                         put_uBuf(uBuf);
1033                     }
1034                 }
1035             }
1036             pthread_mutex_unlock(&ti_ipc_state.lock);
1038             /* Last client being unregistered with Notify module. */
1039             List_delete (&bufList);
1040         }
1042 #if !defined(IPC_BUILD_OPTIMIZE)
1043         if ((tmpStatus < 0) && (status >= 0)) {
1044             status =  tmpStatus;
1045             GT_setFailureReason (curTrace,
1046                              GT_4CLASS,
1047                              "_ti_ipc_detach",
1048                              status,
1049                              "Failed to delete termination semaphore!");
1050         }
1051 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
1052     }
1054     GT_1trace (curTrace, GT_LEAVE, "_ti_ipc_detach", status);
1056     /*! @retval Notify_S_SUCCESS Operation successfully completed */
1057     return status;
1060  /**
1061   * Handler for ocb_free() requests.
1062   *
1063   * Special handler for ocb_free() requests that we export for control.  A
1064   * close request from the client will result in a call to our special ocb_free
1065   * handler.  This function frees any client-specific information that was
1066   * allocated.
1067   *
1068   * \param i_ocb     OCB associated with client's session.
1069   *
1070   * \return POSIX errno value.
1071   *
1072   * \retval None.
1073   */
1075 void
1076 ti_ipc_ocb_free (IOFUNC_OCB_T * i_ocb)
1078     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1079     ti_ipc_object * obj;
1081     if (ocb) {
1082         if (ocb->ipc) {
1083             pthread_mutex_lock(&ti_ipc_state.lock);
1084             obj = ocb->ipc;
1085             /* TBD: Notification to remote core of endpoint closure? */
1086             if (obj->mq) {
1087                 /* Only delete mq if recovery did not do so */
1088                 MessageQCopy_delete (&obj->mq);
1089                 obj->mq = NULL;
1090             }
1092             /*
1093              * If recovery happened and connection is no longer valid,
1094              * ti_ipc_destroy would have already performed detach. So only
1095              * need to detach if it is still valid
1096              */
1097             if (obj->isValid) {
1098                 pthread_mutex_unlock(&ti_ipc_state.lock);
1099                 _ti_ipc_detach(ocb->ipc, FALSE);
1100             }
1101             else {
1102                 pthread_mutex_unlock(&ti_ipc_state.lock);
1103             }
1105             Memory_free (NULL, obj, sizeof(ti_ipc_object));
1106         }
1107         free (ocb);
1108     }
1111  /**
1112   * Handler for close_ocb() requests.
1113   *
1114   * This function removes the notification entries associated with the current
1115   * client.
1116   *
1117   * \param ctp       Thread's associated context information.
1118   * \param reserved  This argument must be NULL.
1119   * \param ocb       OCB associated with client's session.
1120   *
1121   * \return POSIX errno value.
1122   *
1123   * \retval EOK      Success.
1124   */
1126 Int
1127 ti_ipc_close_ocb (resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb)
1129     ti_ipc_ocb_t * ipc_ocb = (ti_ipc_ocb_t *)ocb;
1130     iofunc_notify_remove(ctp, ipc_ocb->ipc->notify);
1131     return (iofunc_close_ocb_default(ctp, reserved, ocb));
1134  /**
1135   * Handler for read() requests.
1136   *
1137   * Handles special read() requests that we export for control.  A read
1138   * request will get a message from the remote processor that is associated
1139   * with the client that is calling read().
1140   *
1141   * \param ctp     Thread's associated context information.
1142   * \param msg     The actual read() message.
1143   * \param ocb     OCB associated with client's session.
1144   *
1145   * \return POSIX errno value.
1146   *
1147   * \retval EOK      Success.
1148   * \retval EAGAIN   Call is non-blocking and no messages available.
1149   * \retval ENOMEM   Not enough memory to preform the read.
1150   */
1152 int
1153 ti_ipc_read(resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *i_ocb)
1155     Int status;
1156     Bool                    flag     = FALSE;
1157     Int                  retVal   = EOK;
1158     UInt32                  i;
1159     MsgList_t          * item;
1160     Int                  nonblock;
1161     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1162     ti_ipc_object * obj = ocb->ipc;
1164     if ((status = iofunc_read_verify(ctp, msg, i_ocb, &nonblock)) != EOK)
1165         return (status);
1167     pthread_mutex_lock(&ti_ipc_state.lock);
1169     if (!obj->isValid) {
1170         pthread_mutex_unlock(&ti_ipc_state.lock);
1171         /* this connection was shutdown due to recovery */
1172         return ESHUTDOWN;
1173     }
1175     if (obj->addr == MessageQCopy_ADDRANY) {
1176         pthread_mutex_unlock(&ti_ipc_state.lock);
1177         return ENOTCONN;
1178     }
1180     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1181         if (ti_ipc_state.eventState [i].ipc == obj) {
1182             flag = TRUE;
1183             break;
1184         }
1185     }
1187     /* Let the check remain at run-time. */
1188     if (flag == TRUE) {
1189         /* Let the check remain at run-time for handling any run-time
1190         * race conditions.
1191         */
1192         if (ti_ipc_state.eventState [i].bufList != NULL) {
1193             item = find_nl(i);
1194             if (dequeue_notify_list_item(item) < 0) {
1195                 if (nonblock) {
1196                     pthread_mutex_unlock(&ti_ipc_state.lock);
1197                     return EAGAIN;
1198                 }
1199                 else {
1200                     retVal = enqueue_waiting_reader(i, ctp->rcvid);
1201                     if (retVal == EOK) {
1202                         pthread_cond_signal(&ti_ipc_state.cond);
1203                         pthread_mutex_unlock(&ti_ipc_state.lock);
1204                         return(_RESMGR_NOREPLY);
1205                     }
1206                     retVal = ENOMEM;
1207                 }
1208             }
1209             else {
1210                 deliver_notification(i, ctp->rcvid);
1211                 pthread_mutex_unlock(&ti_ipc_state.lock);
1212                 return(_RESMGR_NOREPLY);
1213             }
1214         }
1215     }
1217     pthread_mutex_unlock(&ti_ipc_state.lock);
1219     /*! @retval Number-of-bytes-read Number of bytes read. */
1220     return retVal;
1223  /**
1224   * Handler for write() requests.
1225   *
1226   * Handles special write() requests that we export for control.  A write()
1227   * request will send a message to the remote processor which is associated with
1228   * the client.
1229   *
1230   * \param ctp     Thread's associated context information.
1231   * \param msg     The actual write() message.
1232   * \param io_ocb  OCB associated with client's session.
1233   *
1234   * \return POSIX errno value.
1235   *
1236   * \retval EOK      Success.
1237   * \retval ENOTCONN Remote address has not been set.
1238   * \retval ENOMEM   Not enough memory to perform the write.
1239   * \retval EIO      MessageQCopy_send failed.
1240   * \retval EINVAL   msg->i.bytes is negative.
1241   */
1243 int
1244 ti_ipc_write(resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *io_ocb)
1246     int status;
1247     char buf[MessageQCopy_BUFSIZE];
1248     int bytes;
1249     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)io_ocb;
1250     ti_ipc_object * obj = ocb->ipc;
1252     if ((status = iofunc_write_verify(ctp, msg, io_ocb, NULL)) != EOK) {
1253         return (status);
1254     }
1256     pthread_mutex_lock(&ti_ipc_state.lock);
1258     if (!obj->isValid) {
1259         pthread_mutex_unlock(&ti_ipc_state.lock);
1260         /* this connection was shutdown due to recovery */
1261         return ESHUTDOWN;
1262     }
1264     if (obj->remoteAddr == MessageQCopy_ADDRANY) {
1265         pthread_mutex_unlock(&ti_ipc_state.lock);
1266         return ENOTCONN;
1267     }
1269     bytes = ((int64_t) msg->i.nbytes) > MessageQCopy_BUFSIZE ?
1270             MessageQCopy_BUFSIZE : msg->i.nbytes;
1271     if (bytes < 0) {
1272         pthread_mutex_unlock(&ti_ipc_state.lock);
1273         return EINVAL;
1274     }
1275     _IO_SET_WRITE_NBYTES (ctp, bytes);
1277     status = resmgr_msgread(ctp, buf, bytes, sizeof(msg->i));
1278     if (status != bytes) {
1279         pthread_mutex_unlock(&ti_ipc_state.lock);
1280         return (errno);
1281     }
1283     status = MessageQCopy_send(obj->procId, MultiProc_self(), obj->remoteAddr,
1284                                    obj->addr, buf, bytes, TRUE);
1286     pthread_mutex_unlock(&ti_ipc_state.lock);
1288     if (status < 0) {
1289         return (EIO);
1290     }
1292     return(EOK);
1295  /**
1296   * Handler for TIIPC_IOCSETLOCAL requests.
1297   *
1298   * Handles TIIPC_IOCSETLOCAL requests to set the local endpoint address.
1299   *
1300   * \param ctp     Thread's associated context information.
1301   * \param msg     The actual devctl() message.
1302   * \param io_ocb  OCB associated with client's session.
1303   *
1304   * \return POSIX errno value.
1305   *
1306   * \retval EOK      Success.
1307   * \retval EISCONN  Local address is already set.
1308   * \retval ENOMEM   Not enough memory to create the endpoint.
1309   * \retval EINVAL   ctp->info.msglen or ctp->info.dstmsglen is not big enough.
1310   */
1311 static
1312 Int
1313 _ti_ipc_set_local(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1315     Int status = EOK;
1316     tiipc_local_params * cargs = (tiipc_local_params *)(_DEVCTL_DATA (msg->i));
1317     tiipc_local_params * out = (tiipc_local_params *)(_DEVCTL_DATA (msg->o));
1318     ti_ipc_object * obj = ocb->ipc;
1320     if ((ctp->info.msglen - sizeof(msg->i) < sizeof(tiipc_local_params)) ||
1321         (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_local_params))) {
1322         status = (EINVAL);
1323     }
1324     else if (obj->mq) {
1325         /* already a local endpoint associated with this instance */
1326         status = (EISCONN);
1327     }
1328     else {
1329         if (cargs->local_addr == TIIPC_ADDRANY) {
1330             cargs->local_addr = MessageQCopy_ADDRANY;
1331         }
1332         /* Create the local endpoint based on the request */
1333         obj->mq = MessageQCopy_create (cargs->local_addr, NULL, _ti_ipc_cb,
1334                                        obj, &obj->addr);
1335         if (obj->mq == NULL) {
1336             status = (ENOMEM);
1337         }
1338         else {
1339             out->local_addr = obj->addr;
1340             msg->o.ret_val = EOK;
1341             status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1342                                   sizeof(tiipc_local_params)));
1343         }
1344     }
1346     return status;
1349  /**
1350   * Handler for TIIPC_IOCGETLOCAL requests.
1351   *
1352   * Handles TIIPC_IOCGETLOCAL requests to get the local endpoint address info.
1353   *
1354   * \param ctp     Thread's associated context information.
1355   * \param msg     The actual devctl() message.
1356   * \param io_ocb  OCB associated with client's session.
1357   *
1358   * \return POSIX errno value.
1359   *
1360   * \retval EOK      Success.
1361   * \retval EINVAL   ctp->info.dstmsglen is not big enough.
1362   */
1363 static
1364 Int
1365 _ti_ipc_get_local(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1367     Int status = EOK;
1368     tiipc_local_params * out = (tiipc_local_params *)(_DEVCTL_DATA (msg->o));
1369     ti_ipc_object * obj = ocb->ipc;
1371     if (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_local_params)) {
1372         status = (EINVAL);
1373     }
1374     else {
1375         if (obj->addr == MessageQCopy_ADDRANY)
1376             out->local_addr = TIIPC_ADDRANY;
1377         else
1378             out->local_addr = obj->addr;
1379         msg->o.ret_val = EOK;
1380         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1381                               sizeof(tiipc_local_params)));
1382     }
1384     return status;
1387  /**
1388   * Handler for TIIPC_IOCSETREMOTE requests.
1389   *
1390   * Handles TIIPC_IOCSETREMOTE requests to set the remote endpoint address and
1391   * proc ID used for write() commands.
1392   *
1393   * \param ctp     Thread's associated context information.
1394   * \param msg     The actual devctl() message.
1395   * \param io_ocb  OCB associated with client's session.
1396   *
1397   * \return POSIX errno value.
1398   *
1399   * \retval EOK      Success.
1400   * \retval EISCONN  Remote address is already set.
1401   * \retval ENOMEM   Not enough memory to create the endpoint.
1402   * \retval EINVAL   ctp->info.msglen or ctp->info.dstmsglen is not big enough
1403   *                  or the specified remote proc ID is invalid.
1404   */
1405 static
1406 Int
1407 _ti_ipc_set_remote(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1409     Int status = EOK;
1410     tiipc_remote_params * cargs =
1411                                  (tiipc_remote_params *)(_DEVCTL_DATA (msg->i));
1412     ti_ipc_object *obj = ocb->ipc;
1414     if ((ctp->info.msglen - sizeof(msg->i) < sizeof (tiipc_remote_params)) ||
1415         (ctp->info.dstmsglen - sizeof(msg->o) < sizeof (tiipc_remote_params))) {
1416         status = (EINVAL);
1417     }
1418     else if (obj->remoteAddr != MessageQCopy_ADDRANY) {
1419         /* already a remote endpoint associated with this instance */
1420         status = (EISCONN);
1421     }
1422     else if (cargs->remote_proc == MultiProc_self() ||
1423              cargs->remote_proc >= MultiProc_getNumProcessors()) {
1424         /* Don't support sending to self and remote proc ID must be valid */
1425         status = (EINVAL);
1426     }
1427     else {
1428         obj->remoteAddr = cargs->remote_addr;
1429         obj->procId = cargs->remote_proc;
1430         msg->o.ret_val = EOK;
1431         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1432                               sizeof(tiipc_remote_params)));
1433     }
1435     return status;
1438  /**
1439   * Handler for TIIPC_IOCGETREMOTE requests.
1440   *
1441   * Handles TIIPC_IOCGETREMOTE requests to get the remote endpoint address info.
1442   *
1443   * \param ctp     Thread's associated context information.
1444   * \param msg     The actual devctl() message.
1445   * \param io_ocb  OCB associated with client's session.
1446   *
1447   * \return POSIX errno value.
1448   *
1449   * \retval EOK      Success.
1450   * \retval EINVAL   ctp->info.dstmsglen is not big enough.
1451   */
1452 static
1453 Int
1454 _ti_ipc_get_remote(resmgr_context_t *ctp, io_devctl_t *msg, ti_ipc_ocb_t *ocb)
1456     Int status = EOK;
1457     tiipc_remote_params * out = (tiipc_remote_params *)(_DEVCTL_DATA (msg->o));
1458     ti_ipc_object * obj = ocb->ipc;
1460     if (ctp->info.dstmsglen - sizeof(msg->i) < sizeof (tiipc_remote_params)) {
1461         status = (EINVAL);
1462     }
1463     else {
1464         if (obj->remoteAddr == MessageQCopy_ADDRANY)
1465             out->remote_addr = TIIPC_ADDRANY;
1466         else
1467             out->remote_addr = obj->remoteAddr;
1468         out->remote_proc = obj->procId;
1469         msg->o.ret_val = EOK;
1470         status = (_RESMGR_PTR(ctp, &msg->o, sizeof(msg->o) +\
1471                               sizeof(tiipc_remote_params)));
1472     }
1474     return status;
1477  /**
1478   * Handler for devctl() requests.
1479   *
1480   * Handles special devctl() requests that we export for control.  A devctl()
1481   * request will perform different functions depending on the dcmd.
1482   *
1483   * \param ctp     Thread's associated context information.
1484   * \param msg     The actual devctl() message.
1485   * \param i_ocb   OCB associated with client's session.
1486   *
1487   * \return POSIX errno value.
1488   *
1489   * \retval EOK      Success.
1490   * \retval other    Fail.
1491   */
1492 static
1493 Int
1494 ti_ipc_devctl(resmgr_context_t *ctp, io_devctl_t *msg, IOFUNC_OCB_T *i_ocb)
1496     Int status = 0;
1497     ti_ipc_ocb_t *ocb = (ti_ipc_ocb_t *)i_ocb;
1499     if ((status = iofunc_devctl_default(ctp, msg, &ocb->hdr)) != _RESMGR_DEFAULT)
1500         return(_RESMGR_ERRNO(status));
1501     status = 0;
1503     if (!ocb->ipc->isValid) {
1504         return ESHUTDOWN;
1505     }
1507     switch (msg->i.dcmd)
1508     {
1509         case TIIPC_IOCSETLOCAL:
1510             /* Must be called before receiving messages */
1511             status = _ti_ipc_set_local (ctp, msg, ocb);
1512             break;
1513         case TIIPC_IOCGETLOCAL:
1514             status = _ti_ipc_get_local (ctp, msg, ocb);
1515             break;
1516         case TIIPC_IOCSETREMOTE:
1517             /* Must be called before sending messages */
1518             status = _ti_ipc_set_remote (ctp, msg, ocb);
1519             break;
1520         case TIIPC_IOCGETREMOTE:
1521             status = _ti_ipc_get_remote (ctp, msg, ocb);
1522             break;
1523         default:
1524             status = (ENOSYS);
1525             break;
1526     }
1528     return status;
1530  /**
1531   * Unblock read calls
1532   *
1533   * This function checks if the client is blocked on a read call and if so,
1534   * unblocks the client.
1535   *
1536   * \param ctp     Thread's associated context information.
1537   * \param msg     The pulse message.
1538   * \param ocb     OCB associated with client's session.
1539   *
1540   * \return POSIX errno value.
1541   *
1542   * \retval EINTR    The client has been unblocked.
1543   * \retval other    The client has not been unblocked or the client was not
1544   *                  blocked.
1545   */
1547 int
1548 ti_ipc_read_unblock(resmgr_context_t *ctp, io_pulse_t *msg, iofunc_ocb_t *i_ocb)
1550     UInt32                  i;
1551     Bool                    flag     = FALSE;
1552     WaitingReaders_t      * wr;
1553     ti_ipc_ocb_t * ocb = (ti_ipc_ocb_t *)i_ocb;
1554     ti_ipc_object * obj = ocb->ipc;
1556     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1557         if (ti_ipc_state.eventState [i].ipc == obj) {
1558             flag = TRUE;
1559             break;
1560         }
1561     }
1563     /*  Let the check remain at run-time. */
1564     if (flag == TRUE) {
1565         /* Let the check remain at run-time for handling any run-time
1566          * race conditions.
1567          */
1568         pthread_mutex_lock(&ti_ipc_state.lock);
1569         if (ti_ipc_state.eventState [i].bufList != NULL) {
1570             wr = find_waiting_reader(i, ctp->rcvid);
1571             if (wr) {
1572                 put_wr(wr);
1573                 pthread_mutex_unlock(&ti_ipc_state.lock);
1574                 return (EINTR);
1575             }
1576         }
1577         pthread_mutex_unlock(&ti_ipc_state.lock);
1578     }
1580     return _RESMGR_NOREPLY;
1583  /**
1584   * Handler for unblock() requests.
1585   *
1586   * Handles unblock request for the client which is requesting to no longer be
1587   * blocked on the ti-ipc driver.
1588   *
1589   * \param ctp     Thread's associated context information.
1590   * \param msg     The pulse message.
1591   * \param ocb     OCB associated with client's session.
1592   *
1593   * \return POSIX errno value.
1594   *
1595   * \retval EINTR    The rcvid has been unblocked.
1596   */
1598 int
1599 ti_ipc_unblock(resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb)
1601     int status = _RESMGR_NOREPLY;
1602     struct _msg_info info;
1604     /*
1605      * Try to run the default unblock for this message.
1606      */
1607     if ((status = iofunc_unblock_default(ctp,msg, ocb)) != _RESMGR_DEFAULT) {
1608         return status;
1609     }
1611     /*
1612      * Check if rcvid is still valid and still has an unblock
1613      * request pending.
1614      */
1615     if (MsgInfo(ctp->rcvid, &info) == -1 ||
1616         !(info.flags & _NTO_MI_UNBLOCK_REQ)) {
1617         return _RESMGR_NOREPLY;
1618     }
1620     if (ti_ipc_read_unblock(ctp, msg, ocb) != _RESMGR_NOREPLY) {
1621            return _RESMGR_ERRNO(EINTR);
1622     }
1624     return _RESMGR_ERRNO(EINTR);
1627  /**
1628   * Handler for notify() requests.
1629   *
1630   * Handles special notify() requests that we export for control.  A notify
1631   * request results from the client calling select().
1632   *
1633   * \param ctp     Thread's associated context information.
1634   * \param msg     The actual notify() message.
1635   * \param ocb     OCB associated with client's session.
1636   *
1637   * \return POSIX errno value.
1638   */
1640 Int
1641 ti_ipc_notify( resmgr_context_t *ctp, io_notify_t *msg, RESMGR_OCB_T *ocb)
1643     ti_ipc_ocb_t * ipc_ocb = (ti_ipc_ocb_t *)ocb;
1644     int trig;
1645     int i = 0;
1646     Bool flag = FALSE;
1647     MsgList_t * item = NULL;
1648     int status = EOK;
1649     ti_ipc_object * obj = ipc_ocb->ipc;
1651     trig = _NOTIFY_COND_OUTPUT; /* clients can give us data */
1653     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1654         if (ti_ipc_state.eventState [i].ipc == obj) {
1655             flag = TRUE;
1656             break;
1657         }
1658     }
1660     pthread_mutex_lock(&ti_ipc_state.lock);
1661     if (!obj->isValid) {
1662          /*
1663           * connection is no longer valid after recovery.
1664           * unblock all select calls
1665           */
1666          trig |= _NOTIFY_COND_INPUT;
1667     }
1668     /* Let the check remain at run-time. */
1669     else if (flag == TRUE) {
1670         /* Let the check remain at run-time for handling any run-time
1671         * race conditions.
1672         */
1673         if (ti_ipc_state.eventState [i].bufList != NULL) {
1674             item = find_nl(i);
1675             if (item && item->num_events > 0) {
1676                 trig |= _NOTIFY_COND_INPUT;
1677             }
1678         }
1679     }
1680     status = iofunc_notify(ctp, msg, ipc_ocb->ipc->notify, trig, NULL, NULL);
1681     pthread_mutex_unlock(&ti_ipc_state.lock);
1682     return status;
1685  /**
1686   * Initializes and attaches ti-ipc resource manager functions to an
1687   * ti-ipc device name.
1688   *
1689   * \param num     The number to append to the end of the device name.
1690   *
1691   * \return Pointer to the created ti_ipc_dev_t device.
1692   */
1694 static
1695 ti_ipc_dev_t *
1696 _init_device ()
1698     iofunc_attr_t  * attr;
1699     resmgr_attr_t    resmgr_attr;
1700     ti_ipc_dev_t *   dev = NULL;
1702     dev = malloc(sizeof(*dev));
1703     if (dev == NULL) {
1704         return NULL;
1705     }
1707     memset(&resmgr_attr, 0, sizeof resmgr_attr);
1708     resmgr_attr.nparts_max = 10;
1709     resmgr_attr.msg_max_size = 2048;
1710     memset(&dev->ti_ipc.mattr, 0, sizeof(iofunc_mount_t));
1711     dev->ti_ipc.mattr.flags = ST_NOSUID | ST_NOEXEC;
1712     dev->ti_ipc.mattr.conf = IOFUNC_PC_CHOWN_RESTRICTED |
1713                               IOFUNC_PC_NO_TRUNC |
1714                               IOFUNC_PC_SYNC_IO;
1715     dev->ti_ipc.mattr.funcs = &dev->ti_ipc.mfuncs;
1716     memset(&dev->ti_ipc.mfuncs, 0, sizeof(iofunc_funcs_t));
1717     dev->ti_ipc.mfuncs.nfuncs = _IOFUNC_NFUNCS;
1718     dev->ti_ipc.mfuncs.ocb_calloc = ti_ipc_ocb_calloc;
1719     dev->ti_ipc.mfuncs.ocb_free = ti_ipc_ocb_free;
1720     iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &dev->ti_ipc.cfuncs,
1721                      _RESMGR_IO_NFUNCS, &dev->ti_ipc.iofuncs);
1722     iofunc_attr_init(attr = &dev->ti_ipc.cattr, S_IFCHR | 0777, NULL, NULL);
1723     dev->ti_ipc.iofuncs.unblock = ti_ipc_unblock;
1724     dev->ti_ipc.iofuncs.devctl = ti_ipc_devctl;
1725     dev->ti_ipc.iofuncs.notify = ti_ipc_notify;
1726     dev->ti_ipc.iofuncs.close_ocb = ti_ipc_close_ocb;
1727     dev->ti_ipc.iofuncs.read = ti_ipc_read;
1728     dev->ti_ipc.iofuncs.write = ti_ipc_write;
1729     attr->mount = &dev->ti_ipc.mattr;
1730     iofunc_time_update(attr);
1732     if (-1 == (dev->ti_ipc.resmgr_id =
1733         resmgr_attach(ipc_dpp, &resmgr_attr,
1734                       TIIPC_DEVICE_NAME, _FTYPE_ANY, 0,
1735                       &dev->ti_ipc.cfuncs,
1736                       &dev->ti_ipc.iofuncs, attr))) {
1737         free(dev);
1738         return(NULL);
1739     }
1741     return(dev);
1744  /**
1745   * Detaches an ti-ipc resource manager device name.
1746   *
1747   * \param dev     The device to detach.
1748   *
1749   * \return POSIX errno value.
1750   */
1752 static
1753 Void
1754 _deinit_device (ti_ipc_dev_t * dev)
1756     resmgr_detach(ipc_dpp, dev->ti_ipc.resmgr_id, 0);
1758     free (dev);
1760     return;
1763 /*!
1764  *  @brief  Module setup function.
1765  *
1766  *  @sa     ti_ipc_destroy
1767  */
1768 Int
1769 ti_ipc_setup (bool recover)
1771     UInt16 i;
1772     List_Params  listparams;
1773     Int status = 0;
1774     Error_Block eb;
1775     pthread_attr_t thread_attr;
1776     struct sched_param sched_param;
1778     GT_0trace (curTrace, GT_ENTER, "ti_ipc_setup");
1780     Error_init(&eb);
1782     List_Params_init (&listparams);
1783     if (!recover) {
1784         ti_ipc_state.gateHandle = (IGateProvider_Handle)
1785                      GateSpinlock_create ((GateSpinlock_Handle) NULL, &eb);
1786 #if !defined(IPC_BUILD_OPTIMIZE)
1787         if (ti_ipc_state.gateHandle == NULL) {
1788             status = -ENOMEM;
1789             GT_setFailureReason (curTrace,
1790                              GT_4CLASS,
1791                              "_ti_ipc_setup",
1792                              status,
1793                              "Failed to create spinlock gate!");
1794             goto exit;
1795         }
1796 #endif /* if !defined(IPC_BUILD_OPTIMIZE) */
1797     }
1799     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1800         ti_ipc_state.eventState [i].bufList = NULL;
1801         ti_ipc_state.eventState [i].ipc = NULL;
1802         ti_ipc_state.eventState [i].refCount = 0;
1803         ti_ipc_state.eventState [i].head = NULL;
1804         ti_ipc_state.eventState [i].tail = NULL;
1805     }
1807     pthread_attr_init(&thread_attr );
1808     sched_param.sched_priority = PRIORITY_REALTIME_LOW;
1809     pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
1810     pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
1811     pthread_attr_setschedparam(&thread_attr, &sched_param);
1813     ti_ipc_state.run = TRUE;
1814     if (pthread_create(&ti_ipc_state.nt,
1815                        &thread_attr, notifier_thread, NULL) == EOK) {
1816         pthread_setname_np(ti_ipc_state.nt, "tiipc-notifier");
1817         /* create a /dev/tiipc instance for users to open */
1818         if (!ti_ipc_state.dev)
1819             ti_ipc_state.dev = _init_device();
1820         if (ti_ipc_state.dev == NULL) {
1821             Osal_printf("Failed to create tiipc");
1822             ti_ipc_state.run = FALSE;
1823         }
1824         else {
1825             ti_ipc_state.isSetup = TRUE;
1826         }
1827     }
1828     else {
1829         ti_ipc_state.run = FALSE;
1830     }
1831     pthread_attr_destroy(&thread_attr);
1833 exit:
1834     GT_0trace (curTrace, GT_LEAVE, "ti_ipc_setup");
1835     return status;
1839 /*!
1840  *  @brief  Module destroy function.
1841  *
1842  *  @sa     ti_ipc_setup
1843  */
1844 Void
1845 ti_ipc_destroy (bool recover)
1847     ipc_EventPacket * packet;
1848     UInt32                  i;
1849     List_Handle             bufList;
1850     ti_ipc_object      * obj = NULL;
1851     WaitingReaders_t      * wr = NULL;
1852     struct _msg_info        info;
1854     GT_0trace (curTrace, GT_ENTER, "_ti_ipc_destroy");
1856     if (!recover) {
1857         _deinit_device(ti_ipc_state.dev);
1858         ti_ipc_state.dev = NULL;
1859     }
1861     ti_ipc_state.isSetup = FALSE;
1863     for (i = 0 ; i < MAX_PROCESSES ; i++) {
1864         pthread_mutex_lock(&ti_ipc_state.lock);
1865         obj = ti_ipc_state.eventState[i].ipc;
1866         if (obj != NULL) {
1867             /* This is recovery.  Need to mark mq structures as invalid */
1868             obj->isValid = FALSE;
1869             if (obj->mq) {
1870                 MessageQCopy_delete(&obj->mq);
1871                 obj->mq = NULL;
1872             }
1873         }
1874         bufList = ti_ipc_state.eventState [i].bufList;
1876         ti_ipc_state.eventState [i].bufList = NULL;
1877         ti_ipc_state.eventState [i].ipc = NULL;
1878         ti_ipc_state.eventState [i].refCount = 0;
1879         if (bufList != NULL) {
1880             /* Dequeue waiting readers and reply to them */
1881             while ((wr = dequeue_waiting_reader(i)) != NULL) {
1882                 /* Check if rcvid is still valid */
1883                 if (MsgInfo(wr->rcvid, &info) != -1) {
1884                     put_wr(wr);
1885                     pthread_mutex_unlock(&ti_ipc_state.lock);
1886                     MsgError(wr->rcvid, EINTR);
1887                     pthread_mutex_lock(&ti_ipc_state.lock);
1888                 }
1889             }
1890             /* Check for pending ionotify/select calls */
1891             if (obj) {
1892                 if (IOFUNC_NOTIFY_INPUT_CHECK(obj->notify, 1, 0)) {
1893                     iofunc_notify_trigger(obj->notify, 1, IOFUNC_NOTIFY_INPUT);
1894                 }
1895             }
1896             pthread_mutex_unlock(&ti_ipc_state.lock);
1898             /* Free event packets for any received but unprocessed events. */
1899             while (List_empty (bufList) != TRUE){
1900                 packet = (ipc_EventPacket *)
1901                               List_get (bufList);
1902                 if (packet != NULL){
1903                     Memory_free (NULL, packet, sizeof(*packet));
1904                 }
1905             }
1906             List_delete (&(bufList));
1907         }
1908         else {
1909             pthread_mutex_unlock(&ti_ipc_state.lock);
1910         }
1911     }
1913     /* Free the cached list */
1914     pthread_mutex_lock(&ti_ipc_state.lock);
1915     flush_uBuf();
1916     pthread_mutex_unlock(&ti_ipc_state.lock);
1918     if ((!recover) && (ti_ipc_state.gateHandle != NULL)) {
1919         GateSpinlock_delete ((GateSpinlock_Handle *)
1920                                        &(ti_ipc_state.gateHandle));
1921     }
1923     ti_ipc_state.run = FALSE;
1924     // run through and destroy the thread, and all outstanding
1925     // notify structures
1926     pthread_mutex_lock(&ti_ipc_state.lock);
1927     pthread_cond_signal(&ti_ipc_state.cond);
1928     pthread_mutex_unlock(&ti_ipc_state.lock);
1929     pthread_join(ti_ipc_state.nt, NULL);
1930     pthread_mutex_lock(&ti_ipc_state.lock);
1931     while (ti_ipc_state.head != NULL) {
1932         int index;
1933         WaitingReaders_t *item;
1934         index = dequeue_notify_list_item(ti_ipc_state.head);
1935         if (index < 0)
1936             break;
1937         item = dequeue_waiting_reader(index);
1938         while (item) {
1939             put_wr(item);
1940             item = dequeue_waiting_reader(index);
1941         }
1942     }
1943     ti_ipc_state.head = NULL ;
1944     ti_ipc_state.tail = NULL ;
1945     pthread_mutex_unlock(&ti_ipc_state.lock);
1947     GT_0trace (curTrace, GT_LEAVE, "_ti_ipc_destroy");