ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Hello, I'm actually porting my Windows software on Linux.
I coded it with the SDL so the main part of the code directly works with UNIX based system.
I experiment two issues and I would like to know if you may solve them...
1. I need to re-launch my software via command line... For windows, I use ShellExecute, for Mac OSX, open with the -n flag but for linux, I have still not find a way =/
2. For check if the new instance already run, I try to delete a file which is opened by the new instance (which will not run the same code and I don't want that a new instance start to run this code) with windows, if the file was used, remove() don't work but it seems that Linux can't do that. Also, I can't write something in it in case of crash/other thing which won't allow the new instance to say that it doesn't run anymore (and allow a other instance to do that).
1. I need to re-launch my software via command line... For windows, I use ShellExecute
I don't know what ShellExecute is, but assuming it runs a command in the shell, system() is the equivalent function in *nix.
Quote:
Originally Posted by Taiki
I try to delete a file which is opened by the new instance with windows, if the file was used, remove() don't work but it seems that Linux can't do that.
Huh?
Anyway, to delete a file, use the unlink() function (for deleting a directory, you should use the rmdir() function instead).
I also use system() (that's why i'm looking for a command line ) I'm just wondering which command to use...
In fact, I want to test if the file is open somewhere. windows doesn't allow to delete a file if it's in use so I try to delete it and I test if it's still here. I would like to know if there is a way for test that (maybe with an other way) with linux/darwin...
I need to re-launch my software via command line...
Code:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
:
if (need to restart this program) {
execlp(argv[0], argv[0], NULL);
fprintf(stderr, "%s: Cannot restart: %s.\n", argv[0], strerror(errno));
return 1;
}
:
}
If you want, you can add command line parameters as separate strings before the NULL, i.e. execlp(argv[0],argv[0],"foo","bar",NULL); would run the program with two command line parameters, foo and bar. The first string is the command name, the second one is what the program sees it was called with (e.g. argv[0]), followed by the rest of the arguments.
Code:
For check if the new instance already run, I try to delete a file which is opened by the new instance
No, that only works in Windows, nowhere else. Use an advisory lock on a (configuration) file instead.
Most programs and games create a configuration directory .name/ under the user's home directory, and put the configuration file(s), plugins, high scores and such stuff there. You need very little code for this:
Code:
#ifndef GAMEDIR
#define GAMEDIR ".mygame"
#endif
{ const char *const home = getenv("HOME");
const char *const gamedir = GAMEDIR;
int result;
if (home && *home)
do {
result = mkdir(gamedir, 0700); /* drwx------ */
} while (result == -1 && errno == EINTR);
do {
result = chdir(gamedir);
} while (result == -1 && errno == EINTR);
if (result == -1) {
fprintf(stderr, "Missing directory '%s': %s.\n", gamedir, strerror(errno));
exit(1);
}
/* Working directory is now the per-user game directory,
* so you can use relative paths for per-user files,
* and compile-time absolute paths for fixed data files,
* for example /usr/share/games/mygame/.
*/
}
Here is an example function to get an exclusive advisory lock. If successful, it will return a file handle to the file; closing the file will release the advisory lock too. If an error occurs, the function will return NULL, with errno set to EAGAIN if the file is already locked. For all other errors you can use strerror(errno) to obtain a descriptive string (same as perror() shows).
Code:
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
/* Open the named file in read-write mode, creating the file
* (mode -rw-------) if necessary, and apply for an advisory
* exclusive lock.
*
* If successful, the function will return an open file handle.
* Otherwise, it will return NULL with errno set to indicate
* the error; EAGAIN if the file is already locked.
*
* To release the lock, just close the file.
*
* The lock will persist over an exec(). You will want to
* release the lock before an exec() call.
*
* When the program exits (this or the program exec()'d!)
* the lock will be automatically released.
*
* If you fork child processes, they will share the file handle.
* The lock will be released when all processes have either closed
* the handle, or exited; i.e. when there are no open handles left.
*/
FILE *fopen_exclusive(const char *const filename)
{
int descriptor, result, saved_errno;
FILE *handle;
if (!filename || !*filename) {
/* Empty or NULL filename. */
errno = EINVAL;
return NULL;
}
/* Save errno, so we keep it unchanged if we are successful. */
saved_errno = errno;
/* Open the file. Create it (-rw-------) if necessary. */
do {
descriptor = open(filename, O_RDWR | O_NOCTTY | O_CREAT, 0600);
} while (descriptor == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (descriptor == -1)
return NULL;
/* Apply for an exclusive advisory lock. */
do {
result = flock(fd, LOCK_EX | LOCK_NB);
} while (result == -1 && errno == EINTR);
if (result == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EACCES)
saved_errno = EAGAIN;
else
saved_errno = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
errno = saved_errno;
return NULL;
}
/* Convert descriptor to actual file handle. */
do {
handle = fdopen(descriptor, "r+b");
} while (!handle && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (!handle) {
saved_errno = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
errno = saved_errno;
return NULL;
}
/* Success! */
errno = saved_errno;
return handle;
}
Finally, there is a crash-proof way to update per-user files. It is very simple, too. When you wish to save a new file, you create a new file, for example with .new suffix. When done, you verify that there were no write errors, fdatasync() the file to make sure it hits the disk, and rename it over the old file. That way you will always have a complete file, never a partial one. Consider this helper function:
Code:
/* Flush the specified file to disk, then rename from saving to actual.
* Returns 0 if successful, errno code otherwise.
* The handle will be closed in all cases, and saving removed.
*/
int fsave(FILE *const handle, const char *const saving, const char *const actual)
{
int result, saved_errno;
if (!handle)
return errno = EINVAL;
if (!saving || !*saving || !actual || !*actual) {
do {
result = fclose(handle);
} while (result == -1 && errno == EINTR);
return errno = EINVAL;
}
saved_errno = errno;
if (ferror(handle)) {
saved_errno = EIO;
goto fail_close;
}
/* Flush unwritten data to disk. */
do {
result = fflush(handle);
} while (result == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (result == -1) {
saved_errno = EIO;
goto fail_close;
}
/* Sync data; make sure it hits the storage device. */
do {
result = fdatasync(fileno(handle));
}*while (result == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (result == -1 && errno == EIO) {
saved_errno = EIO;
goto fail_close;
}
/* Close file. Check for delayed write errors. */
do {
result = fclose(handle);
} while (result == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (result == -1) {
saved_errno = errno;
goto fail_unlink;
}
/* File is successfully flushed to disk and closed. */
/* Replace existing file with the new one. */
do {
result = rename(saving, actual);
} while (result == -1 && errno == EINTR);
if (result == -1) {
saved_errno = errno;
goto fail_unlink;
}
/* Success! */
errno = saved_errno;
return 0;
fail_close:
/* Close file. */
do {
result = fclose(handle);
} while (result == -1 && errno == EINTR);
fail_unlink:
/* Remove saving file. */
do {
result = unlink(saving);
} while (result == -1 && errno == EINTR);
/* Return failure. */
return errno = saved_errno;
}
To use the above function -- which by the way is one of the rare examples where goto is not harmful; here it simplifies the error handling -- use something like
Code:
FILE *output;
output = fopen("highscores.new", "wb");
if (output) {
/* We can save highscores. */
/* Write the highscore content to output */
fprintf(output, "Highscores:\n");
/* ... */
/* Try saving the highscore file. */
if (fsave(output, "highscores.new", "highscores"))
fprintf(stderr, "Warning: Cannot save highscores: %s.\n", strerror(errno));
} else {
/* We cannot save highscores. Do we need to exit?
The user might be running this from a CD-ROM or something.
*/
}
Note that users will prefer graceful handling of errors, so something like not being able to save the highscores should definitely not abort the program. (Some of us do use read-only media..)
If you had multiple simultaneous copies running, then you would have to use an unique suffix, preferably .shorthostname.pid (which is unique in a local network at any point in time; use gethostname() and getpid() to obtain the string and the PID number). The file replacement will be atomic, but in tight races some processes might see the previous one instead of the very latest one. All will see a complete file, though, never a mix.
For the first part, you misunderstood me: I don't want to restart the soft but launch a new instance. Maybe use fork() + execlp() but it seems heavy and I don't know if they are REALLY independant.
For the second part, the file don't contain anything he's just there when the soft run a special part of the code. But the probleme is that I can't leave it and only check if it exists (in case of crash, the file won't be delete).
But the idea of "block" the file seems very interesting, I'll will use it and told you if it works
For the first part, you misunderstood me: I don't want to restart the soft but launch a new instance.
We POSIX folks call that forking a child process, I think:
Code:
pid_t child, pid;
child = fork();
if (child == (pid_t)-1) {
fprintf(stderr, "Cannot fork a child process: %s.\n", strerror(errno));
exit(1);
}
if (child) {
/* Only the parent process will run this code */
/* Reap the child before exiting */
do {
pid = waitpid(child, NULL, 0);
} while (pid != child);
exit(0);
} else {
/* Only the child process will run this code */
exit(0);
}
Normally, the parent should at some point reap the child process using one of the wait() functions. Otherwise, if the child process exits, it will stay in the process list listed as a zombie.
As you might guess, zombies are just children that haven't been reaped yet. It is mostly just a cosmetic issue, since the kernel will release all resources used by the process except for the PID and the exit status code.
Note that the child process will inherit all variables (and open file handles) from the parent process, but otherwise it will be a different process. The two will not see any changes they make to variables after the fork.
The situation may be easier to understand if you think of the child as having been magically started at the same time as the parent, has received all the same inputs and seen all the same files and times and everything as the parent process .. but that they diverge for the first time at the fork() call. Afterwards, they really are separate "programs".
You can obviously fork multiple times, but make sure you fork only from the parent process. Otherwise, you get an exponential number of child processes (since each child process will fork further children); this is called a fork bomb. When testing code that does forks, run ulimit -n numberofprocesses to limit the number of processes that session (shell or terminal) can create in parallel. A smallish number like 20 is usually enough for testing; I like to do my testing using another terminal or shell. (That way, even if you happen to trigger a fork bomb, it will be limited to 20 processes, and you can kill it from another shell, for example using killall -KILL myprogname.)
Any parent process can check on its children without waiting for the results, effectively just checking if anything notable has happened. Here is a full example:
Code:
pid_t pid;
int exitstatus;
/* See if any child process has exited. */
pid = waitpid((pid_t)-1, &exitstatus, WNOHANG);
if (pid != (pid_t)0 && pid != (pid_t)-1) {
/* Child process 'pid' has exited (or stopped or continued). */
if (WIFEXITED(exitstatus)) {
/* It exited with status WEXITSTATUS(exitstatus) */
} elif (WIFSIGNALED(exitstatus)) {
/* It died from signal WTERMSIG(exitstatus) */
}
}
The above snippet will not wait for any child to exit. If you don't care about the exit status stuff, you can just call waitpid((pid_t)-1,NULL,WNOHANG); in your code now and then, to reap any child processes that have exited. But, like I said, it is okay to leave zombies say during the game, only reaping them from the main menu, for example.
Oh, and if you leave child processes around when the program exits, that too is okay: init (process 1, the grandparent of all processes) will adopt the children, and reap them when they exit. So any zombies too will be eventually reaped.
Last edited by Nominal Animal; 01-18-2012 at 11:46 AM.
I knew fork() but thanks for precision
It's not exactly a child process because both process will work on there own side w/o interact with the other.
If fork() allow each process to work without the other (one can be close without any impact on the other)
I'll check that, i'll be back with feedback soon
If fork() allow each process to work without the other (one can be close without any impact on the other)
Forking two children and letting the parent process exit might be a better approach for you:
Code:
pid_t pid, child1, child2;
child1 = fork();
if (child1 == (pid_t)-1) {
fprintf(stderr, "Cannot fork first child process: %s.\n", strerror(errno));
exit(1);
}
if (!child1) {
/*
* First child process.
*/
exit(0);
}
child2 = fork();
if (child2 == (pid_t)-1) {
fprintf(stderr, "Cannot fork second child process: %s.\n", strerror(errno));
exit(1);
}
if (!child2) {
/*
* Second child process.
*/
exit(0);
}
/* This is the original parent process.
* Since it exits now, the children will be reparented,
* and reaped automatically when they exit.
*/
exit(0);
The two are obviously siblings, only sharing open files and initial state.
The tricky thing about this is to note that the parent process will exit immediately. It might be a good idea to first put up a small splash window, then read the configuration and fork children, and then exit. That way the user will get visual feedback immediately, and is not left waiting for some input. Because the parent process will exit, even the task manager may not realize the children are still running, and you may not get the process icon on the task bar..
So, please test if this works for you. I haven't tested this using graphical user interfaces. Specifically, I don't know how the task bar behaves when there is a delay between the original parent process starting, and the child processes starting a new window. I suspect the task manager does not show the process is still starting up. (You can fix that, of course, by waiting for the children to fully start up before exit() in the parent process. You can do that easily by using two pipes, and closing the pipe when the child has started up. A blocking read on both by the parent will wait until the child closes the pipe.)
The only problem I can see that might trip up someone coming from Windows is leaving (and accumulating) open files. On linux anyway that's easy(-ish) to fix, a readdir loop on /proc/self/fd/, here's a really brutal demonstrator:
Code:
~/sandbox/49381$ cat opendir.cc
#include <cstdio>
#include <sys/types.h>
#include <dirent.h>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
using namespace std;
int main (int c, char **argv)
{
puts(argv[0]);
auto d = opendir ("/proc/self/fd/");
vector<int> v;
while (auto e = readdir (d))
if (e->d_name[0] != '.' && atoi (e->d_name) > 2)
v.push_back (atoi (e->d_name));
for (auto fd:v)
printf ("close(%d)==%d\n", fd, close (fd));
if (argv[1])
exit (0);
puts ("restarting");
char me[255];
me[readlink("/proc/self/exe",me,255)]=0;
execl("/proc/self/exe", me, "--restarting",0);
perror("execl");
return 0;
}
~/sandbox/49381$ make CXXFLAGS=--std=c++0x opendir
g++ --std=c++0x opendir.cc -o opendir
~/sandbox/49381$ ./opendir 4<opendir.cc
./opendir
close(3)==0
close(4)==0
restarting
/home/jthill/sandbox/49381/opendir
close(3)==0
~/sandbox/49381$
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
static int close_all(void)
{
size_t fd_size = 0;
size_t fd_used = 0;
int *fd_list = NULL, *fd_temp;
const struct dirent *ent;
DIR *dir;
const char *name;
int saved_errno, fd, result, err;
saved_errno = errno;
do {
dir = opendir("/proc/self/fd/");
} while (!dir && errno != EINTR);
if (!dir)
return errno;
while (1) {
errno = 0;
ent = readdir(dir);
if (!ent)
break;
if (!(ent->d_name[0] >= '0' && ent->d_name[0] <= '9'))
continue;
fd = ent->d_name[0] - '0';
name = (const char *)&(ent->d_name[1]);
while (*name >= '0' && *name <= '9')
fd = 10*fd + *(name++) - '0';
if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
continue;
if (fd_used >= fd_size) {
fd_size = (fd_used | (size_t)255) + (size_t)257;
fd_temp = realloc(fd_list, sizeof(int) * fd_size);
if (!fd_temp) {
if (fd_list)
free(fd_list);
do {
result = closedir(dir);
} while (result == -1 && result == EINTR);
return errno = ENOMEM;
}
fd_list = fd_temp;
}
fd_list[fd_used++] = fd;
}
if (errno) {
err = errno;
if (fd_list)
free(fd_list);
do {
result = closedir(dir);
} while (result == -1 && errno == EINTR);
return errno = err;
}
fd = dirfd(dir);
do {
result = closedir(dir);
} while (result == -1 && errno == EINTR);
if (result == -1) {
err = errno;
if (fd_list)
free(fd_list);
return errno = err;
}
err = 0;
while (fd_used-->0)
if (fd_list[fd_used] != fd) {
do {
result = close(fd_list[fd_used]);
} while (result == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
if (result == -1)
err = errno;
}
if (fd_list)
free(fd_list);
if (err)
return errno = err;
errno = saved_errno;
return 0;
}
This function has a bit different approach to closing the file descriptors. I think there is a possibility one might skip a descriptor when scanning /proc/self/fd/ and closing descriptors at the same time, although buffering may hide that unless you have a lot of open descriptors. It does happen when scanning directories and renaming files at the same time.
The function generates a dynamically allocated array of the open descriptors first, then tries to close them. It will keep the standard input, standard output, and standard error descriptors open. If successful -- all descriptors except the standard ones closed successfully -- it will return zero and keep errno unchanged, otherwise it will return errno (set to describe the error).
Thanks for these answers
The file management seems to work fine.
For fork(), i made a big mistake and I can't check a new build after patched it so I'll be back later with news.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.