|
26 | 26 | import static com.oracle.truffle.espresso.libjavavm.Arguments.abort;
|
27 | 27 | import static com.oracle.truffle.espresso.libjavavm.Arguments.abortExperimental;
|
28 | 28 | import static com.oracle.truffle.espresso.libjavavm.arghelper.ArgumentsHandler.isBooleanOption;
|
29 |
| -import static java.nio.file.StandardOpenOption.APPEND; |
30 |
| -import static java.nio.file.StandardOpenOption.CREATE; |
31 |
| -import static java.nio.file.StandardOpenOption.CREATE_NEW; |
32 |
| -import static java.nio.file.StandardOpenOption.WRITE; |
33 | 29 |
|
34 |
| -import java.io.BufferedOutputStream; |
35 | 30 | import java.io.IOException;
|
36 |
| -import java.io.OutputStream; |
37 |
| -import java.nio.channels.FileChannel; |
38 |
| -import java.nio.channels.OverlappingFileLockException; |
39 |
| -import java.nio.file.FileAlreadyExistsException; |
40 |
| -import java.nio.file.Files; |
41 |
| -import java.nio.file.LinkOption; |
42 |
| -import java.nio.file.NoSuchFileException; |
43 | 31 | import java.nio.file.Path;
|
44 | 32 | import java.nio.file.Paths;
|
45 | 33 | import java.util.ArrayList;
|
|
50 | 38 | import java.util.Map;
|
51 | 39 | import java.util.logging.Level;
|
52 | 40 |
|
53 |
| -import org.graalvm.collections.Pair; |
| 41 | +import org.graalvm.launcher.Launcher; |
54 | 42 | import org.graalvm.options.OptionCategory;
|
55 | 43 | import org.graalvm.options.OptionDescriptor;
|
56 | 44 | import org.graalvm.options.OptionDescriptors;
|
@@ -90,7 +78,7 @@ void argumentProcessingDone() {
|
90 | 78 | }
|
91 | 79 | if (logFile != null) {
|
92 | 80 | try {
|
93 |
| - builder.logHandler(newLogStream(logFile)); |
| 81 | + builder.logHandler(Launcher.newLogStream(logFile)); |
94 | 82 | } catch (IOException ioe) {
|
95 | 83 | throw abort(ioe.toString());
|
96 | 84 | }
|
@@ -320,155 +308,4 @@ private static List<Instrument> sortedInstruments(Engine engine) {
|
320 | 308 | return instruments;
|
321 | 309 | }
|
322 | 310 |
|
323 |
| - /** |
324 |
| - * Creates a new log file. The method uses a supplemental lock file to determine the file is |
325 |
| - * still opened for output; in that case, it creates a different file, named `path'1, `path`2, |
326 |
| - * ... until it finds a free name. Files not locked (actively written to) are overwritten. |
327 |
| - * |
328 |
| - * @param path the desired output for log |
329 |
| - * @return the OutputStream for logging |
330 |
| - * @throws IOException in case of I/O error opening the file |
331 |
| - * @since 20.0 |
332 |
| - */ |
333 |
| - protected static OutputStream newLogStream(Path path) throws IOException { |
334 |
| - Path usedPath = path; |
335 |
| - Path fileNamePath = path.getFileName(); |
336 |
| - String fileName = fileNamePath == null ? "" : fileNamePath.toString(); |
337 |
| - Path lockFile = null; |
338 |
| - FileChannel lockFileChannel = null; |
339 |
| - for (int unique = 0;; unique++) { |
340 |
| - StringBuilder lockFileNameBuilder = new StringBuilder(fileName); |
341 |
| - if (unique > 0) { |
342 |
| - lockFileNameBuilder.append(unique); |
343 |
| - usedPath = path.resolveSibling(lockFileNameBuilder.toString()); |
344 |
| - } |
345 |
| - lockFileNameBuilder.append(".lck"); |
346 |
| - lockFile = path.resolveSibling(lockFileNameBuilder.toString()); |
347 |
| - Pair<FileChannel, Boolean> openResult = openChannel(lockFile); |
348 |
| - if (openResult != null) { |
349 |
| - lockFileChannel = openResult.getLeft(); |
350 |
| - if (lock(lockFileChannel, openResult.getRight())) { |
351 |
| - break; |
352 |
| - } else { |
353 |
| - // Close and try next name |
354 |
| - lockFileChannel.close(); |
355 |
| - } |
356 |
| - } |
357 |
| - } |
358 |
| - assert lockFile != null && lockFileChannel != null; |
359 |
| - boolean success = false; |
360 |
| - try { |
361 |
| - OutputStream stream = new LockableOutputStream( |
362 |
| - new BufferedOutputStream(Files.newOutputStream(usedPath, WRITE, CREATE, APPEND)), |
363 |
| - lockFile, |
364 |
| - lockFileChannel); |
365 |
| - success = true; |
366 |
| - return stream; |
367 |
| - } finally { |
368 |
| - if (!success) { |
369 |
| - LockableOutputStream.unlock(lockFile, lockFileChannel); |
370 |
| - } |
371 |
| - } |
372 |
| - } |
373 |
| - |
374 |
| - private static Pair<FileChannel, Boolean> openChannel(Path path) throws IOException { |
375 |
| - FileChannel channel = null; |
376 |
| - for (int retries = 0; channel == null && retries < 2; retries++) { |
377 |
| - try { |
378 |
| - channel = FileChannel.open(path, CREATE_NEW, WRITE); |
379 |
| - return Pair.create(channel, true); |
380 |
| - } catch (FileAlreadyExistsException faee) { |
381 |
| - // Maybe a FS race showing a zombie file, try to reuse it |
382 |
| - if (Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS) && isParentWritable(path)) { |
383 |
| - try { |
384 |
| - channel = FileChannel.open(path, WRITE, APPEND); |
385 |
| - return Pair.create(channel, false); |
386 |
| - } catch (NoSuchFileException x) { |
387 |
| - // FS Race, next try we should be able to create with CREATE_NEW |
388 |
| - } catch (IOException x) { |
389 |
| - return null; |
390 |
| - } |
391 |
| - } else { |
392 |
| - return null; |
393 |
| - } |
394 |
| - } |
395 |
| - } |
396 |
| - return null; |
397 |
| - } |
398 |
| - |
399 |
| - private static boolean isParentWritable(Path path) { |
400 |
| - Path parentPath = path.getParent(); |
401 |
| - if (parentPath == null && !path.isAbsolute()) { |
402 |
| - parentPath = path.toAbsolutePath().getParent(); |
403 |
| - } |
404 |
| - return parentPath != null && Files.isWritable(parentPath); |
405 |
| - } |
406 |
| - |
407 |
| - private static boolean lock(FileChannel lockFileChannel, boolean newFile) { |
408 |
| - boolean available = false; |
409 |
| - try { |
410 |
| - available = lockFileChannel.tryLock() != null; |
411 |
| - } catch (OverlappingFileLockException ofle) { |
412 |
| - // VM already holds lock continue with available set to false |
413 |
| - } catch (IOException ioe) { |
414 |
| - // Locking not supported by OS |
415 |
| - available = newFile; |
416 |
| - } |
417 |
| - return available; |
418 |
| - } |
419 |
| - |
420 |
| - private static final class LockableOutputStream extends OutputStream { |
421 |
| - |
422 |
| - private final OutputStream delegate; |
423 |
| - private final Path lockFile; |
424 |
| - private final FileChannel lockFileChannel; |
425 |
| - |
426 |
| - LockableOutputStream(OutputStream delegate, Path lockFile, FileChannel lockFileChannel) { |
427 |
| - this.delegate = delegate; |
428 |
| - this.lockFile = lockFile; |
429 |
| - this.lockFileChannel = lockFileChannel; |
430 |
| - } |
431 |
| - |
432 |
| - @Override |
433 |
| - public void write(int b) throws IOException { |
434 |
| - delegate.write(b); |
435 |
| - } |
436 |
| - |
437 |
| - @Override |
438 |
| - public void write(byte[] b) throws IOException { |
439 |
| - delegate.write(b); |
440 |
| - } |
441 |
| - |
442 |
| - @Override |
443 |
| - public void write(byte[] b, int off, int len) throws IOException { |
444 |
| - delegate.write(b, off, len); |
445 |
| - } |
446 |
| - |
447 |
| - @Override |
448 |
| - public void flush() throws IOException { |
449 |
| - delegate.flush(); |
450 |
| - } |
451 |
| - |
452 |
| - @Override |
453 |
| - public void close() throws IOException { |
454 |
| - try { |
455 |
| - delegate.close(); |
456 |
| - } finally { |
457 |
| - unlock(lockFile, lockFileChannel); |
458 |
| - } |
459 |
| - } |
460 |
| - |
461 |
| - private static void unlock(Path lockFile, FileChannel lockFileChannel) { |
462 |
| - try { |
463 |
| - lockFileChannel.close(); |
464 |
| - } catch (IOException ioe) { |
465 |
| - // Error while closing the channel, ignore. |
466 |
| - } |
467 |
| - try { |
468 |
| - Files.delete(lockFile); |
469 |
| - } catch (IOException ioe) { |
470 |
| - // Error while deleting the lock file, ignore. |
471 |
| - } |
472 |
| - } |
473 |
| - } |
474 | 311 | }
|
0 commit comments