public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* spawnv()  unlocks files in the calling program
@ 2014-02-09 18:49 Steven Bardwell
  2014-02-09 19:50 ` Corinna Vinschen
  0 siblings, 1 reply; 7+ messages in thread
From: Steven Bardwell @ 2014-02-09 18:49 UTC (permalink / raw)
  To: cygwin

I have a simple programs that show the following issue:

1) program locks a file (in my test /tmp/yyy)
2) program then calls spawnv() (in my test    "/bin/sh  -c  /bin/touch
/tmp/xxx").
3) after the spawnv(), the file /tmp/yyy is no longer locked.

It seems to me that this is wrong. Perhaps I am misunderstanding how file 
locking works. On the other hand, the file lock is preserved if the child
task is started with posix_spawn() rather than spawnv().

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <process.h>
#include <fcntl.h>
#include <time.h>
#include <spawn.h>

extern char **environ;

main()
{
  int status;
  pid_t pid, task_pid;
  struct flock lock;
  const char * argv[] = {"/bin/sh", "-c", "/usr/bin/touch /tmp/xxx", (char
*) 0};
  pid = open("/tmp/yyy", O_WRONLY|O_CREAT,0666);  // create file to be
locked
  if (pid==(pid_t)-1) {
    fprintf(stderr, "Error creating /tmp/yyy - %s\n", strerror(errno));
    exit(1);
  }
  lock.l_type = F_WRLCK;                    // lock /tmp/yyy
  lock.l_start = 0;
  lock.l_whence = 0;
  lock.l_len = 0;
  errno = 0;
  if (fcntl(pid, F_SETLKW, &lock) < 0) {
    fprintf(stderr, "Error locking /tmp/yyy - %s\n", strerror(errno));
    exit(1);
  }

  write_status("/tmp/yyy is locked ... sleeping for 10 seconds\n");

  sleep(10);

  status = spawnv(_P_NOWAIT, "/bin/sh", argv);  // spawn some random program
/*  status = posix_spawn(&task_pid, "/bin/sh", NULL, NULL, argv, environ);
*/
  if (errno != 0)
    fprintf(stderr, "Error starting %s (%s)\n", argv[2], strerror(errno));
  else {
    write_status("spawnv() succeeded\n");
  }
  if (access("/tmp/xxx", F_OK)) {               //  check to make sure our
random program worked
    write_status("spawned program did not complete\n");
  } else {
    write_status("spawned program completed\n");
  }

  while (1) {
    write_status("main program idle\n");
    sleep(2);
  }
  exit(0);
}
write_status(char *message)
{
  char ctbuf[90];
  time_t t,time(time_t *);
  t=time((time_t*)0);         /* make a time stamp */
  strcpy(ctbuf,(char *)ctime(&t));
  if (ctbuf[strlen(ctbuf)-1]=='\n') ctbuf[strlen(ctbuf)-1]=(char)0;
  strcat(ctbuf, ": ");
  strcat(ctbuf, message);
  fprintf(stderr, ctbuf);
}

Steve Bardwell





--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: spawnv()  unlocks files in the calling program
  2014-02-09 18:49 spawnv() unlocks files in the calling program Steven Bardwell
@ 2014-02-09 19:50 ` Corinna Vinschen
  2014-02-09 20:10   ` Steven Bardwell
  0 siblings, 1 reply; 7+ messages in thread
From: Corinna Vinschen @ 2014-02-09 19:50 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 780 bytes --]

On Feb  9 13:25, Steven Bardwell wrote:
> I have a simple programs that show the following issue:
> 
> 1) program locks a file (in my test /tmp/yyy)
> 2) program then calls spawnv() (in my test    "/bin/sh  -c  /bin/touch
> /tmp/xxx").
> 3) after the spawnv(), the file /tmp/yyy is no longer locked.

How do you test that?  You're calling fcntl(F_SETLKW) exactly once at
the start of your test application, but never again later.  We're
talking advisory file locking here, so, where's the next fcntl call
waiting for the lock?

I debugged your test app and the lock still exists after the spawn call.



Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: spawnv()  unlocks files in the calling program
  2014-02-09 19:50 ` Corinna Vinschen
@ 2014-02-09 20:10   ` Steven Bardwell
  2014-02-09 20:40     ` Corinna Vinschen
  0 siblings, 1 reply; 7+ messages in thread
From: Steven Bardwell @ 2014-02-09 20:10 UTC (permalink / raw)
  To: cygwin

> How do you test that?  You're calling fcntl(F_SETLKW) exactly once at
> the start of your test application, but never again later.  We're
> talking advisory file locking here, so, where's the next fcntl call
> waiting for the lock?
> 
> I debugged your test app and the lock still exists after the spawn call.
> 
> 
> 
> Corinna

