[Windows] Any way to distinguish ^C Induced EOF from ^Z EOF?

J

Jan Burse

Dear All,

Just running the following test program:

CtrlCRunner ctrl = new CtrlCRunner();
ctrl.installCtrlC(
new Runnable() {
public void run() {
/* do nothing ! */
}
}
);
FileInputStream fs = new FileInputStream(FileDescriptor.in);
byte[] buf = new byte[256];
for (;;) {
System.out.print("test: ");
int len = fs.read(buf);
String str = new String(buf,0,Math.max(0,len));
System.out.println("len = "+len+", buf = "+str+",
buf[0]="+buf[0]);
if ("exit".equals(str.trim())) break;
}
ctrl.deinstallCtrlC();

Noticed that ^C and ^Z both deliver EOF.

When pressing ^C

test: len = -1, buf = , buf[0]=0

When pressing ^Z and ENTER:

test: ^Z
len = -1, buf = , buf[0]=0

How could I distinguish the two in Java?

Best Regards

BTW: It does not happen on Linux and Mac
OS with ^C and ^D, I only see this happen
currently on Windows 7.

Sounds similar to the following problem:
Inconsistent raw_input behavior after Ctrl-C
http://www.gossamer-threads.com/lists/python/python/781893
 
A

Arne Vajhøj

Just running the following test program:

CtrlCRunner ctrl = new CtrlCRunner();
ctrl.installCtrlC(
new Runnable() {
public void run() {
/* do nothing ! */
}
}
);
FileInputStream fs = new FileInputStream(FileDescriptor.in);
byte[] buf = new byte[256];
for (;;) {
System.out.print("test: ");
int len = fs.read(buf);
String str = new String(buf,0,Math.max(0,len));
System.out.println("len = "+len+", buf = "+str+", buf[0]="+buf[0]);
if ("exit".equals(str.trim())) break;
}
ctrl.deinstallCtrlC();

Noticed that ^C and ^Z both deliver EOF.

When pressing ^C

test: len = -1, buf = , buf[0]=0

When pressing ^Z and ENTER:

test: ^Z
len = -1, buf = , buf[0]=0

How could I distinguish the two in Java?

Best Regards

BTW: It does not happen on Linux and Mac
OS with ^C and ^D, I only see this happen
currently on Windows 7.

That type of stuff is very OS specific.

I will (again) suggest using JNI to get the specific
behavior that you desire.

Java IO is just for the 98% of cases.

Arne
 
J

Jan Burse

Arne said:
That type of stuff is very OS specific.

I will (again) suggest using JNI to get the specific
behavior that you desire.

Java IO is just for the 98% of cases.

Arne


When I raise the signal manually, for example
as follows:

new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException x) {
/* */
}
Signal.raise(new Signal("INT"));
}
}.start();

Then the EOF does not happen. So it is not a problem
of the Java dispatcher, more of the ReadFile operation.

I am open to JNI, and also to JNA. Best would
be if there is something out of the box.

It could be fixed, if one would have access to
GetLastError. Namely the MS docs do write:

"Characters can be read from the console input buffer by using ReadFile
with a handle to console input. The console mode determines the exact
behavior of the ReadFile function. By default, the console mode is
ENABLE_LINE_INPUT, which indicates that ReadFile should read until it
reaches a carriage return. If you press Ctrl+C, the call succeeds, but
GetLastError returns ERROR_OPERATION_ABORTED. For more information, see
CreateFile."
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx

Such a patch seems to be also done here:
[Chicken-hackers] [PATCH] handle SIGINT correctly in csi on windows
http://www.mail-archive.com/[email protected]/msg01846.html

Bye
 
A

Arne Vajhøj

When I raise the signal manually, for example
as follows:

new Thread() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException x) {
/* */
}
Signal.raise(new Signal("INT"));
}
}.start();

Then the EOF does not happen. So it is not a problem
of the Java dispatcher, more of the ReadFile operation.

I am open to JNI, and also to JNA.

JNA is also JNI just encapsulated a bit.
Best would
be if there is something out of the box.

Of course.

But Java was not designed to provide that type of
fine control over terminal IO.
It could be fixed, if one would have access to
GetLastError. Namely the MS docs do write:

"Characters can be read from the console input buffer by using ReadFile
with a handle to console input. The console mode determines the exact
behavior of the ReadFile function. By default, the console mode is
ENABLE_LINE_INPUT, which indicates that ReadFile should read until it
reaches a carriage return. If you press Ctrl+C, the call succeeds, but
GetLastError returns ERROR_OPERATION_ABORTED. For more information, see
CreateFile."
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx

With JNI you can use it and get exactly the behavior you want.

Arne
 
J

Jan Burse

Arne said:
But Java was not designed to provide that type of
fine control over terminal IO.

