]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/traceframework.git/commitdiff
added contract handle verification checks in library, added more documentation
authorAravind Batni <aravindbr@ti.com>
Thu, 6 Mar 2014 00:36:51 +0000 (19:36 -0500)
committerAravind Batni <aravindbr@ti.com>
Thu, 6 Mar 2014 00:36:51 +0000 (19:36 -0500)
15 files changed:
config.bld
docs/ReleaseNotes_traceframework.doc
docs/ReleaseNotes_traceframework.pdf
docs/tiheader.htm
docs/traceframework_ug.docx
docs/traceframework_ug.pdf
package.xdc
producer.h
src/traceframework.c
test/TFUnitTest/src/armv7/linux/fw_init.c
test/TFUnitTest/src/c66x/bios/testFramework.c
tf_loc.h [changed mode: 0644->0755]
tfver.h
trace_contract.h
traceframework.h [changed mode: 0644->0755]

index 7bf908fc8b352bd7d04798b0da6960a0088f25a0..fc5b304f9e92678520701f6f5c1fde80a2385e6c 100755 (executable)
@@ -24,7 +24,7 @@ var tfDriverPath = new java.io.File(".//").getPath();
 var tfLLDPartNumber = java.lang.System.getenv("SOC_FAMILY");\r
 \r
 /* Configure the TraceFramework Socket Release Version Information */\r
-var tfDriverReleaseVersion = [01,01,01,00];\r
+var tfDriverReleaseVersion = [01,01,01,01];\r
 \r
 var pkgName = Pkg.name;\r
 \r
index 1a21e3693dc1fb43ecd80fadafd27a21fc740131..649d1e88f58f3c65a358c150b646c728fed62708 100755 (executable)
Binary files a/docs/ReleaseNotes_traceframework.doc and b/docs/ReleaseNotes_traceframework.doc differ
index 511f8a12b152710a608aacf50f76b0c08107ebed..38ff7e0111ed4a3afb2fad88d1f75ca53055db46 100755 (executable)
Binary files a/docs/ReleaseNotes_traceframework.pdf and b/docs/ReleaseNotes_traceframework.pdf differ
index 57de9bb01e7921f5607e64263221eee3f69a233c..3c61efe15bfeb5385362b6b49d8c01120f4b4bc5 100755 (executable)
@@ -6,7 +6,7 @@
 </head><body>
 <table width=100%>
 <tr>
-  <td bgcolor="black" width="1"><a href="http://www.ti.com"><img border=0 src="../tilogo.gif"></a></td>
-  <td bgcolor="red"><img src="../titagline.gif"></td>
+  <td bgcolor="black" width="1"><a href="http://www.ti.com"><img border=0 src="../../tilogo.gif"></a></td>
+  <td bgcolor="red"><img src="../../titagline.gif"></td>
 </tr>
 </table>
index 4fdb91d495d3eb40b833ce69a615f341589155c7..4b4471bb4718e0fb9f9b6628596e4b76d6f979fd 100755 (executable)
Binary files a/docs/traceframework_ug.docx and b/docs/traceframework_ug.docx differ
index aedab02368f89fb0ca63513b8cd3d80f7374fed4..c5b14bde7c05ebc7f23ade2470de423f88b10ba0 100755 (executable)
Binary files a/docs/traceframework_ug.pdf and b/docs/traceframework_ug.pdf differ
index 76e49856bed2ef4e9810d5703accab2e2c0d9509..e7477c6766699d6d9b36b941c03893a9b2c8330f 100755 (executable)
@@ -8,7 +8,7 @@
  *\r
  * Copyright (C) 2011-2013, Texas Instruments, Inc.\r
  *****************************************************************************/\r
-package ti.instrumentation.traceframework[1, 1, 1, 00] {\r
+package ti.instrumentation.traceframework[1, 1, 1, 01] {\r
     module Settings;\r
 }\r
 \r
index 367cf9ca14074189ff2def6118b40da2363a5d0a..83812b0270ebb9cacf47bf8b3f8bed601ecb02a8 100755 (executable)
@@ -106,8 +106,11 @@ typedef enum prodStatus
   TF_PRODUCER_MAX_SUPPORTED_CONSUMERS_REACHED,\r
   /**< Producer reached maximum number of consumers */   \r
 \r
-  TF_PRODUCER_PROD_FAIL\r
+  TF_PRODUCER_PROD_FAIL,\r
   /**< Producer ended up with an unsuccessful operation */   \r
+\r
+  TF_PRODUCER_INVALID_HANDLE\r
+  /**< Invalid producer handle */   \r
   \r
 } tf_prodStatus_e;\r
 \r
index 97b061eefd20d49efc3f7dc026b073be61fd4eb8..3c97d5c1d9769b1fdc97ff6635559b148b24857a 100755 (executable)
   #define SWIZ(x)  (x)
 #endif
 
-#include "ti/instrumentation/traceframework/src/tf_utils.h"
-#include "ti/instrumentation/traceframework/traceframework.h"
+#include "src/tf_utils.h"
+#include "traceframework.h"
 
 #ifdef TF_LINUX_USERSPACE
 #include <stdio.h>
-#include <ti/instrumentation/traceframework/src/cuia_prodif.h>
+#include "src/cuia_prodif.h"
 #else
-#include <ti/instrumentation/traceframework/src/uia_prodif.h>
+#include "src/uia_prodif.h"
 #endif
 
-#include <ti/instrumentation/traceframework/tfver.h>
+#include "tfver.h"
 const char      tfVersionStr[] = TF_DRV_VERSION_STR ":" __DATE__       ":" __TIME__;
 
 /* TF Local Object */
@@ -78,6 +78,59 @@ static inline uint32_t swiz32 (uint32_t x)
 }
 #endif
 
