Link to home
Start Free TrialLog in
Avatar of phillips
phillips

asked on

atexit function

Hello,

I am making a library for file remote access. The library only has few functions to open, close read and write files in another host. I'm using Sun rpc's, and everything works right.
So, what I have is:

  ropen --- Just the same as open, but with a remote file
  rclose
  rread---- Just the same as read but with a remote file
  rwrite


Now I'm trying to accelerate the write processes, by means of a cache in the client side. This is: instead of having to write to the remote machine, I have a local cache, and I write in the local cache (just a buffer in memory), and only when the cache is full I write it in the remote machine.
I have finished it, and It works well.

When the client program close the file with rclose, the rclose function write the contents of the cache in the remote machine.

The problem is when the client program does'nt close the files.

What I want to do is call a function which write the contents of the cache (if the file has been opened for writing) in the remote machine, when the client program finishes.

I have read I can do that with the atexit function, but it doesn't work. What I do is:

void emptycache()
{
...
}

main()
{
...
   if (atexit(emptycache)!=0)
   {
      fprintf(stderr, "Error");
      exit(1);
   }

}

... and the atexit function returns always 0, but the emptycache function is never executed.

I don't know if this happens because the program destroys all the variables before executing emptycache.

Can anybody help me?

Thanks a lot.
Avatar of tovergaard
tovergaard

How do you know that emptycache isn't exectuted ?

How do you terminate your program ?
Does your program exit normally, i.e.,
does it call exit() or return from main(),
rather than be killed by a signal?
In the latter case, emptycache() shouldn't be executed.
It shouldn't destroy all the variables before calling your atexit routines, if it did than the C++ destructors would not work.

Try putting a string out there and print it out just to see.

You are calling 'exit' and not '_exit' or 'abort' or '_c_exit', right?
emmons - it is C, not C++.  Also it shouldn't matter whether you call exit or not, the functions in the atexit list should be executed regardless in reverse order when a program finished.

Are you sure your run-time libraries support atexit?  perhaps you should read the docco for your compiler and machine and make sure that there are no unusual circumstances.

Also ,are you SURE that your exit routine is not being accessed.  If you are just relying on a printf indicating that you got there, then perhaps that may not work becuase the stdin/out/err streams would have already been closed, so you won't get any output.

Perhaps it should do something more obvious, like create a file, write some text and flush and close in you emptycache routine so that you know whether or not it has really worked.

RONSLOW, I understood that it was C and not C++. My only point was that C++ uses the atexit function as part of the destructors, and, since the Microsoft C++ is built using C, it was safe to assume that the same rules would apply to the C compiler.
Likewise, I don't really care if he calls exit (which is implicitly called at the end of main), as long as he does not call any of the other 3 routines. If the other 3 routines are invoked to terminate the program, all of the atexit handling is bypassed.
Sorry if I was misleading or unclear.

You are right about assuring that the routines are not hit. I would suggest writing a simple program to determine what that particular compiler is doing. I wrote somthing against the microsoft and borland compilers under NT on my PC and both executed the atexit functions. Without more details on the configuration of the cache etc, it is tough to say what might be going wrong. I did have this little program write from global memory and from the heap into a file. All worked OK.


Avatar of phillips

ASKER

First of all, I'm using gnu C compiler (gcc) under Linux, and the function atexit is supported by this compiler.

The funtion emptycache is :
void emptycache()
{
 
  int i;              
 
 
  fprintf(stderr, "We are in emptycache\n");
  for(i=0; i<MAXFD; i++);
  {
      if ((filetable[i].busy==1)&&(filetable[i].cache.reading==0))
          writecache(i);
  }
}

As the user is suposed to use my libraries almost in the same way he uses local i/o functions, I have an array of structs:

struct t_cache
{
    char buffer[MAXDATOS];/*The buffer where I read/write data*/
    char *poscache;       /*Buffer's position where I'm                                       reading/writing*/
    int max;       /*The last byte useful of the buffer*/
                   /*I use this to detect the EOF when I read*/
    char reading;  /*I use the cache for reading (=1) or writing
                    (=0)*/
};
 
struct file
{
  short int busy; /*The position of the array is busy*/
  short int remote;/*The file is a remote file*/
  int file;        /*File descriptor (if it is a local file*/
  int position;    /*Position of the file*/
  char name[50];      /*Filename*/
  CLIENT *handle;     /*RPC identificator*/
  struct t_cache cache; /*file's cache*/
};


struct file filetable[64];

So, if the file has been opened for writing, I write in the cache until it is full. Then I write the cache in the remote file with the function writecache (This function works right).When The user close the file with rclose and the file is a remote file opened for writing, I write the data I have written in the cache (not all the data contained in it) in the remote file. When the user fdoesn't close the files. I want to use the function emptycache. As you can see, the function emptycache only looks for files  don't closed, and which have been opened for writing (reading==0).

At this point, If I the user close all the files with rclose (there is no need to write anything), the "We are on the emptycache" appears on the screen; but If I don't close the files (The emptycache function is supposed to run), nothing appears on the screen, and the program becomes blocked (like waiting for something)

I can't imagine why is this hapenning. I have always the solution of closing all the files, but this is not what I want.

