コード例 #1
0
ファイル: init.c プロジェクト: Avanznow/rtems
static void test_chain_first_and_last(void)
{
  rtems_chain_control   chain;
  rtems_chain_node      node1, node2;
  rtems_chain_node     *cnode;

  rtems_chain_initialize_empty( &chain );
  rtems_chain_append( &chain, &node1 );
  rtems_chain_insert( &node1, &node2 );

  puts( "INIT - Verify rtems_chain_is_first" );
  cnode = rtems_chain_first(&chain);  
  rtems_test_assert( rtems_chain_is_first( cnode ) );

  puts( "INIT - Verify rtems_chain_is_last" );
  cnode = rtems_chain_last(&chain);
  rtems_test_assert( rtems_chain_is_last( cnode ) );

  cnode = rtems_chain_get_first_unprotected( &chain );
  rtems_test_assert( cnode == &node1 );
  cnode = rtems_chain_first( &chain );
  rtems_test_assert( cnode == &node2 );
  cnode = rtems_chain_last( &chain );
  rtems_test_assert( cnode == &node2 );
}
コード例 #2
0
ファイル: rtl-obj.c プロジェクト: AlexShiLucky/rtems
bool
rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
                           int              section,
                           const char*      name,
                           size_t           size,
                           off_t            offset,
                           uint32_t         alignment,
                           int              link,
                           int              info,
                           uint32_t         flags)
{
  rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
                                                    sizeof (rtems_rtl_obj_sect_t), true);
  if (!sect)
  {
    rtems_rtl_set_error (ENOMEM, "adding allocated section");
    return false;
  }
  sect->section = section;
  sect->name = rtems_rtl_strdup (name);
  sect->size = size;
  sect->offset = offset;
  sect->alignment = alignment;
  sect->link = link;
  sect->info = info;
  sect->flags = flags;
  sect->base = NULL;
  rtems_chain_append (&obj->sections, &sect->node);

  if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
    printf ("rtl: sect: %-2d: %s\n", section, name);

  return true;
}
コード例 #3
0
static void
bdbuf_tests_task_0_test_7 (bdbuf_task_control* tc)
{
  rtems_status_code   sc;
  bool                passed;
  int                 i;
  rtems_bdbuf_buffer* bd;
  rtems_chain_control buffers;
  dev_t               device;

  /*
   * Set task control's passed to false to handle a timeout.
   */
  tc->passed = false;
  passed = true;

  /*
   * Clear any disk settings.
   */
  bdbuf_clear_disk_driver_watch (tc);
  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);

  device = rtems_filesystem_make_dev_t (tc->major, tc->minor);

  /*
   * Get the blocks 0 -> 4 and hold them.
   */
  rtems_chain_initialize_empty (&buffers);

  for (i = 0; (i < 5) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
    sc = rtems_bdbuf_get (device, i, &bd);
    if (!bdbuf_test_print_sc (sc, true))
      passed = false;

    rtems_chain_append (&buffers, &bd->link);
  }

  for (i = 0; (i < 5) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
                       tc->name, i);
    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
    passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
                                  true);
  }

  if (passed)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: ",
                       tc->name, i,
                       rtems_filesystem_dev_major_t (device),
                       rtems_filesystem_dev_minor_t (device));
    passed = bdbuf_test_print_sc (rtems_bdbuf_syncdev (device), true);
  }

  tc->passed = passed;
  tc->test = 0;
}
コード例 #4
0
ファイル: rap.c プロジェクト: ChOr82/RTEMS
static rtems_rap_app_t*
rtems_rap_app_alloc (void)
{
    rtems_rap_app_t* app = malloc (sizeof (rtems_rap_app_t));
    memset (app, 0, sizeof (rtems_rap_app_t));
    rtems_chain_append (&rap_.apps, &app->node);
    return app;
}
コード例 #5
0
ファイル: rtl-sym.c プロジェクト: gedare/rtems
static void
rtems_rtl_symbol_global_insert (rtems_rtl_symbols_t* symbols,
                                rtems_rtl_obj_sym_t* symbol)
{
  uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name);
  rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets],
                      &symbol->node);
}
コード例 #6
0
ファイル: init.c プロジェクト: 0871087123/rtems
static void test_chain_with_empty_check(void)
{
  rtems_chain_control chain;
  rtems_chain_node a;
  rtems_chain_node b;
  rtems_chain_node *p;
  bool empty;

  puts( "INIT - Verify rtems_chain_append_with_empty_check" );
  rtems_chain_initialize_empty( &chain );
  empty = rtems_chain_append_with_empty_check( &chain, &a );
  rtems_test_assert( empty );
  empty = rtems_chain_append_with_empty_check( &chain, &a );
  rtems_test_assert( !empty );

  puts( "INIT - Verify rtems_chain_prepend_with_empty_check" );
  rtems_chain_initialize_empty( &chain );
  empty = rtems_chain_prepend_with_empty_check( &chain, &a );
  rtems_test_assert( empty );
  empty = rtems_chain_prepend_with_empty_check( &chain, &a );
  rtems_test_assert( !empty );
  empty = rtems_chain_prepend_with_empty_check( &chain, &b );
  rtems_test_assert( !empty );

  puts( "INIT - Verify rtems_chain_get_with_empty_check" );
  rtems_chain_initialize_empty( &chain );
  empty = rtems_chain_get_with_empty_check( &chain, &p );
  rtems_test_assert( empty );

  rtems_chain_append( &chain, &a );
  rtems_chain_append( &chain, &b );
  empty = rtems_chain_get_with_empty_check( &chain, &p );
  rtems_test_assert( !empty );
  rtems_test_assert( p == &a );
  empty = rtems_chain_get_with_empty_check( &chain, &p );
  rtems_test_assert( empty );
  rtems_test_assert( p == &b );
}
コード例 #7
0
ファイル: irq-server.c プロジェクト: AndroidMarv/rtems
static void bsp_interrupt_server_trigger(void *arg)
{
  bsp_interrupt_server_entry *e = arg;

  bsp_interrupt_vector_disable(e->vector);

  if (e->node.next == NULL) {
    rtems_chain_append(&bsp_interrupt_server_chain, &e->node);
  } else {
    ++bsp_interrupt_server_errors;
  }

  rtems_event_send(bsp_interrupt_server_id, BSP_INTERRUPT_EVENT);
}
コード例 #8
0
ファイル: init.c プロジェクト: Dipupo/rtems
rtems_task Init(
  rtems_task_argument ignored
)
{
  rtems_chain_control  chain1;
  rtems_chain_node    *p;
  test_node            node1, node2;
  int                  id;

  TEST_BEGIN();

  puts( "Init - Initialize chain empty" );
  rtems_chain_initialize_empty( &chain1 );

  /* verify that the chain append and insert work */
  puts( "INIT - Verify rtems_chain_insert" );
  node1.id = 1;
  node2.id = 2;
  rtems_chain_append( &chain1, &node1.Node );
  rtems_chain_insert( &node1.Node, &node2.Node );

  for ( p = rtems_chain_first(&chain1), id = 1 ;
        !rtems_chain_is_tail(&chain1, p) ;
        p = p->next , id++ ) {
     test_node *t = (test_node *)p;
     if ( id > 2 ) {
       puts( "INIT - TOO MANY NODES ON CHAIN" );
       rtems_test_exit(0);
     }
     if ( t->id != id ) {
       puts( "INIT - ERROR ON CHAIN ID MISMATCH" );
       rtems_test_exit(0);
     }
  }

  test_chain_first_and_last();
  test_chain_with_empty_check();
  test_chain_with_notification();
  test_chain_get_with_wait();
  test_chain_control_layout();
  test_chain_control_initializer();
  test_chain_node_count();
  test_chain_insert_ordered();
  test_chain_iterator();

  TEST_END();
  rtems_test_exit(0);
}
コード例 #9
0
ファイル: rtl-unresolved.c プロジェクト: goetzpf/rtems
static rtems_rtl_unresolv_block_t*
rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved_t* unresolved)
{
    /*
     * The block header contains a record.
     */
    size_t size =
        (sizeof(rtems_rtl_unresolv_block_t) +
         (sizeof(rtems_rtl_unresolv_rec_t) * (unresolved->block_recs - 1)));
    rtems_rtl_unresolv_block_t* block =
        rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
    if (block)
        rtems_chain_append (&unresolved->blocks, &block->link);
    else
        rtems_rtl_set_error (ENOMEM, "no memory for unresolved block");
    return block;
}
コード例 #10
0
ファイル: genpvec.c プロジェクト: 0871087123/rtems
/*
 *  This routine installs one of multiple ISRs for the general purpose
 *  inerrupt.
 */