+static int32_t setupName(char *dst, char *src)
+{
+  int     len;
+  int32_t ret = 0;
+  
+  len = strlen(src);
+  
+  if (len < 127)
+       strcpy(dst, src);
+  else
+       ret = -1;
+
+  return (ret);
+}
+
+static inline int32_t validate_offset (uint32_t offset) 
+{
+  int32_t retval = 0;
+  
+  if (tfLObj.cfg.instPoolBaseAddr != 0) {
+       /* do a size check on the offset, offset should never be greater than pool size */
+       if (offset > tfLObj.cfg.instPoolSize)
+               retval = -1;
+  }
+  
+  return (retval);
+}
+
+static inline int32_t validate_contract_handle(tf_contract_HANDLE handle) 
+{
+       tf_contract_t   *cPtr = (tf_contract_t *) tf_get_addr(handle);
+
+    /* Two stage verification is done here */
+
+       /* 1. Check if the contract handle is correct when using the instPoolBaseAddress */
+       if (validate_offset((uint32_t)handle)) {
+         return (-1);
+       }
+
+       /* Cache Invalidate Contract fileds to read in this function is not required since contract
+        * contractInfo field woudl have been already cached during the contract create
+        */
+
+       /* 2. Check if the contract has the magic id value */
+       if (cPtr->tf_contractInfo.magic_word == 0xbabeface) {
+         return (0);   
+       }
+       else {
+         return (-1);
+       }
+       
+}
+
 static int32_t  getSlotNum(tf_contract_t* ptr, uint32_t unique_id)
 {
   int             i;
@@ -103,183 +156,6 @@ static int32_t  getSlotNum(tf_contract_t* ptr, uint32_t unique_id)
   else 
        return (-1); /* no slot available */
 }