Note: when the user open a file, I return the position of the filetable array, that the file is using. And I use thie integer as I file descriptor, in the same way the functions open, read, write and close use the file descriptor.

Second Note: I have tested to finish my program with exit(), and returning from main(). The result in both cases is the same.

Thank you for everyting

Hello philips,

When atexit(exit_func) returns 0, it means that the exit_func has
been successfully registered as an exit function. It is *not* the
return value of the exit function.
exit_func will definitely be called when the program is terminated.
However calls to _exit() or abort() will result in program
termination without calling exit functions.

To cache files you can also try using a setvbuf() for chaching your files.  -

Immidiately after fopen(), please call setvbuf() to set up a buffer
for the stream.
setvbuf is declared in stdio.h and provides buffering to streams.
These buffers will be flushed *automaticaly* by any calls to
fclose(), fcloseall() or exit()

I hope this solves your porblem,
Please contact me if you want any more information on this subject

raditha

raditha@usa.net

Hello Raditha!

I think you haven't undestood what I'm trying to do. I will try to explain it better.

As I'm trying to make functions for remote file access; every time the user wants to read or write something from a remote file, I must perform a remote procedure call, which is several times slower than any file access. So, if the user program only want to copy a local file (size=20K) to a remote file. This is:

...

...

int f1, f2;
int amount, written;


f1=ropen(file1, O_RDONLY);
if (f1<0)
{
  fprintf(stderr, "Error\n");
  exit(1);
}
f2=ropen(file2, O_CREAT | O_WRONLY);
if (f2<0)
{
  fprintf(stderr, "Error\n");
  exit(1);
}
while(amount>0)
{
   amount=rget(f1, buf, 100);
   written=rput(f2, buf, amount);
}
...
...                   This is just an small example

In this example the program will do 200 remote precedure calls aprox.; and this will be very very slow.

What I want to do is having a local cache of 1K (for example), completely transparent to the user, so my rput function will write in the cache instead of making the remote call, and when tha cache is full, I will write all the data contained in it, into the remote file. In this example, the user program for copying a local file to a remote file will be the same (the cache is transparent to the user), but it will make only 20 remote calls instead of 200, and of course will be a lot faster.

As you can see, I don't open the destination file. I just call the remote procedure with the appropiate arguments to do it. Furthermore, the cache and the file aren't located in the same machine. So using setvbuf makes no sense.

I hope you can understand now what I want.

I've made this simple prog which _works_ (on DU4):

--//--
#include <stdlib.h>
#include <stdio.h>

static void clean_up(void);
static FILE *fp = NULL;

int main(void)
{
  if(atexit(clean_up)) {
    perror("atexit error");
    return EXIT_FAILURE;
  }

  if(!(fp = fopen("temp", "w"))) {
    perror("cannot open temp");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

void clean_up(void)
{
  fputs("exiting...\n", stderr);

  if(fp) {
    fputs("closing...", stderr);
    if(fclose(fp)) perror("cannot close temp");
    else fputs(" done\n", stderr);
  }
  else fputs("fp is NULL\n", stderr);
}
--//--

So, the problem should be with rpc.
You may want to check your docs to see if exit() messes up with rpc tables prior to executing atexit functions (sorry, i've no access to Linux).

Good luck, julio
Thank you very much julio!

You may be right, because it only don't work when I try to do something with the rpc in the emptycache function. I will make sure of that, and I will let you know..

Thanks again

--phillips
In keeping with julio's comment, it may be the case that the RPC mechanism itself is using atexit() to clean up!  In that case, you need to arrange for your function to be called first.  I believe that ANSI requires atexit() to support some number of calls, and that it defines the order the items are called; you'd have to look it up, but I'm guessing that they get called in reverse order that they are registered in.  If that is so, then you need to make sure you do your atexit() AFTER the RPC mechanism is initialized.   You may need to have a static "init" variable in your code that you use during the first ropen().
I will try it, and I'll let you know.

Thanks

--phillips
It sounds as if you are closing in on a solution. Phillip, your original code snippet is as follows:


              main()
              {
              ...
                 if (atexit(emptycache)!=0)
                 {
                  fprintf(stderr, "Error");
                  exit(1);
                 }

              }

To make sure your atexit() is being called, why not add an else clause to your if statement above and print something to verify that your atexit() call worked? Right now the only verification you get is if atexit() fails to load the emptycache() routine. Sounds simple, but I frequently overlook the obvious.
Hello, Philips.

Why don't you try this simple example, and this
you know if your compiler accepts atexit.

 void FunctionExit(void)
 {
    printf("exiting...\n");
 }

 int main(void)
 {
    atexit(FunctionExit);
    return 0;
 }

Simply try a signal-handler?!?
Finally,   I GOT IT !!!!
You were right julio and cwestin. The RPC was doing extrange things with my "atexit" function.
I have changed the position of my atexit function, and now it works right.
Thank you very much. I don't know what to do with the points.
I think cwestin has been closer to the solution than julio, so cwestin answer my question ,please, and I will give you the points.

Thank you both again

--phillips
ASKER CERTIFIED SOLUTION
Avatar of cwestin
cwestin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Agreed, points should go to cwestin, which should pass me a - say - 20%, for the idea!!

Just joking :-)

Cheers, julio