rtems_isr_entry  set_EE_vector(
  rtems_isr_entry     handler,      /* isr routine        */
  rtems_vector_number vector        /* vector number      */
)
{
  uint16_t         vec_idx  = vector - Score_IRQ_First;
  uint32_t         index;

  assert  (Nodes_Used < NUM_LIRQ_HANDLERS);

  /*
   *  If we have already installed this handler for this vector, then
   *  just reset it.
   */

  for ( index=0 ; index <= Nodes_Used ; index++ ) {
    if ( ISR_Nodes[index].vector == vector &&
         ISR_Nodes[index].handler == handler )
      return NULL;
  }

  /*
   *  Doing things in this order makes them more atomic
   */

  Nodes_Used++;

  index = Nodes_Used - 1;

  ISR_Nodes[index].handler = handler;
  ISR_Nodes[index].vector  = vector;

  /* printf( "Vector Index: %04x, Vector: %d (%x)\n",
          vec_idx, vector, vector); */

  rtems_chain_append( &ISR_Array[vec_idx], &ISR_Nodes[index].Node );

  /*
   * Unmask the interrupt.
   */
  unmask_irq( vec_idx );

  return NULL;
}
コード例 #11
0
ファイル: malloc_deferred.c プロジェクト: AlexShiLucky/rtems
void malloc_deferred_free(
  void *pointer
)
{
  rtems_chain_append(&RTEMS_Malloc_GC_list, (rtems_chain_node *)pointer);
}
コード例 #12
0
int
rtems_rfs_file_open (rtems_rfs_file_system*  fs,
                     rtems_rfs_ino           ino,
                     uint32_t                flags,
                     rtems_rfs_file_handle** file)
{
  rtems_rfs_file_handle* handle;
  rtems_rfs_file_shared* shared;
  int                    rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
    printf ("rtems-rfs: file-open: ino=%" PRId32 "\n", ino);
            
  *file = NULL;

  /*
   * Allocate a new handle and initialise it. Do this before we deal with the
   * shared node data so we do not have to be concerned with reference
   * counting.
   */
  handle = malloc (sizeof (rtems_rfs_file_handle));
  if (!handle)
    return ENOMEM;

  memset (handle, 0, sizeof (rtems_rfs_file_handle));

  rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
      printf ("rtems-rfs: file-open: buffer handle open failed: %d: %s\n",
              rc, strerror (rc));
    free (handle);
    return rc;
  }
  
  /*
   * Scan the file system data list of open files for this ino. If found up
   * the reference count and return the pointer to the data.
   */
  shared = rtems_rfs_file_get_shared (fs, ino);
  if (shared)
  {
    shared->references++;
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
      printf ("rtems-rfs: file-open: ino=%" PRId32 " shared\n", ino);
  }
  else
  {
    /*
     * None exists so create. Copy in the shared parts of the inode we hold in
     * memory.
     */
    shared = malloc (sizeof (rtems_rfs_file_shared));
    if (!shared)
    {
      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
      free (handle);
      return ENOMEM;
    }

    memset (shared, 0, sizeof (rtems_rfs_file_shared));
    
    rc = rtems_rfs_inode_open (fs, ino, &shared->inode, true);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
        printf ("rtems-rfs: file-open: inode open failed: %d: %s\n",
                rc, strerror (rc));
      free (shared);
      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
      free (handle);
      return rc;
    }

    rc = rtems_rfs_block_map_open (fs, &shared->inode, &shared->map);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
        printf ("rtems-rfs: file-open: block map open failed: %d: %s\n",
                rc, strerror (rc));
      rtems_rfs_inode_close (fs, &shared->inode);
      free (shared);
      rtems_rfs_buffer_handle_close (fs, &handle->buffer);
      free (handle);
      return rc;
    }

    shared->references = 1;
    shared->size.count = rtems_rfs_inode_get_block_count (&shared->inode);
    shared->size.offset = rtems_rfs_inode_get_block_offset (&shared->inode);
    shared->atime = rtems_rfs_inode_get_atime (&shared->inode);
    shared->mtime = rtems_rfs_inode_get_mtime (&shared->inode);
    shared->ctime = rtems_rfs_inode_get_ctime (&shared->inode);
    shared->fs = fs;

    rtems_chain_append (&fs->file_shares, &shared->link);

    rtems_rfs_inode_unload (fs, &shared->inode, false);

    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
      printf ("rtems-rfs: file-open: ino=%" PRId32 " share created\n", ino);
  }

  handle->flags  = flags;
  handle->shared = shared;
  
  *file = handle;
  
  return 0;
}
コード例 #13
0
ファイル: mmap.c プロジェクト: SayCV/rtems-rtl
void *mmap(
  void *addr, size_t len, int prot, int flags, int fildes, off_t off
)
{
  struct stat   sb;
  mmap_mapping* mapping;
  ssize_t       r;
  
  /*
   * Clear errno.
   */
  errno = 0;
  
  /*
   * Get a stat of the file to get the dev + inode number and to make sure the
   * fd is ok. The normal libio calls cannot be used because we need to return
   * MAP_FAILED on error and they return -1 directly without coming back to
   * here.
   */
  if ( fstat( fildes, &sb ) < 0 ) {
    errno = EBADF;
    return MAP_FAILED;
  }

  if ( len == 0 ) {
    errno = EINVAL;
    return MAP_FAILED;
  }

  /*
   * Check the type of file we have and make sure it is supported.
   */
  if ( S_ISDIR( sb.st_mode ) || S_ISLNK( sb.st_mode )) {
    errno = ENODEV;
    return MAP_FAILED;
  }
  
  /*
   * We can provide read, write and execute because the memory in RTEMS does
   * not normally have protections but we cannot hide access to memory.
   */
  if ( prot == PROT_NONE ) {
    errno = EINVAL;
    return MAP_FAILED;
  }
  
  /*
   * Check to see if the mapping is valid for the file.
   */
  if ( S_ISREG( sb.st_mode )
       && (( off >= sb.st_size ) || (( off + len ) >= sb.st_size ))) {
    errno = EOVERFLOW;
    return MAP_FAILED;
  }

  /*
   * Obtain the mmap lock. Sets errno on failure.
   */
  if ( !mmap_mappings_lock_obtain( ) )
    return MAP_FAILED;

  if (( flags & MAP_FIXED ) == MAP_FIXED ) {
    rtems_chain_node* node = rtems_chain_first (&mmap_mappings);
    while ( !rtems_chain_is_tail( &mmap_mappings, node )) {
      /*
       * If the map is fixed see if this address is already mapped. At this
       * point in time if there is an overlap in the mappings we return an
       * error.
       */
      mapping = (mmap_mapping*) node;
      if ( ( addr >= mapping->addr ) &&
           ( addr < ( mapping->addr + mapping->len )) ) {
        mmap_mappings_lock_release( );
        errno = ENXIO;
        return MAP_FAILED;
      }
      node = rtems_chain_next( node );
    }
  }

  mapping = malloc( sizeof( mmap_mapping ));
  if ( !mapping ) {
    mmap_mappings_lock_release( );
    errno = ENOMEM;
    return NULL;
  }

  memset( mapping, 0, sizeof( mmap_mapping ));

  mapping->len = len;
  mapping->flags = flags;
  
  if (( flags & MAP_FIXED ) != MAP_FIXED ) {
    mapping->addr = malloc( len );
    if ( !mapping->addr ) {
      mmap_mappings_lock_release( );
      free( mapping );
      errno = ENOMEM;
      return MAP_FAILED;
    }

    /*
     * Do not seek on character devices, pipes or sockets.
     */
    if ( S_ISREG( sb.st_mode ) || S_ISBLK( sb.st_mode ) ) {
      if ( lseek( fildes, off, SEEK_SET ) < 0 ) {
        mmap_mappings_lock_release( );
        free( mapping->addr );
        free( mapping );
        return MAP_FAILED;
      }
    }
  }

  r = read( fildes, mapping->addr, len );

  if ( r != len ) {
    mmap_mappings_lock_release( );
    free( mapping->addr );
    free( mapping );
    errno = ENXIO;
    return MAP_FAILED;
  }

  rtems_chain_append( &mmap_mappings, &mapping->node );

  mmap_mappings_lock_release( );
  
  return mapping->addr;
}
コード例 #14
0
ファイル: init.c プロジェクト: lanzhongheng/rtems
/**
 * Get all the blocks in the pool and hold them. Wake the master to tell it was
 * have the buffers then wait for the master to tell us to release them.
 */
