fcloseall() on Solaris

All

I have a program that loads an Oracle shared object, after performing a truss on the process I noticed that Oracle is not closing all the files it is opening, thus after numerous iterations (255 unclosed file handles) the program quits responding to any future file requests... Thus I want to attempt to close these left open file handles after they are done being used... I have read about a function fcloseall() that should help in accomplishing what I am trying to do, however, I can not get it to work on Solaris 8... At compile time I get an undefined symbol... Does anyone either know how to get fcloseall() to work on Solaris, or have a piece of code that will accomplish this (i.e. closing all file handles generated by the current proces or subprocesses)?

Best regards
echard
echardAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
See the 'fcloseall()' manpage:

NAME
       fcloseall - close all open streams

SYNOPSIS
       #define _GNU_SOURCE

       #include <stdio.h>

       int fcloseall(void);

DESCRIPTION
       The  fcloseall  function dissociates all open streams from
       its underlying file or set  of  functions.   Any  buffered
       output  data is written first, using fflush(3).  Note that
       the standard streams (stdin, stdout and stderr)  are  also
       closed.

RETURN VALUE
       This function always returns 0.

SEE ALSO
       fclose(3), close(2), fflush(3), fopen(3), setbuf(3)

CONFORMING TO
       The fcloseall function is a GNU extension. <-------!


This means that unless you can use gcc and its runtime library, you are pretty much lost.
Kent OlsenDBACommented:
Hi echard,

I'm going to caution you that fcloseall() is inherently dangerous and will very likely not produce the effect that you seek.

fcloseall() closes ALL the streams associated with your task.  This includes stdin, stdout, and stderr.  Many library routines depend on these standard streams so you would have to immediately reopen these streams to prevent a routine from attempting I/O to a standard stream only to find that the FILE pointer now contains garbage.

Can you guarantee that the other streams are abandoned?  Closing a stream (or file handle) when another portion of the application is expecting a valid pointer can also be catastrophic.

My suggestion would be to structure your program so that it fork()s off a child process that handles the Oracle interface.  Data is passed to/from parent and child via pipes.  Your application is free to operate in a rational manner while the child task(s) get to handle all of the I/O including the database interfaces.  Open streams are automatically closed when the child terminates so the ugly side effects that you're seeing now can be avoided.


Kent
jkrCommented:
>>fcloseall() closes ALL the streams associated with your task.

That's why I did not suggest 'for ( int i = 3; i < NFILES; close (i++));' as a workaround :o)
Rowby Goren Makes an Impact on Screen and Online

Learn about longtime user Rowby Goren and his great contributions to the site. We explore his method for posing questions that are likely to yield a solution, and take a look at how his career transformed from a Hollywood writer to a website entrepreneur.

Kent OlsenDBACommented:

Hi jkr,

Yeah... There is no good and easy solution to his problem.

Much like most code involving Oracle.  :)

kent
echardAuthor Commented:
All

I was under the impressions that fcloseall() would leave stdin, stdout, stderr all open and close all other files. However I accept what you said above Kent and jkr... The only good thing about this mess is that I know that I can safely close all file handles above the stdin, stdout, stderr handles (0,1,2) thus a solution similar to jkr's of 'for ( int i = 3; i < NFILES; close (i++));'  may work as an ugly fix until Oracle addresses the issue. I do realize and jkr please forgive this statement that it is an ugly solution and highly undesirable, but it is pertinent that I get these open file handles closed before reaching the soft limit of 256...

I do have a question assuming I use jkr's solution what is the easiest way to determine the current value of NFILES... in other words is it a macro that contains the value? where is it defined? etc...

Kent

I have thought about forking a child process, however that solution is goint o take a little time to implement and I need a short term solution.

Guys please provide thoughts as desired.

echard
jkrCommented:
>>what is the easiest way to determine the current value of NFILES

You answered that by writing 'before reaching the soft limit of 256...' :o)

However, this method is not recommended, even though it is common practise when starting a daemon...

Kent OlsenDBACommented:

>>what is the easiest way to determine the current value of NFILES

C assigns file handles incrementally starting with the lowest available handle.  Since you believe that Oracle is never closing a file you can open a file which should therefore return a handle one higher than the last one used by Oracle.  The use this handle as the upper limit.

int  UpperLimit;
int  idx;

  UpperLimit = open ("LimitCheck", O_CREAT|O_TRUNC);
  for (idx = 3; i <= UpperLimit; close (idx++));


Kent

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
echardAuthor Commented:
Kent and jkr

Thanks for all of your help to this point...

The more I think about it I am wondering if there is a way to close all open file handles pointing to a specific file... For example on of the problem files in {$ORACLE_HOME}/xdk/xdk/mesg/lsxus.msb that is being left open is there a way that either of you may be aware of to "query" for all open file handles that end in *.msb and get the file id for them and then close them accordingly? Just thinking this may be way safer since I am using such an undesirable approach to begin with...

Thoughts?

echard
sunnycoderCommented:
>The more I think about it I am wondering if there is a way to close all open file handles pointing to a specific file
do you have /proc file system on solaris ... or some equivalent information source ...

if yes, then

/proc/<pid>/fd
has list of all fds and their corresponding files ... you need to parse the result , search for the specific file and close all associated fds
imstaffCommented:
This function is an extension to fclose. Even though Solaris supports fclose, fcloseall is not supported. You can use fclose to implement fcloseall: Assuming there is an array of FILE *streams, called fileNamePtr[i]:

for(i = 0; i < MAXSTREAMS; i++)
     fclose(fileNamePtr[i]);
jkrCommented:
Um, why if I may ask?
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Unix OS

From novice to tech pro — start learning today.