To test this, I start this program to check for the lock:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>

main(argc, argv)
int argc;
char *argv[];
{
        int rc;
        FILE *pid_file=NULL;
        struct flock lock;
       char ctbuf[90];
       time_t t,time(time_t *);

while (1) {
        t=time((time_t*)0);         /* make a time stamp */
        strcpy(ctbuf,(char *)ctime(&t));
        if (ctbuf[strlen(ctbuf)-1]=='\n') ctbuf[strlen(ctbuf)-1]=(char)0;

        pid_file=fopen("/tmp/yyy", "r");
        if (!pid_file) {
                strcat(ctbuf, ": could not open file\n");
                fprintf(stderr, ctbuf);
                sleep(2);
                continue;
        }

                lock.l_type = F_WRLCK;
                lock.l_start = 0;
                lock.l_whence = 0;
                lock.l_len = 0;
                errno = 0;
                if ((fcntl(fileno(pid_file), F_GETLK, &lock)) < 0) {
                        fprintf(stderr, "fcntl() error %d\n", strerror(errno));
                        exit(1);
                }

                if (lock.l_type == F_UNLCK) {
                        strcat(ctbuf, ": File is not locked\n");
                        fprintf(stderr, ctbuf);
                } else {
                        strcat(ctbuf, ": File is locked\n");
                        fprintf(stderr, ctbuf);
                }
                sleep(2);
        }
        exit(0);
}

It loops until it can open the file (/tmp/yyy), then every two seconds it checks the locked status of the file. Then I start the other program (in a second window). What I see is:

TESTSPAWN:
Sun Feb  9 14:57:47 2014: /tmp/yyy is locked ... sleeping for 10 seconds
Sun Feb  9 14:57:57 2014: spawnv() succeeded
Sun Feb  9 14:57:57 2014: spawned program completed
Sun Feb  9 14:57:57 2014: main program idle
Sun Feb  9 14:57:59 2014: main program idle
Sun Feb  9 14:58:01 2014: main program idle
Sun Feb  9 14:58:03 2014: main program idle

TESTLOCK:
Sun Feb  9 14:57:40 2014: File is not locked
Sun Feb  9 14:57:42 2014: File is not locked
Sun Feb  9 14:57:44 2014: File is not locked
Sun Feb  9 14:57:46 2014: File is not locked
Sun Feb  9 14:57:48 2014: File is locked
Sun Feb  9 14:57:50 2014: File is locked
Sun Feb  9 14:57:52 2014: File is locked
Sun Feb  9 14:57:54 2014: File is locked
Sun Feb  9 14:57:56 2014: File is locked
Sun Feb  9 14:57:58 2014: File is not locked
Sun Feb  9 14:58:00 2014: File is not locked
Sun Feb  9 14:58:02 2014: File is not locked
Sun Feb  9 14:58:04 2014: File is not locked
Sun Feb  9 14:58:06 2014: File is not locked

Steve

~


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: spawnv()  unlocks files in the calling program
  2014-02-09 20:10   ` Steven Bardwell
@ 2014-02-09 20:40     ` Corinna Vinschen
  2014-02-09 21:30       ` Steven Bardwell
  2014-02-10 11:16       ` Corinna Vinschen
  0 siblings, 2 replies; 7+ messages in thread
From: Corinna Vinschen @ 2014-02-09 20:40 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 1055 bytes --]

On Feb  9 15:06, Steven Bardwell wrote:
> > How do you test that?  You're calling fcntl(F_SETLKW) exactly once at
> > the start of your test application, but never again later.  We're
> > talking advisory file locking here, so, where's the next fcntl call
> > waiting for the lock?
> > 
> > I debugged your test app and the lock still exists after the spawn call.
> > 
> > 
> > 
> > Corinna
> 
> To test this, I start this program to check for the lock:

Ok, I can reproduce it, but it's too late to debug this today.

I have to say, though, that fcntl advisory locking is POSIX
functionality, while the spawn functions are not.  In fact these dreaded
spawn entry points are rather old stuff, which hasn't been tested for a
long time.  FWIW, advisory file locking has never been tested with them,
and the fact that it doesn't work as expected doesn't exactly disturb me.


Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: spawnv()  unlocks files in the calling program
  2014-02-09 20:40     ` Corinna Vinschen
@ 2014-02-09 21:30       ` Steven Bardwell
  2014-02-10  4:10         ` Christopher Faylor
  2014-02-10 11:16       ` Corinna Vinschen
  1 sibling, 1 reply; 7+ messages in thread
From: Steven Bardwell @ 2014-02-09 21:30 UTC (permalink / raw)
  To: cygwin