static void
bdbuf_tests_task_0_test_4 (bdbuf_task_control* tc)
{
  rtems_status_code   sc;
  bool                passed;
  size_t              i;
  rtems_bdbuf_buffer* bd;
  rtems_chain_control buffers;
  size_t              num = bdbuf_test_buffer_count ();

  /*
   * Set task control's passed to false to handle a timeout.
   */
  tc->passed = false;
  passed = true;

  /*
   * Clear any disk settings.
   */
  bdbuf_clear_disk_driver_watch (tc);
  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);

  /*
   * Get the blocks 0 -> 4 and hold them.
   */
  rtems_chain_initialize_empty (&buffers);

  for (i = 0; (i < num) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
    sc = rtems_bdbuf_read (tc->dd, i, &bd);
    if (!bdbuf_test_print_sc (sc, true))
      passed = false;

    rtems_chain_append (&buffers, &bd->link);
  }

  /*
   * Wake the master to tell it we have the buffers.
   */
  bdbuf_send_wait_event (tc->name, "wake master", tc->master);

  if (passed)
  {
    bdbuf_sleep (250);

    bdbuf_set_disk_driver_watch (tc, num / 2);

    /*
     * Release half the buffers, wait 500msecs then release the
     * remainder. This tests the swap out timer on each buffer.
     */
    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[0]: unblocks task 1\n",
                       tc->name);
    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
    sc = rtems_bdbuf_release_modified (bd);
    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[0]: ", tc->name);
    passed = bdbuf_test_print_sc (sc, true);
    if (passed)
    {
      for (i = 1; (i < (num / 2)) && passed; i++)
      {
        bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: " \
                           "unblocks task 1\n", tc->name, i);
        bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
        sc = rtems_bdbuf_release_modified (bd);
        bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
                           tc->name, i);
        passed = bdbuf_test_print_sc (sc, true);
        if (!passed)
          break;
      }

      if (passed)
      {
        passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));

        if (passed)
        {
          bdbuf_sleep (500);

          bdbuf_set_disk_driver_watch (tc, num / 2);

          for (i = 0; (i < (num / 2)) && passed; i++)
          {
            bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
                               tc->name, i + (num / 2));
            bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
            passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
                                          true);
            if (!passed)
              break;
          }

          passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));

          if (passed)
          {
            if (!rtems_chain_is_empty (&buffers))
            {
              passed = false;
              bdbuf_test_printf ("%s: buffer chain not empty\n", tc->name);
            }
          }
        }
      }
    }
  }

  tc->passed = passed;
  tc->test = 0;
}
コード例 #15
0
ファイル: init.c プロジェクト: lanzhongheng/rtems
/**
 * Get the blocks 0 -> 4 and hold them. Wake the master to tell it was have the
 * buffers then wait for the master to tell us to release a single buffer.
 * Task 1 will be block waiting for each buffer. It is a higher priority.
 */
