Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have a code base that is designed around shared memory. Each process that needs to access the memory maps it into its own address space. The data structures in the shared memory are directly accessed, that is, there is no API. For example:

Assume the following:

typedef struct {
  int x;
  int y;
  struct {
    int a;
    int b;
  } z;
} myStruct;

myStruct s;

Then a process might access this structure as:

myStruct *s = mapGlobalMem();

And use it as:

int tmpX = s->x;

The majority of the information in the global structure is configuration information that is set once and read many times. I would like to store this information in a database and develop an API to access the database. The problem is, these references are sprinkled throughout the code. I need a way to parse the code and identify global structure references that will need to be refactored.

I've looked into using ANTLR to create a parser that will identify references to a small set of structures and enter them into a custom symbol table. I could then use this symbol table to identify which source files need to be refactored. It looks like a promising approach.

What other approaches are there? Of course, I'm looking for a programmatic approach. There are far too many source files to examine each one visually.

This is all ordinary ANSI C. Nothing else.

share|improve this question
    
Does mapGlobalMem() exist, or is that you are looking to replace? If it does already exist, is it in a library that you have access to the source code for? –  Jay Elston Sep 5 '11 at 17:18
add comment

4 Answers

I am assuming this is a part of a big project because you mentioned 'too many source files'. I am unclear about the final objective. You can put the configuration in a database and modify mapGlobalMem() to populate & return a memory location that contains the configuration. That way you're not breaking your contract with the current code but you've moved your configuration 'outside' the process. I am assuming you dont want to make a call to the database each time someones trying to access the configuration information.

Now, if you're worried about freshness and hence you need to refactor this out into an API, I would suggest looking for all occurances of mapGlobalMem() and myStruct. This should give you a ball park estimate.

Ultimately, if you're trying to automate this change, I'd assume you'd spend more time automating it than a simple sed / find-replace.

share|improve this answer
add comment

Since your code is in C - rename the typedef, build the code, watch the compiler complain. Now you know where the struct is referenced. Since you'll be converting the code to use a completely different way of accessing this data, you're gonna need to eyeball every single case anyway. So put on a fresh pot of coffee and get hacking... :-)

share|improve this answer
    
Yeah, I thought of this. Unfortunately it doesn't provide a good way of estimating the magnitude of the project. –  Rob Jones Aug 18 '11 at 13:16
    
@LAsse's right, you'll get acount of error messages from the compiler, and that is the scope of the problem. –  Tim Williscroft Dec 16 '11 at 6:01
add comment

A slightly less all-or-nothing approach might be to populate the global structure and return only "const" pointers to it. Let the compiler warnings be your guide, again, but you only "must" update the writers. Initialize the struct once (add an is_configured flag, perhaps as a file scoped static?) on the first request, and if the "writer" function is called, refresh the struct and the backing database. @Lasse has the "right" answer, but this might be the "expedient" one for short-term duct-taping.

Downside: you'd need to handle some kind of asynchronous signal if another process changes a setting. On Unix/Linux, SIGWINCH is a good candidate, and SIGHUP is somewhat traditional. (SIGWINCH gets spurious hits if you're running from an xterm that gets resized, but for a background daemon, it's never called and defaults to being IGNored. SIGHUP defaults to killing you.)

share|improve this answer
add comment

Based on your description, here is how i would set out as the objective.

  1. The mechanism of use for end application should remain same; i.e.

    myStruct *s = mapGlobalMem(); int tmpX = s->x; should not change. This implies that application which uses this GlobalMap shouldn't be aware that such a map is actually from the database.

  2. Both mechanism should continue to function - i.e the existing app should work as it is where it is currently getting the Map or additionally now it can get it from the DB as well.

  3. The system should be thread-safe, and multi-instance capable. Think of it like Malloc(). It manages internal data structures of various things. However, if multiple threads approaches simultaneously it doesn't spoil the structure and different thread/objects can ask for memory and are assigned different blocks.

  4. The overall code base is much larger - hence the unit of changes should be isolated on specific central segments only. i.e. i would change the Map creation part (central) rather than Map access part (distributed all over the code). In this case

  5. Since, i am anyway extending this system in one aspect - say connectivity with DB - i may also extend it in such a way that tomorrow other mechanisms can be used to provide such information.

I am assuming that DATA which is represented in *s is now fetched from DB rather than current source. (If i am wrong here - most of the answer below might need to be rewritten.)

Here is what i would do.

  1. There is extension of primary functionality with a new API : something like setGlobalMem(info);

The info is where i decide which source to use - whether current methodology or db, and if in DB - which query will essentially redistribute it. Alternatively one can also imagine that config can come through a .conf file or through some other form of input.

  1. Re-factor the primary API to support both options. Basically i would have a guarded pointer something like *currentValidMap. Whenever there is an update to/from any data source the final s is updated as one of this; probably something like this might just exists.

  2. I might have an additional function like updateMap(section,source) used restrictively to override some config options locally for example. Here i would use part of the info through some other source. More importantly i might also have lockMap to close any further modifications to the Map. All these APIs are used centrally to establish the Map as required.

I am assuming things - so might be inaccurate in some cases because of this.

Basically I would never modify any other part of the application which is only reading the config data - they have no business to understand where the config data is coming from.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.