13 Replies Latest reply: Dec 13, 2011 9:10 AM by 902571 RSS

    javax.comm.CommPort serial port reopening

      I have two serial ports, for the sake of redundancy in my app. One is designated arbitrarily the active port. If it goes down, I switch to the other as active port. (I can tell it is down because the acknowledgements from the other app at the other end of the connection go unreceived.) Any port that is down undergoes reconnect thread every thirty seconds or so, until someone plugs the cable back in, restoring the healthy dual-port state. The reconnect thread closes and reopens the down port. (On some platforms, my Windows laptop, for example, this is not necessary because plugging back in is sufficient for the port object to carry on read/writing. On others, including my Solaris/XEON machine, you need to reopen.) These ports are java comm's CommPort objects. Everything works fine, almost.

      I have an issue with concurrency and reopening a down port.

      The reopen code causes PortInUseException when opening (after successfully closing) the port sometimes but not always. It causes the exception when the port that is not down is in use for sending its messages and receiving its acknowledgements. This makes no sense to me unless the use of one of the two ports on the machine causes the other to be counted in as owned by the app at that moment (could this be??), causing the PortInUseException, or unless I'm overlooking something in my code which causes the exception to arise at the moment of the healthy port's read/writes as a matter of coincidence. For example, synchronizing in the read/write block on an object which has the down port as a member and can cause the down port to be synchronized on and therefore be considered part of the app even though it is closed. But I think I have eliminated such unhappy synchronization. (When I did, I saw the frequency of the exception drop off.) So, I am at a loss.

      If anyone has any advice on this, I'd be most appreciative.
        • 1. Re: javax.comm.CommPort serial port reopening
          Let me refine my query. The exception does not occur only when I'm writing to the port that isn't unconnected. I've tried writing to it only when the unconnected port is not being reopened. The exception still occurs. It occurs when and only when the execution point of the following loop isn't at the sleep() line. Here is the pseudocode of the main loop:

          while (running) {

          if not currently attempting to reopen either port...//This conditional is a primitive boolean.
          ...write heartbeat to port 1 if it isn't down.
          ...write heartbeat to port 2 if it isn't down.

          Wait for acknowledgement of heartbeats.
          If failed to receive acknowledgement from a port, then start a reopen thread for it

          sleep(five seconds) //WE"RE SAFE HERE. The reopen thread never throws the PortInUseException when this thread asleep here.

          The reopen thread simply calls close() and javax.comm.CommPortIdentifier.getPortIdentifier(portName).open(). It does this without issue when the thread with the above loop is at the sleep() line. It throws PortInUseException if the open() attempt is made when the other thread is not at the sleep() line.

          Both the reopen thread and the main thread (whose loop is above) are in the same class, the reopen thread being an inner class (called ReconnectThread). The class has a handle to the two ports, of course, and there is another class that has a thread which listens to the ports for the acknowledgement signals from the server.

          I've tried synchronization/blocking and doing away with synchronization (in the thought that maybe the synch causes the app to mark the port as in use somehow). No difference. The loop above is the non-synched version.

          It appears that sleep() marks the port as not in use by the app and when the sleep is finished, the port is marked as in use by the app. I don't understand this.

          Any help much appreciated.
          • 2. Re: javax.comm.CommPort serial port reopening
            user961095 wrote:
            It appears that sleep() marks the port as not in use by the app and when the sleep is finished, the port is marked as in use by the app. I don't understand this.
            (warning: I have no experience with the COMM api so if I'm spouting nonsense, please ignore me).

            My interpretation is that the port is in use when you are actually reading from/writing to it, which makes the most sense to me. If you let the thread sleep it will of course not do those actions as it won't loop back to the heartbeat stuff for a few seconds.
            • 3. Re: javax.comm.CommPort serial port reopening
              That was what my first post assumed. Then, to avoid this issue, I added the primitive boolean condition that if a reconnect thread was in process, don't try writing the heartbeats to either port. This is what my second post explained. The problem didn't go away. If by chance the reconnect thread was firing the open() logic at a moment when the other thread was not asleep, I still got PortInUseException.

              It seems that sleep is freeing up the port. But perhaps there's something else going on.
              • 4. Re: javax.comm.CommPort serial port reopening
                don't underestimate the power of concurrency. The boolean flag may well not be changed before the main thread has a chance to loop again, depending on where you change it (can't see that, no code). What the main thread needs to do is block until the reopen thread is done executing. Check out the join() method on Thread for a possibility there, but since Java 5 there is also a spanking new concurrency package with many tools for managing concurrency.

                Out of interest: why is the reopen logic in a separate thread? Why not do that logic right where you are starting the thread?
                • 5. Re: javax.comm.CommPort serial port reopening
                  Thanks for the help. I've tried blocking, to no avail, but I should try again, as you say. As for the primitive boolean not being changed, my logging code tells me this is not the issue. I have an else block on the condition, like so:

                  if (not currently reopening port) {
                  else {
                  Log: "Did not send heartbeats because in reopen attempt"

                  I get PortInUseException when and only when that log statement appears. This is why I think blocking isn't going to help. I could be wrong.

                  I reopen in a separate thread because I don't want to delay the heartbeat. The reopen thread takes a couple seconds because it sleeps for one second twice (once before closing, just to give the acknowledgement a chance to show up late, which happens sometimes, and once after close() and before firing open() just to be sure all is closed with the port, though perhaps this is unnecessary.) The server is expecting it and will become impatient if it is tardy. Of course by adding the condition not to write the heartbeat at all, I am causing the server to become impatient when a reopen is occurring when a heartbeat is due. I think I should try condensing all this to one thread and seeing whether that causes the exception to vanish. EDIT: I should have said "I don't want to delay the heartbeat of the port that isn't undergoing reconnect."

                  Thanks again for your help.

                  Edited by: user961095 on Dec 8, 2011 8:13 AM
                  • 6. Re: javax.comm.CommPort serial port reopening
                    Well, I just tested the idea of doing the reopen() in the same thread as the heartbeats. It seems to make the issue go away! This is good but very strange. I will test in the deployment environment (Solaris, XEON) later (and post my results) but it seems to be a fix in my development environment (Windows laptop.) I cannot explain this. It would seem that whenever two threads have anything to do with a port, then one better be asleep whenever the other is reopening the port. It can't be awake, even if it isn't doing anything to the port, because its merely being awake causes the other to trip over PortInUseException. Either I'm missing something or this is some weird stuff here. Anyway, if I can reopen quickly enough that the server doesn't grow impatient for the heartbeat from the still-connected port, this could be a fix, albeit a mysterious one.

                    I know that Solaris/XEON can exhibit different serial port behavior from Windows. For example, when you sever a serial connection in Windows, you can just plug it back in again and the machine, without the reopen() logic being fired will see it as now open again and continue on writing and listening to it again without issue. But on my Solaris/XEON machine, once you sever a serial connection, plugging it back in again doesn't help. It's now considered closed and must be reopened by the Java code. So, it's not clear how the above fix will translate from my Windows environment to the Solaris one.
                    • 7. Re: javax.comm.CommPort serial port reopening
                      The result on the Solaris was somewhat encouraging. No longer get the PortInUseException. Instead, I get an Exception (will find out what kind later with more complete logging of its kind - whatever it is isn't listed in the API for CommPortIdentifier.open()). So, I get farther, I guess, which is encouraging. The e.getMessage() is "port currently busy." Maybe letting the port close out itself for a minute and then reopening will work.

                      By the way, someone might suggest, "So you get an unexplained exception. So what? You're catching it. Maybe when you call open() when the cable is plugged back in you won't get it and all will be well." I suppose this is possible. It's certainly worth a simple test...
                      • 8. Re: javax.comm.CommPort serial port reopening
                        The new Exception I mentioned is just a RuntimeException: "Device busy" it says. I'm not the only one to get this with Java Comm:


                        Giving the port 15 secs after close() before attempting to open again didn't help. I think Java Comm 2.x has some bugs in close(). Perhaps 3.0 fixes this but it is hard to find.
                        • 9. Re: javax.comm.CommPort serial port reopening
                          The code with the change mentioned above now works without issue in Windows but not in Solaris x86. So, I'm wondering whether "Device busy" is an issue peculiar to Solaris that I might address at the OS level, rather than the application level.
                          • 10. Re: javax.comm.CommPort serial port reopening
                            Jebus, what a cross-platform head ache this turns out to be. The threads problem stumps me a little too, it would seem like the active thread takes ownership of the serial port somehow. It might be that the comm implementation actually does some thread binding magic behind the scenes, I really don't know about that.

                            Note that there are several third party comm implementations available. The default Sun one is not slated as the most stable one; there isn't even one for comm v3 that I know of.
                            • 11. Re: javax.comm.CommPort serial port reopening
                              Yes, I'm hoping that I'll have Java Comm 3.0 in my hands soon, plus an RXTX compilation for Solaris x86m, too. If those fail, then, yes, I'll have to look at paying for a third-party product. It looks like they aren't all that expensive.

                              I could try the following work-around. Put any thread that has anything to do with the ports to sleep for a moment and then quickly call my reopen() on the port and then wake the threads up. If I end up having to try that (yikes, not a lot of fun but a somewhat klugey way to work-around a weird issue), I'll post results.

                              The daniweb thread I noted above has a sanity test in it. Will try it today. It simply is a bit of code that opens, closes and reopens a port repeatedly, so that, if successful then you know that it is possible for a Java app to open, close and reopen a port without issue on your platform. Then, assuming there's no bug in Java Comm, you at least know that either (1.) your (big, multithreaded) app has an issue you can fix where it is holding on to a port or (2.) there simply is a weird and relatively unfixable (except with klugey workarounds) issue between your platform's serial ports and multithreaded Java Comm apps. So, the test doesn't get you far, but it at least rules out the possibility that a Java Comm app simply cannot close and reopen a port on your platform at all. It would remain to be seen whether RXTX or a for-pay serial driver could pass the test.

                              This issue is kind of important in its little sphere. If you need real time messages to go over serial port and if you need redundancy (a backup serial port) because you can't afford to miss messages for six hours because someone inadvertently disconnected a serial cable, then you have to solve this issue.

                              Edited by: user961095 on Dec 9, 2011 7:35 AM
                              • 12. Re: javax.comm.CommPort serial port reopening
                                Got Java Comm 3.x. It is no improvement in this issue over 2.x.
                                • 13. Re: javax.comm.CommPort serial port reopening
                                  The issue when running on Windows mentioned upthread goes away when either (a.) I switch to RXTX instead of JavaComm or (b.) I do not add an event listener with SerialPort.addEventListener(). Therefore, it seems that SerialPort.removeEventListener() does not work in JavaComm's implementation but does work in RXTX. This fellow discovered the issue, too: http://wangdp.blogspot.com/2011/11/serial-port-in-java.html

                                  I'll need to use a compilation of RXTX for my Solaris x86 machine now.