static void
bdbuf_tests_task_0_test_2 (bdbuf_task_control* tc)
{
  rtems_status_code   sc;
  bool                passed;
  int                 i;
  rtems_bdbuf_buffer* bd;
  rtems_chain_control buffers;

  /*
   * Set task control's passed to false to handle a timeout.
   */
  tc->passed = false;
  passed = true;

  /*
   * Get the blocks 0 -> 4 and hold them.
   */
  rtems_chain_initialize_empty (&buffers);

  for (i = 0; (i < 5) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
    sc = rtems_bdbuf_get (tc->dd, i, &bd);
    if (!bdbuf_test_print_sc (sc, true))
      passed = false;

    rtems_chain_append (&buffers, &bd->link);
  }

  /*
   * Wake the master to tell it we have the buffers.
   */
  bdbuf_send_wait_event (tc->name, "wake master", tc->master);

  if (passed)
  {
    /*
     * For each buffer we hold wait until the master wakes us
     * and then return it. Task 2 will block waiting for this
     * buffer. It is a higher priority task.
     */
    for (i = 0; (i < 5) && passed; i++)
    {
      sc = bdbuf_wait (tc->name, BDBUF_SECONDS (5));
      if (sc != RTEMS_SUCCESSFUL)
      {
        bdbuf_test_printf ("%s: wait failed: ", tc->name);
        bdbuf_test_print_sc (sc, true);
        passed = false;
        break;
      }
      else
      {
        bdbuf_test_printf ("%s: rtems_bdbuf_release[%d]: unblocks task 1\n",
                           tc->name, i);
        bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
        sc = rtems_bdbuf_release (bd);
        bdbuf_test_printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
        if (!bdbuf_test_print_sc (sc, true))
        {
          passed = false;
          break;
        }
      }
    }
  }

  tc->passed = passed;
  tc->test = 0;
}
コード例 #16
0
ファイル: init.c プロジェクト: lanzhongheng/rtems
static void
bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
{
  rtems_status_code   sc;
  bool                passed;
  int                 i;
  rtems_bdbuf_buffer* bd;
  rtems_chain_control buffers;
  rtems_chain_node*   node;
  rtems_chain_node*   pnode;

  /*
   * Set task control's passed to false to handle a timeout.
   */
  tc->passed = false;
  passed = true;

  /*
   * Clear any disk settings.
   */
  bdbuf_clear_disk_driver_watch (tc);
  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);

  /*
   * Get the blocks 0 -> 4 and hold them.
   */
  rtems_chain_initialize_empty (&buffers);

  for (i = 0; (i < 5) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
    sc = rtems_bdbuf_get (tc->dd, i, &bd);
    if (!bdbuf_test_print_sc (sc, true))
      passed = false;

    rtems_chain_append (&buffers, &bd->link);
  }

  node = rtems_chain_tail (&buffers);
  node = node->previous;

  bd = (rtems_bdbuf_buffer*) node;
  pnode = node->previous;
  rtems_chain_extract (node);
  node = pnode;
  bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
  passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);

  bd = (rtems_bdbuf_buffer*) node;
  pnode = node->previous;
  rtems_chain_extract (node);
  node = pnode;
  bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
  passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);

  for (i = 0; (i < 3) && passed; i++)
  {
    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
                       tc->name, i);
    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
    passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
                                  true);
  }

  if (passed)
  {
    /*
     * Check the block order.
     */
    bdbuf_set_disk_driver_action (tc, BDBUF_DISK_BLOCKS_INORDER);

    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: checking order\n",
                       tc->name, i,
                       tc->major,
                       tc->minor);
    sc = rtems_bdbuf_syncdev (tc->dd);
    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: ",
                       tc->name, i,
                       tc->major,
                       tc->minor);
    passed = bdbuf_test_print_sc (sc, true);
  }

  tc->passed = passed;
  tc->test = 0;
}
コード例 #17
0
ファイル: rtems-rfs-buffer.c プロジェクト: AndroidMarv/rtems
int
rtems_rfs_buffer_handle_release (rtems_rfs_file_system*   fs,
                                 rtems_rfs_buffer_handle* handle)
{
  int rc = 0;

  if (rtems_rfs_buffer_handle_has_block (handle))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
      printf ("rtems-rfs: buffer-release: block=%" PRIu32 " %s refs=%d %s\n",
              rtems_rfs_buffer_bnum (handle),
              rtems_rfs_buffer_dirty (handle) ? "(dirty)" : "",
              rtems_rfs_buffer_refs (handle),
              rtems_rfs_buffer_refs (handle) == 0 ? "BAD REF COUNT" : "");

    if (rtems_rfs_buffer_refs (handle) > 0)
      rtems_rfs_buffer_refs_down (handle);

    if (rtems_rfs_buffer_refs (handle) == 0)
    {
      rtems_chain_extract (rtems_rfs_buffer_link (handle));
      fs->buffers_count--;

      if (rtems_rfs_fs_no_local_cache (fs))
      {
        handle->buffer->user = (void*) 0;
        rc = rtems_rfs_buffer_io_release (handle->buffer,
                                          rtems_rfs_buffer_dirty (handle));
      }
      else
      {
        /*
         * If the total number of held buffers is higher than the configured
         * value remove a buffer from the queue with the most buffers and
         * release. The buffers are held on the queues with the newest at the
         * head.
         *
         * This code stops a large series of transactions causing all the
         * buffers in the cache being held in queues of this file system.
         */
        if ((fs->release_count +
             fs->release_modified_count) >= fs->max_held_buffers)
        {
          rtems_rfs_buffer* buffer;
          bool              modified;

          if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
            printf ("rtems-rfs: buffer-release: local cache overflow:"
                    " %" PRIu32 "\n", fs->release_count + fs->release_modified_count);

          if (fs->release_count > fs->release_modified_count)
          {
            buffer = (rtems_rfs_buffer*) rtems_chain_get (&fs->release);
            fs->release_count--;
            modified = false;
          }
          else
          {
            buffer =
              (rtems_rfs_buffer*) rtems_chain_get (&fs->release_modified);
            fs->release_modified_count--;
            modified = true;
          }
          buffer->user = (void*) 0;
          rc = rtems_rfs_buffer_io_release (buffer, modified);
        }

        if (rtems_rfs_buffer_dirty (handle))
        {
          rtems_chain_append (&fs->release_modified,
                              rtems_rfs_buffer_link (handle));
          fs->release_modified_count++;
        }
        else
        {
          rtems_chain_append (&fs->release, rtems_rfs_buffer_link (handle));
          fs->release_count++;
        }
      }
    }
    handle->buffer = NULL;
  }

  return rc;
}
コード例 #18
0
ファイル: init.c プロジェクト: 0871087123/rtems
static void test_chain_with_notification(void)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_chain_control chain;
  rtems_chain_node a;
  rtems_chain_node b;
  rtems_chain_node *p = (rtems_chain_node *) 1;
  rtems_event_set out = 0;

  puts( "INIT - Verify rtems_chain_append_with_notification" );
  rtems_chain_initialize_empty( &chain );
  sc = rtems_chain_append_with_notification(
    &chain,
    &a,
    rtems_task_self(),
    EVENT
  );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  sc = rtems_chain_get_with_wait( &chain, EVENT, TIMEOUT, &p );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &a );

  rtems_chain_initialize_empty( &chain );

  rtems_chain_append( &chain, &b );
  sc = rtems_chain_append_with_notification(
    &chain,
    &a,
    rtems_task_self(),
    EVENT
  );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &a );

  puts( "INIT - Verify rtems_chain_prepend_with_notification" );
  rtems_chain_initialize_empty( &chain );
  sc = rtems_chain_prepend_with_notification(
    &chain,
    &a,
    rtems_task_self(),
    EVENT
  );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  sc = rtems_chain_get_with_wait( &chain, EVENT, TIMEOUT, &p );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &a );

  rtems_chain_prepend( &chain, &b );
  sc = rtems_chain_prepend_with_notification(
    &chain,
    &a,
    rtems_task_self(),
    EVENT
  );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &a );

  puts( "INIT - Verify rtems_chain_prepend_with_notification" );
  puts( "INIT - Verify rtems_chain_get_with_notification" );
  rtems_chain_initialize_empty( &chain );

  rtems_chain_append( &chain, &b );
  rtems_chain_append( &chain, &a );

  sc = rtems_chain_get_with_notification(&chain, rtems_task_self(), EVENT, &p);
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &b );

  sc = rtems_chain_get_with_notification(&chain, rtems_task_self(), EVENT, &p);
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( p == &a );
  sc = rtems_event_receive(
    EVENT,
    RTEMS_EVENT_ALL | RTEMS_WAIT,
    TIMEOUT,
    &out
  );
  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
  rtems_test_assert( out == EVENT );
}
コード例 #19
0
/*
 *  Create an IMFS filesystem node of an arbitrary type that is NOT
 *  the root directory node.
 */
