Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I check that all my init functions have been called?

Tags:

c

embedded

I am writing a large C program for embedded use. Every module in this program has an init() function (like a constructor) to set up its static variables.

The problem is that I have to remember to call all of these init functions from main(). I also have to remember to put them back if I have commented them out for some reason.

Is there anything clever I do to make sure that all of these functions are getting called? Something along the lines of putting a macro in each init function that, when you call a check_inited() function later, sends a warning to STDOUT if not all the functions are called.

I could increment a counter, but I'd have to maintain the correct number of init functions somewhere and that is also prone to error.

Thoughts?

The following is the solution I decided on, with input from several people in this thread

My goal is to make sure that all my init functions are actually being called. I want to do this without maintaining lists or counts of modules across several files. I can't call them automatically as Nick D suggested because they need to be called in a certain order.

To accomplish this, a macro included in every module uses the gcc constructor attribute to add the init function name to a global list.

Another macro included in the body of the init function updates the global list to make a note that the function was actually called.

Finally, a check function is called in main() after all of the inits are done.

Notes:

  1. I chose to copy the strings into an array. This not strictly necessary because the function names passed will always be static strings in normal usage. If memory was short you could just store a pointer to the string that was passed in.

  2. My reusable library of utility functions is called "nx_lib". Thus all the 'nxl' designations.

  3. This isn't the most efficient code in the world but it's only called a boot time so that doesn't matter for me.

  4. There are two lines of code that need to be added to each module. If either is omitted, the check function will let you know.

  5. you might be able to make the constructor function static, which would avoid the need to give it a name that is unique across the project.

  6. this code is only lightly tested and it's really late so please check carefully before trusting it.

Thank you to:

pierr who introduced me to the constructor attribute.

Nick D for demonstrating the ## preprocessor trick and giving me the framework.

tod frye for a clever linker-based approach that will work with many compilers.

Everyone else for helping out and sharing useful tidbits.

nx_lib_public.h

This is the relevant fragment of my library header file

#define NX_FUNC_RUN_CHECK_NAME_SIZE 20

typedef struct _nxl_function_element{
  char func[NX_FUNC_RUN_CHECK_NAME_SIZE];
  BOOL called;
} nxl_function_element;

void nxl_func_run_check_add(char *func_name);
BOOL nxl_func_run_check(void);
void nxl_func_run_check_hit(char *func_name);

#define NXL_FUNC_RUN_CHECK_ADD(function_name) \
  void cons_ ## function_name() __attribute__((constructor)); \
  void cons_ ## function_name() { nxl_func_run_check_add(#function_name); }

nxl_func_run_check.c

This is the libary code that is called to add function names and check them later.

#define MAX_CHECKED_FUNCTIONS 100

static nxl_function_element  m_functions[MAX_CHECKED_FUNCTIONS]; 
static int                   m_func_cnt = 0; 


// call automatically before main runs to register a function name.
void nxl_func_run_check_add(char *func_name)
{
  // fail and complain if no more room.
  if (m_func_cnt >= MAX_CHECKED_FUNCTIONS) {
    print ("nxl_func_run_check_add failed, out of space\r\n");
    return; 
  }

  strncpy (m_functions[m_func_cnt].func, func_name, 
           NX_FUNC_RUN_CHECK_NAME_SIZE);

  m_functions[m_func_cnt].func[NX_FUNC_RUN_CHECK_NAME_SIZE-1] = 0;

  m_functions[m_func_cnt++].called = FALSE;
}

// call from inside the init function
void nxl_func_run_check_hit(char *func_name)
{
  int i;

  for (i=0; i< m_func_cnt; i++) {
    if (! strncmp(m_functions[i].func, func_name, 
                  NX_FUNC_RUN_CHECK_NAME_SIZE)) {
      m_functions[i].called = TRUE;   
      return;
    }
  }

  print("nxl_func_run_check_hit(): error, unregistered function was hit\r\n");
}

// checks that all registered functions were called
BOOL nxl_func_run_check(void) {
  int i;
  BOOL success=TRUE;

  for (i=0; i< m_func_cnt; i++) {
    if (m_functions[i].called == FALSE) {
      success = FALSE;
      xil_printf("nxl_func_run_check error: %s() not called\r\n", 
                 m_functions[i].func);
     } 
  }
  return success;
}

solo.c

This is an example of a module that needs initialization

#include "nx_lib_public.h"

NXL_FUNC_RUN_CHECK_ADD(solo_init)
void solo_init(void)
{
  nxl_func_run_check_hit((char *) __func__);

  /* do module initialization here */
}
like image 681
NXT Avatar asked Sep 28 '09 02:09

NXT


People also ask

How do you check if function has been called?

You can log a message when the function is called using: Debug. Log("Function called!"); You can store a bool that starts as false and set it to true when you enter the function. You can then check this bool elsewhere in code to tell whether your function has been called.

When init function will be called?

init() Function This function is present in every package and this function is called when the package is initialized. This function is declared implicitly, so you cannot reference it from anywhere and you are allowed to create multiple init() function in the same program and they execute in the order they are created.

Is INIT called only once?

Init functions are called only once, after all the variable declarations and before the main function.

How do you know if a function has been called in JavaScript?

You can check for a function using the typeof keyword, which will return "function" if given the name of any JavaScript function.


1 Answers

You can use gcc's extension __attribute__((constructor)) if gcc is ok for your project.

#include <stdio.h>
void func1() __attribute__((constructor));
void func2() __attribute__((constructor));

void func1()
{
    printf("%s\n",__func__);
}

void func2()
{
    printf("%s\n",__func__);
}

int main()
{
    printf("main\n");
    return 0;
}

//the output
func2
func1
main
like image 106
pierrotlefou Avatar answered Sep 29 '22 07:09

pierrotlefou