This Java is just a *frigging cheap RI* implementation,
that doesn't work correctly for console streams, although
it could.

It doesn't map the File metaphor correctly to the
console streams. The Java developers were not reading
the MS specs, and just doing a cheap hack.

The native readBytes must anyway check GetLastError
and eventually throw IOException. With some additional
logic and a re-read everything would be fine.

But I agree, the scope is a little bit enlarged, since
it is a behaviour that can only be observed during
Signals, which is also a little bit out of scope of
standard java.

Bye
 
A

Arne Vajhøj

This Java is just a *frigging cheap RI* implementation,
that doesn't work correctly for console streams, although
it could.

It doesn't map the File metaphor correctly to the
console streams. The Java developers were not reading
the MS specs, and just doing a cheap hack.

The native readBytes must anyway check GetLastError
and eventually throw IOException. With some additional
logic and a re-read everything would be fine.

But I agree, the scope is a little bit enlarged, since
it is a behaviour that can only be observed during
Signals, which is also a little bit out of scope of
standard java.

Java was designed to write business apps that:
* are reliable
* are cheap to develop
* will run on any platform that has Java

I think they achieved that.

But everything comes at a cost.

Java is not a good language for OS specific code.

That includes advanced terminal IO.

Windows, *nix, z/OS, i, OpenVMS etc. are rather
different when it comes to how they handle control
keys.

Arne
 
M

markspace

This Java is just a *frigging cheap RI* implementation,
that doesn't work correctly for console streams, although


Well we'll wait here until you right your own implementation. How long
do you think that will take?
 
J

Jan Burse

markspace said:
Well we'll wait here until you right your own
implementation. How long do you think that will take?

given the fact that Java appeared already in 1995
and that tons of developers were involved with
it, its a real schame how poor it still is.

*fcuk*
 
L

Lew

Jan said:
given the fact that Java appeared already in 1995
and that tons of developers were involved with
it, its a real schame how poor it still is.

*fcuk*

The usual whinge of someone whose personal favorite feature didn't make it
into Java, irrespective of whether such personal favorite feature is feasible,
consistent with Java's mission, or useful to anyone else besides himself.

On an objective basis, your statement is nonsense. On a subjective basis, poor
you.
 
S

Silvio Bierman

given the fact that Java appeared already in 1995
and that tons of developers were involved with
it, its a real schame how poor it still is.

*fcuk*

Given the fact that tons of developers have consistently chosen
differently since 1995, it is very likely that your view on this is flawed.
 
A

Arne Vajhøj

given the fact that Java appeared already in 1995
and that tons of developers were involved with
it, its a real schame how poor it still is.

*fcuk*

Actually Java first went GA in January 1996.

And I think works fine or what it was intended for - and
in fact way beyond that.

If a developer chose Java for a task that Java was not designed
for and has never been prioritized since, then it is the
developers faults not Java's fault.

Arne
 
J

Jan Burse

Arne said:
If a developer chose Java for a task that Java was not designed
for and has never been prioritized since, then it is the
developers faults not Java's fault.

Here is an example (although quite an artifical one)
which shows how this flaw can harm the end-user. Consider
this naive code:


System.out.println("Do you want commit/rollback? (^D or ^Z/Enter)");
String str=br.readLine();
if (str=null) {
commitTransaction();
} else if ("".equals(str)) {
rollbackTransaction();
}

Now what do you expect a program to do after the prompt:

Do you want commit/rollback? (^D or ^Z/Enter)

When the end-user presses ^C. Here is what happens on
the different platforms because of this flaw:

Mac or Linux: Upon pressing ^C the standard interrupt
handler will be invoked, which calls System.exit(),
neither commit nor rollback is issued, depending
on the database most likely the System.exit() will
do a rollback.

Windows: A race condition is induced. Upon pressing
^C two things will happen: The readLine() will
return null and in the same time the standard
interrupt handler will be invoked. If the System.exit()
and its shutdown handlers are slow it might be
very well that a commit happens.

So this is something I called fucked up. If I have time
I will try to file a bug, if there isn't yet one. Filing
a bug should be easy since "GetLastError returns
ERROR_OPERATION_ABORTED" is well documented by MS.

Best Regards

P.S.: I did some measurements. It appears that usually
the readLine() returns before that the INT handler gets
invoiked. The delay is about ~1ms. One can easily
measure it with the new System.nanoTime().

P.S.S.: Therefore I adopetd the workaround of Gabriel
Genellina with a timeout of around 10ms. But this
design is also flawed, it might provoke an unrecognized
EOF. But it is better than nothing...
 
J

Jan Burse

Silvio said:
Given the fact that tons of developers have consistently chosen
differently since 1995, it is very likely that your view on this is flawed.

I guess your are subject to the same brainwash like
the subjects in "The Emperor's New Clothes". I even
don't feel pitty for you.
 
J

Jan Burse