IMFS_jnode_t *IMFS_create_node(
  rtems_filesystem_location_info_t *parent_loc,
  IMFS_jnode_types_t                type,
  const char                       *name,
  mode_t                            mode,
  const IMFS_types_union           *info
)
{
  IMFS_jnode_t        *node;
  IMFS_jnode_t        *parent;
  IMFS_fs_info_t      *fs_info;

  /*
   *  MUST have a parent node to call this routine.
   */
  if ( parent_loc == NULL )
    return NULL;

  /*
   *  Allocate filesystem node and fill in basic information
   */
  node  = IMFS_allocate_node( type, name, mode & ~rtems_filesystem_umask );
  if ( !node )
    return NULL;

  /*
   *  Set the type specific information
   */
  switch (type) {
    case IMFS_DIRECTORY:
      rtems_chain_initialize_empty(&node->info.directory.Entries);
      break;

    case IMFS_HARD_LINK:
      node->info.hard_link.link_node = info->hard_link.link_node;
      break;

    case IMFS_SYM_LINK:
      node->info.sym_link.name = info->sym_link.name;
      break;

    case IMFS_DEVICE:
      node->info.device.major = info->device.major;
      node->info.device.minor = info->device.minor;
      break;

    case IMFS_LINEAR_FILE:
      node->info.linearfile.size      = 0;
      node->info.linearfile.direct    = 0;

    case IMFS_MEMORY_FILE:
      node->info.file.size            = 0;
      node->info.file.indirect        = 0;
      node->info.file.doubly_indirect = 0;
      node->info.file.triply_indirect = 0;
      break;

    case IMFS_FIFO:
      node->info.fifo.pipe = NULL;
      break;

    default:
      assert(0);
      break;
  }

  /*
   *  This node MUST have a parent, so put it in that directory list.
   */
  parent       = parent_loc->node_access;
  fs_info      = parent_loc->mt_entry->fs_info;

  node->Parent = parent;
  node->st_ino = ++fs_info->ino_count;

  rtems_chain_append( &parent->info.directory.Entries, &node->Node );

  return node;
}
コード例 #20
0
int
rtems_bsd_rc_conf_service_add(const char*               name,
                              const char*               control,
                              rtems_bsd_rc_conf_service entry)
{
  service* srv;
  char*    ctl = NULL;
  char*    s;
  char*    c;

  srv = malloc(sizeof(*srv));
  if (srv == NULL) {
    errno = ENOMEM;
    return -1;
  }

  memset(srv, 0, sizeof(*srv));

  srv->name = strdup(name);
  if (control != NULL) {
    ctl = strdup(control);
    srv->control = ctl;
  }
  srv->entry = entry;

  if (srv->name == NULL || (control != NULL && ctl == NULL)) {
    fprintf(stderr, "error: rc.conf: add service: no memory\n");
    free((void*) srv->control);
    free((void*) srv->name);
    free(srv);
    errno = ENOMEM;
    return -1;
  }

  if (control != NULL) {
    s = c = ctl;

    while (*c != '\0') {
      if (*c == ';') {
        *c = '\0';

        if (strncasecmp("before:", s, sizeof("before:") - 1) == 0) {
          if (srv->before == NULL) {
            srv->before = s + sizeof("before:") - 1;
            s = NULL;
          }
          else {
            fprintf(stderr, "error: rc.conf: add service: repeated 'before'\n");
            c = NULL;
          }
        }
        else if (strncasecmp("after:", s, sizeof("after:") - 1) == 0) {
          if (srv->after == NULL) {
            srv->after = s + sizeof("after:") - 1;
            s = NULL;
          }
          else {
            fprintf(stderr, "error: rc.conf: add service: repeated 'after'\n");
            c = NULL;
          }
        }
        else if (strncasecmp("require:", s, sizeof("require:") - 1) == 0) {
          if (srv->require == NULL) {
            srv->require = s + sizeof("require:") - 1;
            s = NULL;
          }
          else {
            fprintf(stderr, "error: rc.conf: add service: repeated 'require'\n");
            c = NULL;
          }
        }
        else {
          fprintf(stderr, "error: rc.conf: add service: unknown keyword: %s\n", s);
          c = NULL;
        }

        if (c == NULL) {
          free((void*) srv->control);
          free((void*) srv->name);
          free(srv);
          errno = EINVAL;
          return -1;
        }
      }
      else if (s == NULL) {
        s = c;
      }

      ++c;
    }

    if (s != NULL) {
      fprintf(stderr, "error: rc.conf: add service: no ';' found\n");
      free((void*) srv->control);
      free((void*) srv->name);
      free(srv);
      errno = EINVAL;
      return -1;
    }

    /*
     * Place on the services list. The node is removed before being inserted. If
     * there are competing positions the last position is used. As a result
     * handle 'after' before 'before'.
     */
    rtems_chain_prepend(&services, &srv->node);
  }
  else {
    /*
     * No control string, add the end.
     */
    rtems_chain_append(&services, &srv->node);
  }

  /*
   * After.
   */
  if (srv->after != NULL) {
    const char* cc = srv->after;
    while (*cc != '\0') {
      const char* cs = cc;
      size_t      l;
      while (*cc != ',' && *cc != '\0')
        ++cc;
      l = cc - cs;
      if (strncasecmp(cs, "last", l) == 0) {
        fprintf(stderr,
                "error: rc.conf: add service: 'last' in 'after': %s\n",
                control);
        rtems_chain_extract(&srv->node);
        free((void*) srv->control);
        free((void*) srv->name);
        free(srv);
        errno = EINVAL;
        return -1;
      }
      else if (strncasecmp(cs, "first", l) == 0) {
        /* already prepended */
      }
      else {
        rtems_chain_node* node = rtems_chain_first(&services);
        while (!rtems_chain_is_tail(&services, node)) {
          service* ss = (service*) node;
          if (ss != srv &&
              strlen(ss->name) == l && strncasecmp(ss->name, cs, l) == 0) {
            rtems_chain_extract(&srv->node);
            rtems_chain_insert(&ss->node, &srv->node);
            break;
          }
          node = rtems_chain_next(node);
        }
      }
    }
  }

  /*
   * Before.
   */
  if (srv->before != NULL) {
    const char* cc = srv->before;
    while (*cc != '\0') {
      const char* cs = cc;
      size_t      l;
      while (*cc != ',' && *cc != '\0')
        ++cc;
      l = cc - cs;
      if (strncasecmp(cs, "first", l) == 0) {
        fprintf(stderr, "error: rc.conf: add service: 'first' in 'before'\n");
        rtems_chain_extract(&srv->node);
        free((void*) srv->control);
        free((void*) srv->name);
        free(srv);
        errno = EINVAL;
        return -1;
      }
      else if (strncasecmp(cs, "last", l) == 0) {
        rtems_chain_extract(&srv->node);
        rtems_chain_append(&services, &srv->node);
      }
      else {
        rtems_chain_node* node = rtems_chain_first(&services);
        while (!rtems_chain_is_tail(&services, node)) {
          service* ss = (service*) node;
          if (strlen(ss->name) == l && strncasecmp(ss->name, cs, l) == 0) {
            rtems_chain_extract(&srv->node);
            if (rtems_chain_is_first(node))
              rtems_chain_prepend(&services, &srv->node);
            else {
              service* sp = (service*) rtems_chain_previous(node);
              rtems_chain_insert(&sp->node, &srv->node);
            }
            break;
          }
          node = rtems_chain_next(node);
        }
      }
    }
  }

  return 0;
}
コード例 #21
0
ファイル: rtems-rfs-buffer.c プロジェクト: AndroidMarv/rtems
int
rtems_rfs_buffer_handle_request (rtems_rfs_file_system*   fs,
                                 rtems_rfs_buffer_handle* handle,
                                 rtems_rfs_buffer_block   block,
                                 bool                     read)
{
  int rc;

  /*
   * If the handle has a buffer release it. This allows a handle to be reused
   * without needing to close then open it again.
   */
  if (rtems_rfs_buffer_handle_has_block (handle))
  {
    /*
     * Treat block 0 as special to handle the loading of the super block.
     */
    if (block && (rtems_rfs_buffer_bnum (handle) == block))
      return 0;

    if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
      printf ("rtems-rfs: buffer-request: handle has buffer: %" PRIu32 "\n",
              rtems_rfs_buffer_bnum (handle));

    rc = rtems_rfs_buffer_handle_release (fs, handle);
    if (rc > 0)
      return rc;
    handle->dirty = false;
    handle->bnum = 0;
  }

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
    printf ("rtems-rfs: buffer-request: block=%" PRIu32 "\n", block);

  /*
   * First check to see if the buffer has already been requested and is
   * currently attached to a handle. If it is share the access. A buffer could
   * be shared where different parts of the block have separate functions. An
   * example is an inode block and the file system needs to handle 2 inodes in
   * the same block at the same time.
   */
  if (fs->buffers_count)
  {
    /*
     * Check the active buffer list for shared buffers.
     */
    handle->buffer = rtems_rfs_scan_chain (&fs->buffers,
                                           &fs->buffers_count,
                                           block);
    if (rtems_rfs_buffer_handle_has_block (handle) &&
        rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
      printf ("rtems-rfs: buffer-request: buffer shared: refs: %d\n",
              rtems_rfs_buffer_refs (handle) + 1);
  }

  /*
   * If the buffer has not been found check the local cache of released
   * buffers. There are release and released modified lists to preserve the
   * state.
   */
  if (!rtems_rfs_fs_no_local_cache (fs) &&
      !rtems_rfs_buffer_handle_has_block (handle))
  {
    /*
     * Check the local cache of released buffers.
     */
    if (fs->release_count)
      handle->buffer = rtems_rfs_scan_chain (&fs->release,
                                             &fs->release_count,
                                             block);

    if (!rtems_rfs_buffer_handle_has_block (handle) &&
        fs->release_modified_count)
    {
      handle->buffer = rtems_rfs_scan_chain (&fs->release_modified,
                                             &fs->release_modified_count,
                                             block);
      /*
       * If we found a buffer retain the dirty buffer state.
       */
      if (rtems_rfs_buffer_handle_has_block (handle))
        rtems_rfs_buffer_mark_dirty (handle);
    }
  }

  /*
   * If not located we request the buffer from the I/O layer.
   */
  if (!rtems_rfs_buffer_handle_has_block (handle))
  {
    rc = rtems_rfs_buffer_io_request (fs, block, read, &handle->buffer);

    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
        printf ("rtems-rfs: buffer-request: block=%" PRIu32 ": bdbuf-%s: %d: %s\n",
                block, read ? "read" : "get", rc, strerror (rc));
      return rc;
    }

    rtems_chain_set_off_chain (rtems_rfs_buffer_link(handle));
  }

  /*
   * Increase the reference count of the buffer.
   */
  rtems_rfs_buffer_refs_up (handle);
  rtems_chain_append (&fs->buffers, rtems_rfs_buffer_link (handle));
  fs->buffers_count++;

  handle->buffer->user = (void*) ((intptr_t) block);
  handle->bnum = block;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
    printf ("rtems-rfs: buffer-request: block=%" PRIu32 " bdbuf-%s=%" PRIu32 " refs=%d\n",
            block, read ? "read" : "get", handle->buffer->block,
            handle->buffer->references);

  return 0;
}
コード例 #22
0
ファイル: mount.c プロジェクト: epicsdeb/rtems
int mount(
  const char                 *source,
  const char                 *target,
  const char                 *filesystemtype,
  rtems_filesystem_options_t options,
  const void                 *data
)
{
  rtems_filesystem_fsmount_me_t mount_h = NULL;
  rtems_filesystem_location_info_t      loc;
  rtems_filesystem_mount_table_entry_t *mt_entry = NULL;
  rtems_filesystem_location_info_t     *loc_to_free = NULL;
  bool has_target = target != NULL;
  size_t target_length = 0;

  /*
   *  Are the file system options valid?
   */

  if ( options != RTEMS_FILESYSTEM_READ_ONLY &&
       options != RTEMS_FILESYSTEM_READ_WRITE )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   *  Get mount handler
   */
  mount_h = rtems_filesystem_get_mount_handler( filesystemtype );
  if ( !mount_h )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   * Allocate a mount table entry
   */
  mt_entry = alloc_mount_table_entry(
    source,
    target,
    filesystemtype,
    &target_length
  );
  if ( !mt_entry )
    rtems_set_errno_and_return_minus_one( ENOMEM );

  mt_entry->mt_fs_root.mt_entry = mt_entry;
  mt_entry->options = options;
  mt_entry->pathconf_limits_and_options = rtems_filesystem_default_pathconf;

  /*
   *  The mount_point should be a directory with read/write/execute
   *  permissions in the existing tree.
   */

  if ( has_target ) {
    if ( rtems_filesystem_evaluate_path(
           target, target_length, RTEMS_LIBIO_PERMS_RWX, &loc, true ) == -1 )
      goto cleanup_and_bail;

    loc_to_free = &loc;

    /*
     * Test for node_type_h
     */

    if (!loc.ops->node_type_h) {
      errno =  ENOTSUP;
      goto cleanup_and_bail;
    }

    /*
     *  Test to see if it is a directory
     */

    if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) {
      errno = ENOTDIR;
      goto cleanup_and_bail;
    }

    /*
     *  You can only mount one file system onto a single mount point.
     */

    if ( rtems_filesystem_mount_iterate( is_node_fs_root, loc.node_access ) ) {
      errno = EBUSY;
      goto cleanup_and_bail;
    }

    /*
     *  This must be a good mount point, so move the location information
     *  into the allocated mount entry.  Note:  the information that
     *  may have been allocated in loc should not be sent to freenode
     *  until the system is unmounted.  It may be needed to correctly
     *  traverse the tree.
     */

    mt_entry->mt_point_node.node_access = loc.node_access;
    mt_entry->mt_point_node.handlers = loc.handlers;
    mt_entry->mt_point_node.ops = loc.ops;
    mt_entry->mt_point_node.mt_entry = loc.mt_entry;

    /*
     *  This link to the parent is only done when we are dealing with system
     *  below the base file system
     */

    if ( !loc.ops->mount_h ){
      errno = ENOTSUP;
      goto cleanup_and_bail;
    }

    if ( loc.ops->mount_h( mt_entry ) ) {
      goto cleanup_and_bail;
    }
  } else {
    /*
     * Do we already have a base file system ?
     */
    if ( !rtems_chain_is_empty( &mount_chain ) ) {
      errno = EINVAL;
      goto cleanup_and_bail;
    }

    /*
     *  This is a mount of the base file system --> The
     *  mt_point_node.node_access will be left to null to indicate that this
     *  is the root of the entire file system.
     */
  }

  if ( (*mount_h)( mt_entry, data ) ) {
    /*
     * Try to undo the mount operation
     */
    if ( loc.ops->unmount_h ) {
      loc.ops->unmount_h( mt_entry );
    }
    goto cleanup_and_bail;
  }

  /*
   *  Add the mount table entry to the mount table chain
   */
  rtems_libio_lock();
  rtems_chain_append( &mount_chain, &mt_entry->Node );
  rtems_libio_unlock();

  if ( !has_target )
    rtems_filesystem_root = mt_entry->mt_fs_root;

  return 0;

cleanup_and_bail:

  free( mt_entry );

  if ( loc_to_free )
    rtems_filesystem_freenode( loc_to_free );

  return -1;
}