31
31
import java .io .File ;
32
32
import java .io .IOException ;
33
33
import java .io .PrintStream ;
34
+ import java .nio .file .Files ;
35
+ import java .nio .file .Paths ;
36
+ import java .nio .file .attribute .FileTime ;
34
37
import java .util .Properties ;
35
38
import java .util .Vector ;
39
+ import java .util .concurrent .TimeUnit ;
36
40
37
41
/**
38
42
* This class handles incoming attachment requests from other VMs. Must be
@@ -54,7 +58,7 @@ public class AttachHandler extends Thread {
54
58
/**
55
59
* Time delay before we give up trying to terminate the wait loop.
56
60
*/
57
- static final long shutdownTimeoutMs = Integer . getInteger ("com.ibm.tools.attach.shutdown_timeout" , 10000 ).longValue (); //$NON-NLS-1$
61
+ static final long shutdownTimeoutMs = Long . getLong ("com.ibm.tools.attach.shutdown_timeout" , 10000 ).longValue (); //$NON-NLS-1$
58
62
private enum AttachStateValues {
59
63
ATTACH_UNINITIALIZED , ATTACH_TERMINATED , ATTACH_STARTING , ATTACH_INITIALIZED
60
64
}
@@ -118,6 +122,8 @@ static final class syncObject {
118
122
/* [PR Jazz 30075] Make syncFileLock an instance variable since it is accessed only by the attachHandler singleton. */
119
123
FileLock syncFileLock ;
120
124
125
+ static volatile Thread fileAccessTimeUpdaterThread ;
126
+
121
127
/**
122
128
* Keep the constructor private
123
129
*/
@@ -323,10 +329,91 @@ private boolean initialize() throws IOException {
323
329
syncFileLock = new FileLock (syncFileObjectTemp .getAbsolutePath (), TargetDirectory .SYNC_FILE_PERMISSIONS );
324
330
/* give other users read permission to the sync file */
325
331
332
+ if (IPC .isLinux ) {
333
+ // Update AttachAPI control file access time every sleepDays (8 days by default).
334
+ // This is to prevent Linux systemd from deleting the aging files within /tmp after 10 days.
335
+ // More details at https://github.com/eclipse-openj9/openj9/issues/18720
336
+ int sleepDays = 8 ;
337
+ String fileAccessUpdateTime = internalProperties .getProperty ("com.ibm.tools.attach.fileAccessUpdateTime" , "8" ); //$NON-NLS-1$ //$NON-NLS-2$
338
+ IPC .logMessage ("fileAccessUpdateTime = " + fileAccessUpdateTime ); //$NON-NLS-1$
339
+ try {
340
+ sleepDays = Integer .parseInt (fileAccessUpdateTime );
341
+ } catch (NumberFormatException nfe ) {
342
+ // ignore this non-fatal exception, and use the default value
343
+ }
344
+ IPC .logMessage ("fileAccessTimeUpdaterThread sleepDays = " + sleepDays ); //$NON-NLS-1$
345
+ if (sleepDays > 0 ) {
346
+ final long targetIntervalMillis = TimeUnit .DAYS .toMillis (sleepDays );
347
+ final String lastAccessTime = "lastAccessTime" ; //$NON-NLS-1$
348
+ final String commonDir = CommonDirectory .getCommonDirFileObject ().getPath ();
349
+ fileAccessTimeUpdaterThread = new Thread ("Attach API update file access time" ) { //$NON-NLS-1$
350
+ @ Override
351
+ public void run () {
352
+ VM .markCurrentThreadAsSystem ();
353
+
354
+ long lastMillis = System .currentTimeMillis ();
355
+ long sleepMillis = targetIntervalMillis ;
356
+ for (;;) {
357
+ try {
358
+ Thread .sleep (sleepMillis );
359
+ } catch (InterruptedException ie ) {
360
+ // ignore this non-fatal exception
361
+ IPC .logMessage ("fileAccessTimeUpdaterThread received an InterruptedException: " + ie .getMessage ()); //$NON-NLS-1$
362
+ }
363
+ if (isAttachApiTerminated ()) {
364
+ IPC .logMessage ("AttachAPI was terminated, fileAccessTimeUpdaterThread exits" ); //$NON-NLS-1$
365
+ break ;
366
+ }
367
+ long currentMillis = System .currentTimeMillis ();
368
+ long passedMillis = currentMillis - lastMillis ;
369
+ if (passedMillis >= sleepMillis ) {
370
+ FileTime fileTime = FileTime .fromMillis (currentMillis );
371
+ IPC .logMessage ("fileAccessTimeUpdaterThread currentMillis = " + currentMillis ); //$NON-NLS-1$
372
+ try {
373
+ // Common directory : _attachlock
374
+ File attachLock = new File (commonDir , CommonDirectory .ATTACH_LOCK );
375
+ if (attachLock .exists ()) {
376
+ // _attachlock only appears when there was an attaching request
377
+ Files .setAttribute (Paths .get (attachLock .getPath ()), lastAccessTime , fileTime );
378
+ IPC .logMessage ("fileAccessTimeUpdaterThread updated access time = " + attachLock ); //$NON-NLS-1$
379
+ }
380
+ // Common directory : _controller
381
+ Files .setAttribute (Paths .get (commonDir , CommonDirectory .CONTROLLER_LOCKFILE ), lastAccessTime , fileTime );
382
+ // Common directory : _notifier
383
+ Files .setAttribute (Paths .get (commonDir , CommonDirectory .CONTROLLER_NOTIFIER ), lastAccessTime , fileTime );
384
+ // Target directory : attachNotificationSync
385
+ Files .setAttribute (Paths .get (TargetDirectory .getSyncFileObject ().getPath ()), lastAccessTime , fileTime );
386
+ // Target directory : attachInfo
387
+ Files .setAttribute (Paths .get (TargetDirectory .getAdvertisementFileObject ().getPath ()), lastAccessTime , fileTime );
388
+ } catch (IOException ioe ) {
389
+ // ignore this non-fatal exception
390
+ IPC .logMessage ("fileAccessTimeUpdaterThread received an IOException : " + ioe .getMessage ()); //$NON-NLS-1$
391
+ }
392
+ // reset for next update
393
+ sleepMillis = targetIntervalMillis ;
394
+ lastMillis = currentMillis ;
395
+ } else {
396
+ // continue sleep()
397
+ sleepMillis = targetIntervalMillis - passedMillis ;
398
+ IPC .logMessage ("fileAccessTimeUpdaterThread currentMillis = " + currentMillis //$NON-NLS-1$
399
+ + ", passedMillis = " + passedMillis //$NON-NLS-1$
400
+ + ", sleepMillis = " + sleepMillis ); //$NON-NLS-1$
401
+ }
402
+ }
403
+ }
404
+ };
405
+ fileAccessTimeUpdaterThread .setDaemon (true );
406
+ if (isAttachApiTerminated ()) {
407
+ IPC .logMessage ("AttachAPI was already terminated, no need to start fileAccessTimeUpdaterThread" ); //$NON-NLS-1$
408
+ return false ;
409
+ }
410
+ fileAccessTimeUpdaterThread .start ();
411
+ }
412
+ }
413
+
326
414
return true ;
327
415
}
328
416
329
-
330
417
/**
331
418
* Try to read the reply. If it exists, connect to the attacher. This may be called from tryAttachTarget() in the case
332
419
* of a VM attaching to itself.
@@ -372,7 +459,6 @@ public void attachSelf(int portNumber, String key) {
372
459
* @return true if the caller should destroy the semaphore
373
460
*/
374
461
protected boolean terminate (boolean wakeHandler ) {
375
-
376
462
if (LOGGING_DISABLED != loggingStatus ) {
377
463
IPC .logMessage ("AttachHandler terminate: Attach API is being shut down, currentAttachThread = " + currentAttachThread ); //$NON-NLS-1$
378
464
}
@@ -391,7 +477,12 @@ protected boolean terminate(boolean wakeHandler) {
391
477
break ;
392
478
}
393
479
}
394
- currentAttachThread .interrupt (); /* do this after we change the attachState */
480
+ /* do this after we change the attachState */
481
+ if ((fileAccessTimeUpdaterThread != null ) && fileAccessTimeUpdaterThread .isAlive ()) {
482
+ IPC .logMessage ("fileAccessTimeUpdaterThread interrupt" ); //$NON-NLS-1$
483
+ fileAccessTimeUpdaterThread .interrupt ();
484
+ }
485
+ currentAttachThread .interrupt ();
395
486
if (wakeHandler ) {
396
487
if (LOGGING_DISABLED != loggingStatus ) {
397
488
IPC .logMessage ("AttachHandler terminate removing contents of directory : " , TargetDirectory .getTargetDirectoryPath (getVmId ())); //$NON-NLS-1$
@@ -522,6 +613,55 @@ static final class teardownHook extends Thread {
522
613
super ("Attach API teardown" ); //$NON-NLS-1$)
523
614
}
524
615
616
+ private static void threadJoinHelper (Thread thread , long shutdownDeadlineNs ) {
617
+ long timeout = 100 ;
618
+ int retryNumber = 0 ;
619
+ for (;;) {
620
+ long currentNanoTime = System .nanoTime ();
621
+ long tempTimeout = TimeUnit .NANOSECONDS .toMillis (shutdownDeadlineNs - currentNanoTime );
622
+ if (tempTimeout <= 0 ) {
623
+ // already reached shutdownDeadlineNs
624
+ // or ignore the NANOSECONDS.excessNanos() which is less than 1ms
625
+ IPC .logMessage (thread + " already reached shutdownDeadlineNs : currentNanoTime = " //$NON-NLS-1$
626
+ + currentNanoTime + ", tempTimeout = " + tempTimeout ); //$NON-NLS-1$
627
+ break ;
628
+ }
629
+ if (timeout > tempTimeout ) {
630
+ // not wait beyond shutdownDeadlineNs
631
+ timeout = tempTimeout ;
632
+ }
633
+ IPC .logMessage (thread + ": currentNanoTime = " + currentNanoTime //$NON-NLS-1$
634
+ + ", tempTimeout = " + tempTimeout //$NON-NLS-1$
635
+ + ", timeout = " + timeout ); //$NON-NLS-1$
636
+ try {
637
+ thread .join (timeout );
638
+ } catch (InterruptedException e ) {
639
+ IPC .logMessage (thread + ": join() interrupted" ); //$NON-NLS-1$
640
+ break ;
641
+ }
642
+ State state = thread .getState ();
643
+ if (state == Thread .State .TERMINATED ) {
644
+ // exit if thread is terminated
645
+ IPC .logMessage (thread + " is terminated, exit" ); //$NON-NLS-1$
646
+ break ;
647
+ }
648
+ IPC .logMessage (thread + ": state = " + state //$NON-NLS-1$
649
+ + ", timeout waiting for termination. Retry #" //$NON-NLS-1$
650
+ + retryNumber + ", timeout = " + timeout ); //$NON-NLS-1$
651
+ timeout *= 2 ;
652
+ retryNumber += 1 ;
653
+ if (thread == currentAttachThread ) {
654
+ IPC .logMessage (thread + ": currentAttachThread requires AttachHandler.terminateWaitLoop()" ); //$NON-NLS-1$
655
+ AttachHandler .terminateWaitLoop (true , retryNumber );
656
+ } else if (thread == fileAccessTimeUpdaterThread ) {
657
+ IPC .logMessage (thread + ": fileAccessTimeUpdaterThread requires thread.interrupt()" ); //$NON-NLS-1$
658
+ thread .interrupt ();
659
+ } else {
660
+ throw new InternalError (thread + ": unexpected" ); //$NON-NLS-1$
661
+ }
662
+ }
663
+ }
664
+
525
665
@ Override
526
666
public void run () {
527
667
/*[PR CMVC 188652] Suppress OOM messages from attach API*/
@@ -534,7 +674,11 @@ public void run() {
534
674
if (null == mainHandler ) {
535
675
return ; /* the constructor failed */
536
676
}
537
- long shutdownDeadlineNs = System .nanoTime () + shutdownTimeoutMs *1000000 ;
677
+ long currentNanoTime = System .nanoTime ();
678
+ long shutdownDeadlineNs = currentNanoTime + TimeUnit .MILLISECONDS .toNanos (shutdownTimeoutMs );
679
+ IPC .logMessage ("currentNanoTime = " + currentNanoTime //$NON-NLS-1$
680
+ + ", shutdownTimeoutMs = " + shutdownTimeoutMs //$NON-NLS-1$
681
+ + ", shutdownDeadlineNs = " + shutdownDeadlineNs ); //$NON-NLS-1$
538
682
boolean destroySemaphore = mainHandler .terminate (true );
539
683
try {
540
684
/*[PR CMVC 172177] Ensure the initializer thread has terminated */
@@ -548,18 +692,9 @@ public void run() {
548
692
* currentAttachThread is the same as mainHandler before the wait loop launches.
549
693
* In that case, the join is redundant but harmless.
550
694
*/
551
- int timeout = 100 ;
552
- int retryNumber = 0 ;
553
- while (System .nanoTime () < shutdownDeadlineNs ) {
554
- currentAttachThread .join (timeout ); /* timeout in milliseconds */
555
- if (currentAttachThread .getState () != Thread .State .TERMINATED ) {
556
- IPC .logMessage (currentAttachThread + "Timeout waiting for wait loop termination. Retry #" + retryNumber ); //$NON-NLS-1$
557
- timeout *= 2 ;
558
- AttachHandler .terminateWaitLoop (true , retryNumber );
559
- ++retryNumber ;
560
- } else {
561
- break ;
562
- }
695
+ threadJoinHelper (currentAttachThread , shutdownDeadlineNs );
696
+ if ((fileAccessTimeUpdaterThread != null ) && fileAccessTimeUpdaterThread .isAlive ()) {
697
+ threadJoinHelper (fileAccessTimeUpdaterThread , shutdownDeadlineNs );
563
698
}
564
699
} catch (InterruptedException e ) {
565
700
IPC .logMessage ("teardown join with attach handler interrupted" ); //$NON-NLS-1$
0 commit comments