Lew said:
On an objective basis, your statement is nonsense. On a subjective
basis, poor you.

Personal or not. Face it, the Java library hasn't
much evolved since 1995. I am not talking about the
Java language, the Java language itself did a
tremendous development, we have Generics and super
cool good performant 64-bit JITs.

But the platform support for Windows hasn't evolved
since much. The NIO is kind of a joke, concerning
interrupts, all it can give you is ClosedByInterrupt-
Exception but not a clean InterruptedIOException.
And ClosedByInterruptException doesn't even work
for "CON" on Windows.

But its no wonder, since Windows boycotted Java and
did his own thing with CLR etc.. Why should they
care about have a good library for Windows. In the
end we as end-users are the victims of this commercial
struggle. *fcuk*

Bye
 
J

Jan Burse

Leif said:
Oh _come on_! If you insist on writing a console-based interactive
program in Java, at least have enough common sense to not choose
control codes for the expected user input.

I didn't choose control codes.

I chose end-of-file of a stream. Which is on a windows
console ^Z and in Mac or Linux ^D. But this is only the
most common default, it could be also other key combinations,
and I guess it can be configured in some console utilities.

And its very common that programs assume that everything is
fine when a end-of-file is encountered, and that they then
commit their work. This is the sunshine case.

Bye
 
A

Arne Vajhøj

Personal or not. Face it, the Java library hasn't
much evolved since 1995.

Not true.

It has grown a lot. By more than a factor 10.

And Java is still first GA in January 1996 not 1995.
I am not talking about the
Java language, the Java language itself did a
tremendous development, we have Generics and super
cool good performant 64-bit JITs.

JIT's are not part of the Java language.
But the platform support for Windows hasn't evolved
since much.

Not much.

But that is by design.

Java is supposed to be portable.

Support for very OS specific features and being
portable does not go very well together.

If you need the fine control over stuff like
this then pick a language that has prioritized
low level OS integration over portability.
But its no wonder, since Windows boycotted Java and
did his own thing with CLR etc.. Why should they
care about have a good library for Windows. In the
end we as end-users are the victims of this commercial
struggle. *fcuk*

..NET does offer more low level features than Java, but
also in .NET sometimes the answer is to go back to
native C/C++ code.

Arne
 
A

Arne Vajhøj

Here is an example (although quite an artifical one)
which shows how this flaw can harm the end-user. Consider
this naive code:


System.out.println("Do you want commit/rollback? (^D or ^Z/Enter)");
String str=br.readLine();
if (str=null) {
commitTransaction();
} else if ("".equals(str)) {
rollbackTransaction();
}

Now what do you expect a program to do after the prompt:

Do you want commit/rollback? (^D or ^Z/Enter)

When the end-user presses ^C. Here is what happens on
the different platforms because of this flaw:

Mac or Linux: Upon pressing ^C the standard interrupt
handler will be invoked, which calls System.exit(),
neither commit nor rollback is issued, depending
on the database most likely the System.exit() will
do a rollback.

Windows: A race condition is induced. Upon pressing
^C two things will happen: The readLine() will
return null and in the same time the standard
interrupt handler will be invoked. If the System.exit()
and its shutdown handlers are slow it might be
very well that a commit happens.

But the entire code is bad.

CTRL/D or CTRL/Z are not portable (I am pretty sure that
an EBCDIC based system does not have such).

CTRL/C is not portable either.

Considering EOF key (if such exist on the platform)
to mean commit and return to mean rollback and all other
to mean neither is very bad code.

And no finally block.

How can you expect that 2 x platform specific features +
2 x bad coding practices could result in reliable cross
platform code????

Arne
 
A

Arne Vajhøj

I didn't choose control codes.

I chose end-of-file of a stream. Which is on a windows
console ^Z and in Mac or Linux ^D.

There are other platforms as well.
And its very common that programs assume that everything is
fine when a end-of-file is encountered, and that they then
commit their work.

I don't think CTRL/Z or CTRL/D is that common to mean
commit changes in console apps.

Arne
 
J

Jan Burse

Arne said:
CTRL/D or CTRL/Z are not portable (I am pretty sure that
an EBCDIC based system does not have such).

Do you see some Ctrl-D or Ctrl-Z in my code? Except
as explanatory in a prompt?
CTRL/C is not portable either.

Do you see some Ctrl-C in my code?

But SIGINT is widely supported, even on:
- z/OS
- AIX

http://www.ibm.com/developerworks/java/library/i-signalhandling/

Whether you issue it via Ctrl-C, or some kill don't
know what in a separate process doesn't matter.

Here is a reminder for you: The posed problem is as follows

IF sigint is supported THEN how sould
FileInputStream(FileDescriptor.in) behave?

I don't care about those platforms where there is no sigint.
The problem is then automatically resolved. The IF THEN
is trivially true.

Bye
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top