> 
> Ok, I can reproduce it, but it's too late to debug this today.
> 
> I have to say, though, that fcntl advisory locking is POSIX
> functionality, while the spawn functions are not.  In fact these dreaded
> spawn entry points are rather old stuff, which hasn't been tested for a
> long time.  FWIW, advisory file locking has never been tested with them,
> and the fact that it doesn't work as expected doesn't exactly disturb me.
> 
> 
> Corinna
> 
> --
Knowing this, I will use the posix_spawn() function -- I wanted to reduce the
number of fork() calls  in my application (because of the many warnings about
the complexity of the Cygwin implementation of fork() and reported problems
with it), but if spawnv() won't do what I need, then under the bus it goes.

Steve



--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: spawnv()  unlocks files in the calling program
  2014-02-09 21:30       ` Steven Bardwell
@ 2014-02-10  4:10         ` Christopher Faylor
  0 siblings, 0 replies; 7+ messages in thread
From: Christopher Faylor @ 2014-02-10  4:10 UTC (permalink / raw)
  To: cygwin

On Sun, Feb 09, 2014 at 04:09:03PM -0500, Steven Bardwell wrote:
>On Sun, Feb 09, 2014 at 09:38:25PM +0100, Corinna Vinschen wrote:
>>Ok, I can reproduce it, but it's too late to debug this today.
>>
>>I have to say, though, that fcntl advisory locking is POSIX
>>functionality, while the spawn functions are not.  In fact these
>>dreaded spawn entry points are rather old stuff, which hasn't been
>>tested for a long time.  FWIW, advisory file locking has never been
>>tested with them, and the fact that it doesn't work as expected doesn't
>>exactly disturb me.
>>
>Knowing this, I will use the posix_spawn() function -- I wanted to
>reduce the number of fork() calls in my application (because of the
>many warnings about the complexity of the Cygwin implementation of
>fork() and reported problems with it), but if spawnv() won't do what I
>need, then under the bus it goes.

As I think has been pointed out, posix_spawn uses fork() so you are not
going to see any differences there.  And, FWIW, Cygwin's spawn/exec are
hardly simple either.  Both fork and exec are trying to implement something
that can't be done easily on Windows.

cgf

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: spawnv()  unlocks files in the calling program
  2014-02-09 20:40     ` Corinna Vinschen
  2014-02-09 21:30       ` Steven Bardwell
@ 2014-02-10 11:16       ` Corinna Vinschen
  1 sibling, 0 replies; 7+ messages in thread
From: Corinna Vinschen @ 2014-02-10 11:16 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 2096 bytes --]

On Feb  9 21:38, Corinna Vinschen wrote:
> On Feb  9 15:06, Steven Bardwell wrote:
> > > How do you test that?  You're calling fcntl(F_SETLKW) exactly once at
> > > the start of your test application, but never again later.  We're
> > > talking advisory file locking here, so, where's the next fcntl call
> > > waiting for the lock?
> > > 
> > > I debugged your test app and the lock still exists after the spawn call.
> > > 
> > > 
> > > 
> > > Corinna
> > 
> > To test this, I start this program to check for the lock:
> 
> Ok, I can reproduce it, but it's too late to debug this today.
> 
> I have to say, though, that fcntl advisory locking is POSIX
> functionality, while the spawn functions are not.  In fact these dreaded
> spawn entry points are rather old stuff, which hasn't been tested for a
> long time.  FWIW, advisory file locking has never been tested with them,
> and the fact that it doesn't work as expected doesn't exactly disturb me.

I found the reason.  On UNIX, an exec'ed process substitutes the calling
process.  When that happens, fcntl locks are inherited by the child.
The internal implementation of exec and spawn share a lot of code.  One
of the code bits is the function which hands over the fcntl locks from
parent to child.  So after spawn, the owner of the lock is not the
parent anymore, but the child process.  After the child process died,
the lock is abandoned and your 2nd test application rightfully claims
that the file region is unlocked.

I applied a patch which now differs between exec and spawn in the
function handling the inheritance of locks in the child.  If it has been
spawned, it does not take over POSIX locks anymore, but rather it just
gives them up in favor of the parent process.

The current snapshot at http://cygwin.com/snapshots/ does not have this
patch, but we will certainly produce another snapshot in the next few
days.


HTH,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-02-10 10:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-09 18:49 spawnv() unlocks files in the calling program Steven Bardwell
2014-02-09 19:50 ` Corinna Vinschen
2014-02-09 20:10   ` Steven Bardwell
2014-02-09 20:40     ` Corinna Vinschen
2014-02-09 21:30       ` Steven Bardwell
2014-02-10  4:10         ` Christopher Faylor
2014-02-10 11:16       ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).