-#if 0
-static int32_t syncLockCheck(tf_contract_HANDLE contract_handle, uint32_t user_id)  
-{  
-  tf_contract_t      *cPtr = (tf_contract_t *) contract_handle;  
-  uint32_t                       sz1  = (sizeof (conSharedInfo_t));  
-  syncLockUser_t     *users;  
-  int32_t                    ret = SYNC_LOCK_ERROR_NONE;  
-
-  if ( contract_handle == NULL )  {
-       ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_HANDLE; 
-  }
-  else {
-         //for ( i = 0; i < TF_MAX_CONSUMERS_PERCONTRACT; i++) 
-         { 
-                 /* Invalidate Cache for all slots to get information from all consumers*/ 
-                 TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[user_id], sz1);
-                 users  = (syncLockUser_t *)&cPtr->consumer_shared_info[user_id].consumerInfo.syncLockUser;    
-                 if ( users->entering == 1 || users->number > 0 ) 
-                 {
-                   ret = SYNC_LOCK_IN_USE;  
-                       return ( ret );  
-                 } 
-         }  
-  }
-  return (ret);
-}
-
-
-/**
- *  @brief Acquires the lock. If another user has the lock, this function will 
- *         block until the lock has been released.
- *
- *  @param[in]   lock         Lock handle.
- *
- *  @param[in]   user_id      ID of the user attempting to obtain the lock.
- *
- *  @return      0 if the lock has been obtained. Non-zero if an error was 
- *               encountered.
- */
-/* Based on the Lamport's Bakery algorithm */
-volatile int32_t number, entering, user_number, user_entering;
-int32_t syncLockAcquire(tf_contract_HANDLE contract_handle, int32_t user_id)
-{
-  tf_contract_t*  cPtr = (tf_contract_t *) contract_handle;
-  uint32_t           sz1 = (sizeof (conSharedInfo_t));
-  syncLockUser_t *users, *myself;
-  int32_t         i, ret = SYNC_LOCK_ERROR_NONE;
-
-  if ( contract_handle == NULL ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_HANDLE;
-    return ( ret );    
-  }
-  
-  if ( ( user_id < 0) || (user_id >= TF_MAX_CONSUMERS_PERCONTRACT) ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_USER_ID;
-       return (ret);
-  }
-  
-  /* Cache Inv for my slot to reflect in shared memory */
-  TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[user_id], sz1); 
-
-  /* Take a number */
-  myself = &cPtr->consumer_shared_info[user_id].consumerInfo.syncLockUser;  
-  tf_contract_reg32_r((uint32_t *)&number,      (uint32_t *) &myself->number);
-  tf_contract_reg32_r((uint32_t *)&entering, (uint32_t *) &myself->entering); 
-
-  if ( ( number > 0 ) || 
-           (entering == 1) ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_DBL_LOCK;
-  }
-  else 
-  {
-    /* number[i] = 1 + max(number[1:N]) */
-       entering = 1; number = 0;
-       
-       tf_contract_reg32_w((uint32_t *)&number,   (uint32_t *) &myself->number);
-       tf_contract_reg32_w((uint32_t *)&entering, (uint32_t *) &myself->entering);     
-
-       /* Wb Cache for my slot to reflect in shared memory */
-       TF_CONTRACT_osalEndMemAccess(&cPtr->consumer_shared_info[user_id], sz1); 
-       
-    for ( i = 0; i < TF_MAX_CONSUMERS_PERCONTRACT; i++)
-    {
-      users = &cPtr->consumer_shared_info[i].consumerInfo.syncLockUser;
-      /* Invalidate Cache for all slots to get information from all consumers*/
-      TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[i], sz1);       
-      tf_contract_reg32_r((uint32_t *) &user_number, (uint32_t *) &users->number);               
-      if (  number < user_number )
-      {
-         number = user_number;
-        tf_contract_reg32_w((uint32_t *)&number,   (uint32_t *) &myself->number);               
-                /* Wb Cache for my slot to reflect in shared memory */
-        TF_CONTRACT_osalEndMemAccess(&cPtr->consumer_shared_info[user_id], sz1);                
-      }
-    }
-
-       number ++;   entering = 0;
-       tf_contract_reg32_w((uint32_t *)&number,   (uint32_t *) &myself->number);
-       tf_contract_reg32_w((uint32_t *)&entering, (uint32_t *) &myself->entering);
-       
-       /* Wb Cache for my slot to reflect in shared memory */
-       TF_CONTRACT_osalEndMemAccess(&cPtr->consumer_shared_info[user_id], sz1);        
-
-    /* Wait for the number to be "called"... (No one to call you, so go around to everyone to see if its your turn.) */
-    for ( i = 0; i < TF_MAX_CONSUMERS_PERCONTRACT; i++ )
-    {
-      users = &cPtr->consumer_shared_info[i].consumerInfo.syncLockUser;
-
-      /* Wait for the other guy to get a number */
-      do {
-         /* Invalidate Cache for all slots to get information from all consumers*/
-         TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[i], sz1);                  
-            tf_contract_reg32_r((uint32_t *)&user_entering, (uint32_t *) &users->entering);                    
-      }  while ( user_entering);
-
-      /* Wait for the other guy to go if their turn is before you */
-         do {
-         /* Invalidate Cache for all slots to get information from all consumers*/
-         TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[i], sz1);                  
-            tf_contract_reg32_r((uint32_t *)&user_number,   (uint32_t *) &users->number);              
-         } while ( ( user_number != 0) &&                    // This guy is waiting...
-              ( ( user_number < number ) ||             // They have a better number...
-                ( ( user_number == number ) &&          // They have the same number...
-                ( i < user_id )                         // They are more important than you.
-                )
-              )
-            );
-    }
-  }
-   
-  return ( ret );
-
-}
-
-
-/**
- *  @brief Release the lock so that another user may acquire it.
- *
- *  @param[in]   lock         Lock handle.
- *
- *  @param[in]   user_id      ID of the user releasing the lock.
- *
- *  @return      0 if the lock was released successfully, non-zero if an error 
- *               was encountered.
- */
-int32_t syncLockRelease(tf_contract_HANDLE contract_handle, int32_t user_id)
-{
-  tf_contract_t* cPtr = (tf_contract_t *) contract_handle;
-  uint32_t              sz = (sizeof (conSharedInfo_t));
-  int32_t        ret    = SYNC_LOCK_ERROR_NONE;
-  //volatile int32_t number;
-
-  if ( contract_handle == NULL ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_HANDLE;
-       return (ret);
-  }
-
-  if ( ( user_id < 0) || (user_id >= TF_MAX_CONSUMERS_PERCONTRACT) ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_USER_ID;
-       return (ret);
-  }
-  
-  TF_CONTRACT_osalBeginMemAccess(&cPtr->consumer_shared_info[user_id], sz); 
-  tf_contract_reg32_r((uint32_t *)&number,   (uint32_t *) &cPtr->consumer_shared_info[user_id].consumerInfo.syncLockUser.number);  
-
-  if ( number == 0 ) {
-    ret = tfLObj.tf_errno = SYNC_LOCK_ERROR_DBL_UNLOCK;
-  }
-  else {
-    number = 0;
-       tf_contract_reg32_w((uint32_t *)&number,   (uint32_t *) &cPtr->consumer_shared_info[user_id].consumerInfo.syncLockUser.number);
-       TF_CONTRACT_osalEndMemAccess(&cPtr->consumer_shared_info[user_id], sz); 
-  }
-
-  return ( ret );
-}
-#endif
 
 static inline int32_t tf_updateRegMask(uint32_t reg_addr, uint32_t reg_mask)
 {
@@ -591,6 +467,11 @@ static inline uint32_t  tf_get_over_run_count(tf_contract_HANDLE contract_handle
   tf_contract_t* contract_ptr = (tf_contract_t *) tf_get_addr(contract_handle);
   uint32_t       over_run_cnt;
 
+  /* Check if contract handle is valid */
+  if (validate_contract_handle(contract_handle)) {
+       return (0xFFFFFFFF);
+  }
+
   /* Cache Invalidate Contract fileds to read in this function */
   TF_CONTRACT_osalBeginMemAccess(&contract_ptr->overrun_count, 128); 
   
@@ -604,6 +485,11 @@ static inline uint32_t  tf_check_log_info_next_buf(tf_contract_HANDLE contract_h
   tf_contract_t* contract_ptr;
   uint32_t       wb_flag;
 
+  /* Check if contract handle is valid */
+  if (validate_contract_handle(contract_handle)) {
+         return (0xFFFFFFFF);
+  }  
+
   contract_ptr = (tf_contract_t*) tf_get_addr(contract_handle);
   TF_CONTRACT_osalBeginMemAccess(&contract_ptr->tf_contractInfo, sizeof (tf_contractInfo_t) );
 
@@ -688,7 +574,7 @@ static inline void tf_contract_init (void* tf_contract_base, uint32_t num)
        /* Get the memory map size */   
        sz = sizeof (tf_contract_t) * num;
 
-    if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_V1_INIT_ARM) == 0
+    if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_BLK_ADDR_TYPE) == TF_CONTRACT_BUF_PHYSICAL_ADDR
        {
                cPtr_base = (tf_contract_t *) TF_CONTRACT_osalMmap (tf_contract_base, sz);
     }
@@ -704,6 +590,9 @@ static inline void tf_contract_init (void* tf_contract_base, uint32_t num)
    {
      memset(cPtr, 0, sizeof(tf_contract_t));
 
+        temp = 0xbabeface;
+        tf_contract_reg32_w(&temp, &cPtr->tf_contractInfo.magic_word);
+
         temp = TRACE_CONTRACT_AVAILABLE;
      tf_contract_reg32_w(&temp, &cPtr->tf_contractInfo.contractState);
         TF_CONTRACT_osalEndMemAccess(cPtr, sizeof (tf_contract_t));
@@ -738,17 +627,18 @@ static inline tf_contract_HANDLE tf_contract_find(void* tf_contract_start_addr,
    tf_contract_t *cPtr;
    uint32_t    num, flag = 0;
    int32_t     val; 
-   uint32_t    magic_word, contractVersion, i, sz;
+   uint32_t    magic_word, i, sz;
    
    num = num_contracts;  
 
    val = strlen(name);
-   if (val == 0) return 0;
+   if (val == 0) 
+      return ((tf_contract_HANDLE)(-1));
 
    sz = sizeof (tf_contract_t) * num;
 
 #ifdef TF_LINUX_USERSPACE   
-   if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_V1_INIT_ARM) == 0
+   if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_BLK_ADDR_TYPE) == TF_CONTRACT_BUF_PHYSICAL_ADDR
    {
          cPtr = (tf_contract_t *) TF_CONTRACT_osalMmap (tf_contract_start_addr, sz);
    }
@@ -759,14 +649,14 @@ static inline tf_contract_HANDLE tf_contract_find(void* tf_contract_start_addr,
    }
 
     if (cPtr == 0)
-        return (0);
+               return ((tf_contract_HANDLE)(-1));
+
     TF_CONTRACT_osalBeginMemAccess(cPtr, sz);  
-    tf_contract_reg32_r(&contractVersion, &cPtr->tf_contractInfo.contractVersion);
     tf_contract_reg32_r(&magic_word, &cPtr->tf_contractInfo.magic_word);
                
-       if ( (contractVersion == TRACE_CONTRACT_VERSION_2) ||
-                (magic_word != 0xbabeface)             )
-          return (0);
+       /* Not a valid contract */
+       if (magic_word != 0xbabeface)
+               return ((tf_contract_HANDLE)(-1));
     
    for (i =0 ; i<num; i++ )
    {
@@ -786,7 +676,7 @@ static inline tf_contract_HANDLE tf_contract_find(void* tf_contract_start_addr,
    }
    else {
       tfLObj.tf_errno = TF_ERRNO_NO_CONTRACT_FOUND;
-      return (0);
+      return ((tf_contract_HANDLE)(-1));
    }
 }  
 
@@ -805,6 +695,9 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
            (contractType > TF_CONTRACT_ARM_ARM) )
            return (NULL);
 
+   if (tf_contractConfig.tf_contract_start_addr == NULL)
+         return (NULL);
+
    TF_CONTRACT_osalEnter();
 
    num = tf_contractConfig.num_contracts;
@@ -813,7 +706,7 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
 
    sz = sizeof (tf_contract_t) * num;
 
-   if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_V1_INIT_ARM) == 0
+   if ((tfLObj.cfg.ctrlBitMap & tf_CONTRACT_BLK_ADDR_TYPE) == TF_CONTRACT_BUF_PHYSICAL_ADDR
    {
           cPtr = (tf_contract_t *) TF_CONTRACT_osalMmap (tf_contractConfig.tf_contract_start_addr, sz);
    }
@@ -823,15 +716,17 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
           cPtr = (tf_contract_t *) tf_contractConfig.tf_contract_start_addr;
    }   
 
-   //printf ("contract start address =0x%x\n", cPtr);   
-   
    for (i =0 ; i<num; i++ )
    {
      TF_CONTRACT_osalBeginMemAccess(&cPtr->tf_contractInfo, 128);
      tf_contract_reg32_r(&tmp, &cPtr->tf_contractInfo.contractState);
      if (tmp == TRACE_CONTRACT_AVAILABLE) 
      {
-    //    printf ("TF_CONTRACT_CREATE: cptr=0x%x, cPtr->tf_contractInfo.contractType=%d\n", cPtr, cPtr->tf_contractInfo.contractType);
+        /* set up the name */
+        if (setupName(cPtr->name, name) != 0) {
+          break;    
+        }
+               
         flag = 1;
        tmp = TRACE_CONTRACT_NOT_AVAILABLE;
                tf_contract_reg32_w(&tmp, &cPtr->tf_contractInfo.contractState);
@@ -842,8 +737,7 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
 
    if (flag == 1)
    {
-     /* set up the name */
-     strcpy(cPtr->name, name);
+        
         TF_CONTRACT_osalEndMemAccess(cPtr->name, 128);
      
      /* Ring Buffer Setup */  
@@ -865,9 +759,6 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
         tmp = (uint32_t) contractType; /* contract type, during start up */
         tf_contract_reg32_w(&tmp, &cPtr->tf_contractInfo.contractType);         
 
-        tmp = 0xbabeface;
-     tf_contract_reg32_w(&tmp, &cPtr->tf_contractInfo.magic_word);     
-        
         TF_CONTRACT_osalEndMemAccess(&cPtr->tf_contractInfo, 128);
         
         tmp = tf_contractConfig.num_ringbufs - 1;
@@ -897,7 +788,7 @@ static inline tf_contract_HANDLE tf_contract_create(tf_contractConfig_t tf_contr
    }
    else {
     tfLObj.tf_errno = TF_ERRNO_ALL_CONTRACTS_FULL;     
-    return (0);
+    return ((tf_contract_HANDLE) (-1));
    }
 }    
 
@@ -1138,9 +1029,15 @@ tf_consStatus_e tf_consumerGetContractHandle(tf_cons_HANDLE cHandle, tf_contract
    tf_consInst_t*       inst = (tf_consInst_t *) cHandle;
 
    if (cHandle == NULL)
-     return (TF_CONSUMER_INVALID_CONTRACT_HANDLE);
+     return (TF_CONSUMER_INVALID_HANDLE);
   
    *contract_handle = (tf_contract_HANDLE) tf_get_offset(inst->contract_ptr);
+
+   /* Check if contract handle is valid */
+   if (validate_contract_handle(contract_handle)) {
+        return (TF_CONSUMER_INVALID_CONTRACT_HANDLE);
+   }   
+   
    return (TF_CONSUMER_SUCCESS);
 }
 
@@ -1151,6 +1048,9 @@ tf_consStatus_e tf_alignConsumer2FrozenProd(tf_consumer_HANDLE cHandle)
     tf_contract_t*   contract_ptr;     
        int32_t          wb_flag;
 
+       if (cHandle == NULL)
+         return (TF_CONSUMER_INVALID_HANDLE);
+
        if (cInst_ptr->trigFlag == 0) 
                cInst_ptr->trigFlag = 1;
        else
@@ -1199,7 +1099,7 @@ tf_consStatus_e tf_consProcess(tf_consumer_HANDLE cHandle)
   int32_t          producer_state;
 
   if (cHandle == NULL) {
-       return (TF_CONSUMER_INVALID_ARGUMENTS);
+       return (TF_CONSUMER_INVALID_HANDLE);
   }
 
   contract_ptr = cInst_ptr->contract_ptr;
@@ -1315,6 +1215,10 @@ tf_consStatus_e tf_consAck(tf_consumer_HANDLE cHandle)
   tf_consInst_t*    cInst_ptr = (tf_consInst_t *)cHandle; 
   tf_contract_t*    contract_ptr;
   consumerInfo_t*   cInfo; 
+
+  if (cHandle == NULL) {
+       return (TF_CONSUMER_INVALID_HANDLE);
+  }
   
   contract_ptr = cInst_ptr->contract_ptr;
   
@@ -1357,6 +1261,10 @@ tf_consStatus_e tf_consDestroy(tf_consumer_HANDLE cHandle)
   uint32_t                      num_consumers;
   uint32_t                      magic_id;
 
+  if (cHandle == NULL) {
+       return (TF_CONSUMER_INVALID_HANDLE);
+  }
+
   TF_CONTRACT_osalEnter();  
 
   contract_ptr  = cInst_ptr->contract_ptr;
@@ -1411,8 +1319,12 @@ tf_consumer_HANDLE tf_consCreate(tf_consConfig_t   config)
   int32_t                       slot_id;
   TF_CONTRACT_osalEnter();
 
-  if ( (config.contract_handle  == NULL)                 ||
-       (config.sendFxn          == NULL)                 ||
+  /* Check if contract handle is valid, otherwise return NULL */
+  if (validate_contract_handle(config.contract_handle)) {
+       return (NULL);
+  }   
+  
+  if ( (config.sendFxn          == NULL)                 ||
        (config.contract_handle  == NULL) ) 
   {
     /* Un supported slot id, can not fit */
@@ -1604,6 +1516,14 @@ void tf_contractGetInfo(tf_contract_HANDLE handle, tf_contractGetInfo_t* info)
   consumerInfo_t    *cInfo;  
   int               i;
  
+  if (info == NULL) {
+    return;
+  }
+
+  /* Check if contract handle is valid */
+  if (validate_contract_handle(handle)) {
+    return;
+  }     
 
   TF_CONTRACT_osalBeginMemAccess(&cPtr->tf_contractInfo, 128);
   tf_contract_reg32_r(&info->contractState, &cPtr->tf_contractInfo.contractState); 
@@ -1685,6 +1605,11 @@ void TF_CONTRACT_INIT(void* tf_contract_base, uint32_t num)
   tf_contract_init(tf_contract_base, num);
 }
 
+tf_contract_HANDLE tf_newContract(tf_contractConfig_t tf_contractConfig) 
+{
+  return(tf_new_contract(tf_contractConfig));
+}
+
 tf_contract_HANDLE TF_NEW_CONTRACT(tf_contractConfig_t tf_contractConfig) 
 {
   return(tf_new_contract(tf_contractConfig));
@@ -1702,10 +1627,16 @@ tf_prodStatus_e tf_prodGetContractHandle(tf_producer_HANDLE pHandle, tf_contract
    /* Producer is not yet created, so return the same buffer */
    if (pHandle == NULL) {
          tfLObj.tf_errno = TF_ERRNO_INVALID_PRODUCER_HANDLE;   
-            return (TF_PRODUCER_INVALID_CONTRACT_HANDLE);
+            return (TF_PRODUCER_INVALID_HANDLE);
    }
    
    *contract_handle = (tf_contract_HANDLE) tf_get_offset(prodInst->contract_ptr);
+
+   /* Check if contract handle is valid */
+   if (validate_contract_handle(contract_handle)) {
+        return (TF_PRODUCER_INVALID_CONTRACT_HANDLE);
+   } 
+   
    return (TF_PRODUCER_PROD_SUCCESS);
 }
 
@@ -1721,6 +1652,9 @@ void tf_prodNotifyConsumers(tf_producer_HANDLE pHandle)
   uint32_t          numNotify;
   consumerInfo_t*   cInfo_ptr;
   uint32_t          temp;  
+
+  if (pHandle == NULL)
+        return;
  
   prodInst = (tf_prodInst_t*) pHandle;
 
@@ -1861,7 +1795,10 @@ int32_t tf_prodUpdateConsumers (tf_producer_HANDLE  pHandle)
   tf_prodInst_t*    prodInst = (tf_prodInst_t *) pHandle;
   tf_contract_t*    contract_ptr;
   uint32_t          i, num_consumers;
+
+  if (pHandle == NULL)
+        return (-1);
+  
   contract_ptr = prodInst->contract_ptr;
 
   /* Update num of consumers information from the contract */
@@ -1893,6 +1830,9 @@ tf_prodStatus_e tf_prodDestroy(tf_producer_HANDLE pHandle)
   tf_prodInst_t*        pInst = (tf_prodInst_t *) pHandle;
   uint32_t              loc_var;
 
+  if (pHandle == NULL)
+        return (TF_PRODUCER_INVALID_HANDLE);
+
   contract_ptr = pInst->contract_ptr;
 
   TF_CONTRACT_osalBeginMemAccess(&contract_ptr->tf_contractInfo, sizeof (tf_contractInfo_t));
@@ -1935,8 +1875,11 @@ void tf_prodSetOOBData(tf_contract_HANDLE cHandle, uint8_t* data)
 void* tf_prodGetCurBuf(tf_producer_HANDLE pHandle)
 {
   tf_prodInst_t*        pInst   = (tf_prodInst_t*)pHandle;
-  uint32_t cur_index            = pInst->buf_info.current_index;
 
+  if (pHandle == NULL)
+        return (NULL);
+  
+  uint32_t cur_index            = pInst->buf_info.current_index;
   return (pInst->buf_info.buf_ptr[cur_index]);
 
 }
@@ -1945,6 +1888,10 @@ void* tf_prodGetCurBuf(tf_producer_HANDLE pHandle)
 void tf_prodGetOOBData(tf_contract_HANDLE cHandle, uint8_t* data)
 {
   tf_contract_t* contract_ptr = (tf_contract_t*) tf_get_addr(cHandle);  
+  if (validate_contract_handle(cHandle)) {
+       return;
+  }
+  
   tf_contract_snapshot_smem((void*)contract_ptr->oob_info, (void*)data , TF_CONTRACT_OOB_SIZE_BYTES);
   return;
 }
@@ -1962,9 +1909,12 @@ tf_producer_HANDLE tf_prodCreate
   tf_prodInst_t*      pInst;
   tf_producer_HANDLE  tf_producer_handle;
   uint32_t            sz;
- // uint32_t            temp;
   uint8_t*            base_ptr;  
   int                 num_buf;
+
+  if (validate_contract_handle(config.contract_handle)) {
+       return (NULL);
+  }
   
   tf_producer_handle = TF_PRODUCER_osalMemAlloc(TF_PRODUCER_INST_SIZE, TF_PRODUCER_INST_ALIGN);
 
@@ -2211,6 +2161,9 @@ Ptr tf_prodBufExchange (tf_producer_HANDLE pHandle, uint8_t *full)
  ***********************************************************************************/
 void tf_systemCfg (tf_StartCfg_t *startCfg)
 {
+    if (startCfg == NULL)
+               return;
+       
     tfLObj.cfg = *startCfg;
        tfLObj.tf_errno = 0;
 }
index ed46f1818b4a3172796b67c73d872ffd0459a68e..d6111b9892d9ec6ec68bc44129ee5bd90390f2b4 100755 (executable)
@@ -94,7 +94,7 @@ int initTraceFrameworkContracts_ver2(void)
                tfContractConfig.num_ringbufs       = UTF_NUM_RINGBUFS;\r
                tfContractConfig.ringbuf_size       = UTF_SIZE_RINGBUF;                                 \r
                name                                = tfuTestGlobalContractsV2[i].name;\r
-               tfContractHandle                    = TF_NEW_CONTRACT(tfContractConfig);\r
+               tfContractHandle                    = tf_newContract(tfContractConfig);\r
 \r
                if (tfContractHandle == NULL)\r
                {\r
@@ -282,7 +282,8 @@ void traceFrameworkStartCfg(int isMaster)
    * "NON ARM CONTRACTS" that existed earlier\r
    */\r
   startCfg.instPoolBaseAddr = fwShmHandle;\r
-  startCfg.ctrlBitMap      |= tf_CONTRACT_V1_INIT_ARM; /* Indicate that ARM initializes contract version 1 */\r
+  startCfg.instPoolSize     = FW_TEST_SHARED_MEMORY_SIZE;\r
+  startCfg.ctrlBitMap      |= TF_CONTRACT_BUF_NOT_PHYSICAL_ADDR; /* Indicate that contract block base is Virtual address for contract version 1 */\r
   tf_systemCfg (&startCfg);\r
 }\r
 \r
index 810e26c2c65c9b5082801f24d1162da149b3c875..418daf1d3b5e89ddfb44fecfe01942471f094232 100755 (executable)
@@ -590,7 +590,7 @@ int initTraceFrameworkContracts_ver2(void)
                        tfContractConfig.num_ringbufs       = UTF_NUM_RINGBUFS;\r
                tfContractConfig.ringbuf_size       = UTF_SIZE_RINGBUF;                 \r
                }\r
-               tfContractHandle                    = TF_NEW_CONTRACT(tfContractConfig);\r
+               tfContractHandle                    = tf_newContract(tfContractConfig);\r
                //tfuTestGlobalContractsV2[i].tf_contract_handle =  tfContractHandle;\r
                if (tfContractHandle == NULL)\r
                {\r
old mode 100644 (file)
new mode 100755 (executable)
index 7754ee1..d9b48df
--- a/tf_loc.h
+++ b/tf_loc.h
@@ -46,44 +46,21 @@ extern "C" {
 
 
 #include <string.h>
+
 /* OSAL Includes */
-#include <ti/instrumentation/traceframework/contract_osal.h>
+#include <contract_osal.h>
 
 /** @addtogroup TRACEFRAMEWORK_SYMBOL
 @{
 */
 
 /**
- * @brief   maximum consumers allowed per contract
- */
-#define  TF_MAX_CONSUMERS_PERCONTRACT      4
-
-/**
- * @brief   Alignment for the tf_contract memory
- */
-
-#define  TF_CONTRACT_BUFS_ALIGN            128
-
-/**
- * @brief   number of bytes allocated for the name of the contract
- */
-
-#define  TF_CONTRACT_NAME_SIZE_BYTES            128
-
-
-/**
- * @brief   number of bytes allocated for the Out of Band information
- */
-
-#define  TF_CONTRACT_OOB_SIZE_BYTES            128
-
-/**
- * @brief   maximum number of buffers in the ring for the trace framework's producer instance
+ * @brief   maximum number of buffers in the ring handled by the trace framework's producer instance
  */
 #define TF_PROD_MAX_NUM_BUF             1024
 
 /**
- * @brief   Maximum number of buffers that can be handled by the Trace Framework's consumer instance 
+ * @brief   Maximum number of buffers in the ring handled by the Trace Framework's consumer instance 
  */
 #define TF_CONSUMER_MAX_NUM_BUF      1024
 
@@ -102,14 +79,11 @@ extern "C" {
  */ 
 /*@{*/
 /**
- *  @def  tf_CONTRACT_V1_INIT_ARM
- *        Control Info -- 0: The contract block (version 1) is initialized by DSP, 
- *                           hence contract base physical address needs to be passed onto ARM consumers
- *                        1: The contract block (version 1) is initialized by ARM, 
- *                           hence contract base virtual  address can to be passed onto ARM consumers 
- *                          - this feature enables only ARM Producers and ARM Consumers
+ *  @def  tf_CONTRACT_BLK_ADDR_TYPE
+ *        Control Info -- 0: The contract block (version 1) base is physical address 
+ *                        1: The contract block (version 1) base is virtual  address 
  */
-#define tf_CONTRACT_V1_INIT_ARM             0x0001 
+#define tf_CONTRACT_BLK_ADDR_TYPE    0x0001 
 
 /*@}*/
 /** @} */
@@ -120,6 +94,7 @@ extern "C" {
 typedef struct {
   void*     instPoolBaseAddr;        /**< Base address of the global shared memory pool from which global 
                                                LLD instance & channel instance memory is allocated */
+  uint32_t  instPoolSize;            /**< Pool size of the global shared memory */                                                                                             
   uint32_t  ctrlBitMap;              /**< Control bit map @ref tfCtrlBitMap */                                                                                                 
 } tf_StartCfg_t;
 
@@ -289,7 +264,7 @@ typedef struct
  *        Do not change the order the elements in the contract area 
  */
  typedef struct tf_contract{
-    char               name[TF_CONTRACT_NAME_SIZE_BYTES];   /**< name of the tf_contract - @n@b WARNING: @n deprecated with contract version TRACE_CONTRACT_VERSION_2 */
+    char               name[128];   /**< name of the tf_contract - @n@b WARNING: @n deprecated with contract version TRACE_CONTRACT_VERSION_2 */
        
     tf_contractInfo_t  tf_contractInfo;     /**< tf_contract information describing the ring buffer and type */ 
        uint8_t            pad1[128 - sizeof (tf_contractInfo_t)];
@@ -303,9 +278,10 @@ typedef struct
     uint32_t           num_consumers;     /**< number of consumers registered in the tf_contract */
     uint8_t            pad4[128 - sizeof (uint32_t)];
        
-    conSharedInfo_t    consumer_shared_info[TF_MAX_CONSUMERS_PERCONTRACT];     /**< List describing consumer's shared information */
+    conSharedInfo_t    consumer_shared_info[4];     /**< List describing consumer's shared information */
        
-    uint8_t            oob_info[128];  /**< 128 bytes of out of band data provided for application */
+    uint8_t            oob_info[128];  /**< 128 bytes of out of band data provided for application, 
+                                                                    trace framework does not alter information in this area */
        
     uint32_t           overrun_count;     /**< producer's over run count on the ring buffers */
     uint8_t            pad5[128 - sizeof (uint32_t)];
diff --git a/tfver.h b/tfver.h
index 11cd3fb1dbe67e72403b39d7f11dce4a549ac949..25d60cc0c30f0ba010110298ebf431abb348d541 100644 (file)
--- a/tfver.h
+++ b/tfver.h
@@ -51,13 +51,13 @@ extern "C" {
  * format:
  *  0xAABBCCDD -> Arch (AA); API Changes (BB); Major (CC); Minor (DD)
  */
-#define TF_DRV_VERSION_ID                     (0x01010100)
+#define TF_DRV_VERSION_ID                     (0x01010101)
 
 /**
  * @brief   This is the version string which describes the TF driver along with the
  * date and build information.
  */
-#define TF_DRV_VERSION_STR                    "TF Driver Revision: 01.01.01.00"
+#define TF_DRV_VERSION_STR                    "TF Driver Revision: 01.01.01.01"
 
 
 #ifdef __cplusplus
index ee07e4c57ac122b4b3b2dd9ab0862f01ca426d85..7f0673ec953a1c758eee154e700461fc29097b34 100755 (executable)
@@ -58,11 +58,17 @@ extern "C" {
 /**
  * @brief   Alignment for the tf_contract memory
  */
+#define  TF_CONTRACT_BUFS_ALIGN                 128
+
+/**
+ * @brief   maximum consumers allowed per contract
+ */
+#define  TF_MAX_CONSUMERS_PERCONTRACT             4
 
-#define  TF_CONTRACT_BUFS_ALIGN            128
 
 /**
- * @brief   number of bytes allocated for the name of the contract
+ * @brief   number of bytes allocated for the name of the contract (applicable only for contract version 1)
+ *          since contract version 2 does not handle name within traceframework
  */
 
 #define  TF_CONTRACT_NAME_SIZE_BYTES            128
@@ -70,6 +76,9 @@ extern "C" {
 
 /**
  * @brief   number of bytes allocated for the Out of Band information
+ *          Out of band information is really for the application to keep some information in the traceframework contract
+ *          and retrive it from either producer/consumers as it is. Traceframework does not alter any information
+ *          stored in 
  */
 
 #define  TF_CONTRACT_OOB_SIZE_BYTES            128
@@ -227,8 +236,10 @@ tf_contract_HANDLE tf_contractCreate(tf_contractConfig_t tf_contractConfig, char
  *  @n@b tf_newContract
  *
  *  @b  brief
- *  @n  New API added to create the contract between producer/consumer instances
+ *  @n  API added to create the contract between producer/consumer instances
  *      This API is applicable for the contract version TRACE_CONTRACT_VERSION_2
+ *      Application needs to maintain any names associated with this contract handle 
+ *      outside traceframework
  *
  *  @param[in]  tf_contractConfig
  *      tf_contract configuration structure
@@ -314,7 +325,7 @@ uint32_t  tf_getOverRunCount(tf_contract_HANDLE contract_handle);
  */
 uint32_t  tf_isLogInfoNextBuf (tf_contract_HANDLE contract_handle);
 
-/*
+/**
  * ============================================================================
  *  @n@b tf_contractGetInfo
  *
@@ -323,7 +334,7 @@ uint32_t  tf_isLogInfoNextBuf (tf_contract_HANDLE contract_handle);
  *
  *      Application Requirements:
  *      Application would need to create valid contract handle before calling this function
- *  @param[in]  hanle
+ *  @param[in]  handle
  *      trace framework contract handle
  *
  *  @param[in]  info
@@ -336,7 +347,7 @@ uint32_t  tf_isLogInfoNextBuf (tf_contract_HANDLE contract_handle);
  */
 void tf_contractGetInfo(tf_contract_HANDLE handle, tf_contractGetInfo_t* info);
 
-/*
+/**
  * ============================================================================
  *  @n@b tf_systemCfg
  *
@@ -344,7 +355,7 @@ void tf_contractGetInfo(tf_contract_HANDLE handle, tf_contractGetInfo_t* info);
  *  @n starts the system with start configurations 
  *
  *      Application Requirements:
- *      Application would need to call this API with proper startCfg arguments
+ *      Application would need to call this API once per process/core with proper startCfg arguments
  *      before Contract Create, Produer Create and Consumer Create functions
  *
  *  @param[in]  startCfg
old mode 100644 (file)
new mode 100755 (executable)
index ebc24b0..c7320b8
@@ -87,9 +87,25 @@ extern "C" {
  *
  * @subsection Ring_Contract Contract
  *
- * Contract is a shared memory area between the producer and multiple consumers. The layout
- * for the contract memory is as below.
+ * Contract is a shared memory area between the producer and multiple consumers. 
+ * Traceframework supports two contract versions.
+ * - Contract Version 1: All the contracts in the system are in one contiguous big chunk of the memory. Either DSP or ARM needs to 
+ * create that contiguous pool and needs to initialize it via trace framework provided APIs. 
+ *   - @ref tf_contractInit - to initialize the contract memory pool
+ *   - @ref tf_contractCreate - to create the named contract 
+ *   - @ref tf_contractFind - to find the contract by name in producer/consumer functions. 
+ * Please note that the contracts created under this version are named contracts. Traceframework internally handles the name of the contracts.
+ *   - Limitations:
+ *      - Requires big chunk of contiguous memory
+ *      - When ARM initializes the Contract Pool (concept of virtual memory), DSPs do not get to know the physical base address of the contract
+ * of the contracts. Hence every contract created under version 1 
+ * - Contract Version 2: Handling of name within the contracts are removed. The association of name to the contract handle needs to be done
+ * outside traceframework library. There is no need to pre-allocate the big contract chunk of memory. Contracts can be created as and when needed
+ * on either DSP or ARM using the below traceframework provided APIs.
+ *   - @ref tf_newContract - to initialize, create the new contract
+ *   
  * @verbatim
+        The layout for the contract memory is as below.
           
      +-------+----------------------------------------------------------------------------------------------------------------+
      | Line1 |   Contract name (128 Bytes)                                                                                    |
@@ -106,24 +122,24 @@ extern "C" {
      | Line5 | Number of Consu |                                                                                              |
      |       | -ers (4 bytes)  | Padding (124 bytes)                                                                          |
      +-------+-----------------+--------------------+-------------------+--------------------+--------------------------------+
-     | Line6 | Cons1MagicID    | Cons1_last_free    | Cons1_Notify Reg  | Cons1 Notfy Method | Cons1 Local CallBk| Padding for|                                                                                             |
+     | Line6 | Cons1MagicID    | Cons1_last_free    | Cons1_Notify Reg  | Cons1 Notfy Method | Cons1 Local CallBk| Padding for|
      |       | (4 bytes)       | Buf Index (4 Bytes)| Mask (4 bytes)    | (4 Bytes)          | Function (4 Bytes)| 104 bytes  |
      +-------+-----------------+--------------------+-------------------+--------------------+--------------------------------+
-     | Line7 | Cons2MagicID    | Cons2_last_free    | Cons2_Notify Reg  | Cons2 Notfy Method | Cons2 Local CallBk| Padding for|                                                                                             |
+     | Line7 | Cons2MagicID    | Cons2_last_free    | Cons2_Notify Reg  | Cons2 Notfy Method | Cons2 Local CallBk| Padding for|
      |       | (4 bytes)       | Buf Index (4 Bytes)| Mask (4 bytes)    | (4 Bytes)          | Function (4 Bytes)| 104 bytes  |
      +-------+-----------------+--------------------+-------------------+--------------------+--------------------------------+
-     | Line8 | Cons3MagicID    | Cons3_last_free    | Cons3_Notify Reg  | Cons3 Notfy Method | Cons3 Local CallBk| Padding for|                                                                                             |
+     | Line8 | Cons3MagicID    | Cons3_last_free    | Cons3_Notify Reg  | Cons3 Notfy Method | Cons3 Local CallBk| Padding for|
      |       | (4 bytes)       | Buf Index (4 Bytes)| Mask (4 bytes)    | (4 Bytes)          | Function (4 Bytes)| 104 bytes  |
      +-------+-----------------+--------------------+-------------------+--------------------+--------------------------------+
-     | Line9 | Cons4MagicID    | Cons4_last_free    | Cons4_Notify Reg  | Cons4 Notfy Method | Cons4 Local CallBk| Padding for|                                                                                             |
+     | Line9 | Cons4MagicID    | Cons4_last_free    | Cons4_Notify Reg  | Cons4 Notfy Method | Cons4 Local CallBk| Padding for|
      |       | (4 bytes)       | Buf Index (4 Bytes)| Mask (4 bytes)    | (4 Bytes)          | Function (4 Bytes)| 104 bytes  |
      +-------+-----------------+--------------------+-------------------+--------------------+--------------------------------+
      | Line10|   Out of Band data Information (128 Bytes)                                                                     |
      +-------+----------------------------------------------------------------------------------------------------------------+
 
  Contract Name Field
-    Line 1 in the contract is reserved for the name of the contract. Few examples of the
-    contract name are,
+    Line 1 in the contract is reserved for the name of the contract. This filed is applicable only for Contract version 1.
+    Few examples of the contract name are,
     1. UIA_CONTRACT_CORE0,
     2. UIA_CONTRACT_CORE1,
     3. UIA_CONTRACT_CORE2,
@@ -156,11 +172,19 @@ extern "C" {
  * - The elements in the contract memory are cache line aligned.
  * 
  * @subsection Rebuilding Rebuilding the Libraries
- * Please follow the below steps to rebuild the libraries
- * - Setup the build environment (sample environment setting is provided as in pdk build environment)
- * - cd "\ti\pdk_##_1_00_##_##\packages"
- * - gmake -C ti / instrumentation / traceframework LIBDIR=./lib clean
- * - gmake -C ti / instrumentation / traceframework LIBDIR=./lib all
+ * Please follow the below steps to rebuild the libraries 
+ * - for DSP side
+ *   - Setup the build environment (sample environment setting is provided as in pdk build environment)
+ *   - cd "\ti\pdk_##_1_00_##_##\packages"
+ *   - gmake -C ti / instrumentation / traceframework LIBDIR=./lib clean
+ *   - gmake -C ti / instrumentation / traceframework LIBDIR=./lib all
+ * - for ARM side
+ *   - export DEVICE=device (e.g., k2h)
+ *   - export CROSS_TOOL_INSTALL_PATH=<croos_tool_install_path> (e.g., /opt/linaro-2013.03/bin)
+ *   - export CROSS_TOOL_PRFX= <cross_tool_prefix> (e.g., for linaro 2013.03 arm-linux-gnueabihf-)
+ *   - export CUIA_INSTALL_DIR=<where cuia install can be found> (e.g., devkit base path or actual cuia install location like $HOME/cuia_1_00_00_13)
+ *   - export PDK_INSTALL_PATH=<current_working_directory>
+ *   - make -C ti/instrumentation/traceframework -f makefile_armv7 clean all
  */
 
 #include <string.h>