Giter Club home page Giter Club logo

kilim's Introduction

Kilim: Continuations, Fibers, Actors and message passing for the JVM

Kilim is composed of 2 primary components:

  • The Kilim weaver modifies the bytecode of compiled java classes, enabling a method to save it's state and yield control of it's thread, ie to cooperatively multitask
  • The Kilim runtime library provides constructs that leverage the weaver to simplify concurrent programming, including Coroutines, Task, Actors, Mailboxes (aka channels), and Generators

Together, these facilities allow for simple concurrency and can scale to millions of concurrent tasks

Usage

Code can be woven:

  • during compilation by using the maven plugin
  • during compilation by running kilim.tools.Weaver
  • at runtime by invoking kilim.tools.Kilim com.yourcompany.yourclass
  • at runtime by including if (kilim.tools.Kilim.trampoline(false,args)) return; at the start of main()

Writing code with Kilim

Please see docs/manual.txt and docs/kilim_ecoop08.pdf for a brief introduction.

  • src/kilim/examples contains some simple examples
  • src/kilim/bench contains some performance benchmarks
  • kilim streams is a port of java 8 streams to kilim
  • java empower is a comparison of several async web server techs
    • kj/src/main/java/KilimJetty.java shows integrating with jetty async
    • kilim/src/main/java/KilimHello.java shows the built-in kilim web server (which in addition to doing async connections also does async io)

"hello world" in kilim

for an example of a project that uses kilim (with the trampoline for runtime weaving) see the battle royale demo in this repository. clone this repository, and from that directory execute mvn package exec:java -Dexec.mainClass=kilim.demo.Battle

Similarity to Java Futures

java.util.concurrent.Future<V> is an interface that can represents the result of an asynchronous computation. kilim pre-dates java futures, and uses a slightly different api, but kilim supports the same notion, ie to block until an async computation finishes:

  • kilim.Task.joinb() blocks until a Task completes
  • kilim.Task.isDone() returns true if this Task completed
  • cancellation isn't explicitly supported
  • kilim.Mailbox.getb() is also similar

these methods allow synchronizing threads with async computations. however, the real power of kilim is in enabling communication between async computations. for this, use the join() and get() methods which are Pausable

Maven

for an example of a project that uses kilim, see the kilim jetty demo in this repository

  • the pom.xml specifies kilim as both a dependency and a plugin for ahead-of-time weaving
  • this version supports java 8, 9, 11, 12 and 13-ea (and 10 if you don't use lambdas)
  • there are dedicated artifacts for java 7 and 10 (see below)

the dependency:

    <dependency>
        <groupId>org.db4j</groupId>
        <artifactId>kilim</artifactId>
        <version>2.0.1</version>
    </dependency>

weaving with the kilim plugin:

    <plugin>
        <groupId>org.db4j</groupId>
        <artifactId>kilim</artifactId>
        <version>2.0.1</version>
        <executions>
            <execution>
                <goals><goal>weave</goal></goals>
            </execution>
        </executions>
    </plugin>

Overview

  • java.lang.Runnable: once a java.lang.Task starts running, it takes over the thread until it returns

  • kilim.Continuation: like java.lang.Runnable, but can yield (relinquish control of the thread) while preserving state. It’s caller must arrange to resume it at some appropriate time. Used for event-driven state machines where the event loop knows when to resume. The programmer is in charge of the event loop.

  • kilim.Task: like kilim.Continuation, but specifies a reason that it yields, and a scheduler automatically resumes it when the reason is no longer true. Typically used for a system of communicating state machines that communicate using Mailboxes. Releases the programmer from the job of mapping fibers to thread and of managing an event loop and the delivery of events.

  • kilim.Pausable: a hypothetical exception used to declare intent. a method that declares this to be thrown will trigger the weaver

  • kilim.Mailbox: a queue with Pausable methods that cause the calling Task method to yield when an operation would otherwise block and to resume automatically when the Mailbox because available for reading or writing

  • kilim.Fiber: the structure that stores the Continuation (and Task) state

Java Versions

java 8, 11 and 12 are the recommended platforms, but 7, 8, 9, and 10 are regularly tested, and in theory java 6 could probably still be made to work without too much work

java 8, java 9, java 11, java 12 and java 13-ea:

  • maven central: org.db4j : kilim : 2.0.2
  • compiled with java 8 bytecode
  • ASM 7.1 supports all versions of java through java 13-ea (and presumably, java 13 when it's released)

other versions and notes on limitations

java 7:

  • JAVA_HOME=path/to/java7 ant clean weave jar
  • see demos/java7 for usage examples
  • some features are not available, eg jetty integration and lambdas
  • this version is incompatible with lambdas in later java versions because default interface methods aren't supported
  • maven central: 2.0.1-jdk7

java 9:

  • the java 8 compiled version supports java 9
  • see demos/battle/pom9.xml for a usage example
  • kilim does not explicitly support modules, but works with the builtin fallback support, see below
  • JShell works - see demos/jshell

java 10:

  • java 10 has a bug and refuses to load some valid lambdas
  • https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8209112
  • this is already fixed in java 11 but will not be fixed in java 10 due to the new release cycle
  • throws java.lang.NoClassDefFoundError when attempting to load a woven fiber-less lambda
  • workaround: use lambdas that take an explicit last parameter Fiber dummy and a corresponding default method without that last parameter
  • the Fiber argument should not be accessed in the lambda
  • to call a Pausable lambda, call the default method
  • github tag: java10
  • all lambdas that will be loaded need to be woven with this java10 "fiber-included" flavor of kilim
  • this will work fine with java 8 or 9 as well, however it exposes the fiber to the user and makes it harder to detect unwoven Pausable methods, so it's use is discouraged unless you need to support java 10
  • maven central: 2.0.0-28-jdk10
    interface Lambda {
        void execute(Fiber fiber) throws Pausable, Exception;
        default void execute() throws Pausable, Exception {}
    }
    static void dummy() throws Pausable, Exception {
        Lambda lambda = dummy -> {
            Task.sleep(1000);
            System.out.println("hello world");
        };
        lambda.execute();
    }

java 11:

  • constant dynamics and preview classes are not yet supported - they will be when usage in the wild is seen
  • JEP 330 single-file source invocation works with java 11
    • the JEP 330 class loader has some limitations which must be worked around
    • for java 11, use the kilim jar as a -javaagent (fixed in java 12)
    • see demos/java11

specific java features

lambdas:

jshell:

  • working
  • see demos/jshell for an example of automatic weaving

JEP-330 single file source invocation

  • working
  • see demos/java11 for an example
  • for java 11, a java agent (included) is needed, see above (this is fixed in java 12)
  • call Kilim.trampoline in main to enable weaving
  • eg for java 12:
    public static void main(String[] args) {
        if (kilim.tools.Kilim.trampoline(new Object() {},false,args)) return;
    ...

modules:

  • kilim works with java 9 and later using the builtin fallback support
  • no module-info.java is provided
    • if you have a demo project that you can share that "depends" on modules, create an issue and it will be investigated

Project Loom:

  • Project Loom is not yet released and is not yet supported by kilim
    • some testing has been done
  • Loom attempts to run a much larger subset of the java language than kilim, at least initially at the expense of performance
  • when it is released, kilim will integrate with Loom fibers in whatever capacity makes sense

Building

summary:

  • maven and ant are used cooperatively
  • maven is used for downloading dependencies (or manually copy them to ./libs - see pom.xml)
    • only needs to be done once (until dependencies change)
    • mvn initialize (but any pom-based mvn command should work too)
    • and cleaner to delete the copied jars
  • maven can also be used for building, but tests are disabled
  • there's a kilim maven plugin, but it's not used here to avoid a circular dependency - the weaver is run directly instead (using ant)
  • the plugin is only built during the maven build, but once built will be packaged by ant as well, eg mvn package && ant jar

simple: mvn install

build with tests: ant clean testjit test jar doc

details:

  • testjit runs the tests (after compiling) using the runtime weaver
  • test runs the tests using the compile-time weaver, as well as some tests that don't require weaving
  • doc generates sources.jar and javadoc.jar
  • mvn install:install-file -DpomFile=pom.xml -Dfile=$(target/kilim*.jar) -Dsources=target/sources.jar -Djavadoc=target/javadoc.jar

Support

public support:

nqzero is currently the primary maintainer. he's focused on making Kilim easy to use and reliable and is actively using Kilim

Sriram is the original author (in 2006 !) and deserves a great deal of thanks for his excellent work. He continues to provide guidance on kilim and is especially interested in theory and performance, but is not actively using kilim today. He can be reached at kilim at malhar.net

Users

a number of companies (or their employees) appear to have been using Kilim recently and have contributed

Copyright and License

Kilim v2.0

  • Copyright (c) 2006, 2014 Sriram Srinivasan (kilim at malhar.net)
  • Copyright (c) 2016 nqzero
  • Copyright (c) 2013 Nilang Shah
  • Copyright (c) 2013 Jason Pell
  • Copyright (c) 2013 Jestan Nirojan (maven plugin)

This software is released under an MIT-style license (please see the License file). Unless otherwise noted, all files in this distribution are offered under these terms, and files that explicitly refer to the "MIT License" refer to this license

kilim's People

Contributors

feuermurmel avatar gww1945 avatar jestan avatar kilim avatar krestenkrab avatar nilangshah avatar pellcorp avatar ravikant86 avatar seedeed avatar sriram-srinivasan avatar yyonghe avatar zbigniew-mandziejewicz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kilim's Issues

How to create a jdk dynamic proxy calls Pausable method?

I want to create a dynamic proxy, this proxy calls methods which are Pausable.
but throws exception:

java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1342)
at kilim.Task.errNotWoven(Task.java:231)
at com.xxx.XXInvocationHandler.invoke(XXInvocationHandler.java)
at com.sun.proxy.$Proxy17.dotXXX(Unknown Source)

use Proxy.newProxyInstance() to create proxy

"invoke" method in XXInvocationHandler is already declare as Pausable, and is woven

need help!
THANK YOU!

Using error reporting in spring projects

image
It's the boot method.

The following is the exception information started:
Connected to the target VM, address: '127.0.0.1:59025', transport: 'socket'
Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at kilim.tools.Kilim.trampoline(Kilim.java:113)
at kilim.tools.Kilim.trampoline(Kilim.java:65)
at com.star.demo.BootDemoApplication.main(BootDemoApplication.java:11)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at kilim.WeavingClassLoader.run(WeavingClassLoader.java:122)
at kilim.tools.Kilim.trampoline(Kilim.java:110)
... 2 more
Caused by: java.lang.IllegalArgumentException: Cannot instantiate interface org.springframework.context.ApplicationContextInitializer : org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:438)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:420)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:413)
at org.springframework.boot.SpringApplication.(SpringApplication.java:269)
at org.springframework.boot.SpringApplication.(SpringApplication.java:250)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1214)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1203)
at com.star.demo.BootDemoApplication.main(BootDemoApplication.java:14)
... 8 more
Caused by: java.lang.IllegalArgumentException: class org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer is not assignable to interface org.springframework.context.ApplicationContextInitializer
at org.springframework.util.Assert.assignableCheckFailed(Assert.java:673)
at org.springframework.util.Assert.isAssignable(Assert.java:604)
at org.springframework.util.Assert.isAssignable(Assert.java:635)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:432)
... 15 more

And finally, my pom.xml file.

org.springframework.boot spring-boot-starter-parent 2.1.7.RELEASE com.star demo 0.0.1-SNAPSHOT boot-demo Demo project for Spring Boot
<properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.db4j</groupId>
        <artifactId>kilim</artifactId>
        <version>2.0.2</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.db4j</groupId>
            <artifactId>kilim</artifactId>
            <version>2.0.2</version>
            <executions>
                <execution>
                    <goals><goal>weave</goal></goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

能不能帮忙看下原因

Implementation of equals() and merge() in class kilim.analysis.Value (out of date FIXME?)

The equals() method of kilim.analysis.Value has the following implementation of equals:

public boolean equals(Object obj) {
    // TODO FIXME : This is WRONG. Two values can be created at the same site when
    // entering a method (all incoming parameter values are given location 0).
    // That would make two distinct params with the same type equal.
    if (this == obj) return true;
    Value other = (Value)obj;
    if (this.typeDesc.equals(other.typeDesc) &&
            this.constVal.equals(other.constVal) &&
                this.numSites == other.numSites) {
        // Check sites
        for (int i = 0; i < this.numSites; i++) {
            if (sites[i] != other.sites[i]) {
                return false;
            }
        }
            return true;
        }
    return false;
}

The comment says that the equals implementation is wrong. Is this really the case, or is the comment out of sync with the code?

If the check this.constVal.equals(other.constVal) is removed, then I agree with the comment (since then you could not distinguish between two formal parameters with the same type, both of which have have site position zero and the typeDesc's are the same). However, checking the constVal's guards against this, right?

By the same argument, in the the implementation of the method merge() in the same class, shouldn't the line

if (newNumSites != numSites || newType != typeDesc) { ... }

be replaced with:

if (newNumSites != numSites || newType != typeDesc || !constVal.equals(other.constVal)) { ... }

Right?

Therefore, in summary:

  1. I believe that the FIXME comment in equals() should be deleted, since it is out-of-sync with the code.
  2. The implementation of merge() may be have bug, since the above check is missing. (Although I expect merge() would never be called in this case, it should operate correctly nonetheless.)

Many thanks!

Invoking non-static method throws NullPointerException

stackTrace

java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at kilim.Task.invoke(Task.java:278)
at kilim.examples.Reflect.execute(Reflect.java:16)
at kilim.Task._runExecute(Task.java:432)
at kilim.WorkerThread.run(WorkerThread.java:32)

package kilim.examples;

import java.lang.reflect.Method;

import kilim.Pausable;
import kilim.Task;

public class Reflect extends Task {
    @Override
    public void execute() throws Pausable, Exception {
        int n = test();
        System.out.println("test (normal): " + n);

        // Invoking test() via reflection
        Method mthd = Reflect.class.getDeclaredMethod("test", new Class[0]);
        Object ret = Task.invoke(mthd, this, /* no args */(Object[]) null);
        System.out.println("test (reflect): " + ret);
        System.exit(0);
    }

   // non-static method
    public int test() throws Pausable {
        int m = 10;
        for (int i = 0; i < 2; i++) { // Force multiple yields
            Task.sleep(100);
            m *= 2;
        }
        return m; // must return 40 if all goes well.
    }

    public static void main(String args[]) {
        Reflect ref = new Reflect();
        ref.start();
        ref.joinb();
    }
}

Where is EventSubscriber.onEvent() implemented?

Hi, guys, I want to consult where the method EventSubscriber.onEvent() is implemented?

I see, when doing mailbox.put(msg), method put calls put(msg, t), here t will be added to the waiting list srcs, and when msg space is availabe, it maybe notified by calling t.onEvent().

But I read the Task.java, class Task doesn't implement the method onEvent(), so I want to ask where is the onEvent method implemented by class Task. Will the weaver handle this?

Thanks in advance!

switch to Opcodes.ASM5

trying to weave an interface with a default method results in an error:

"INVOKESPECIAL/STATIC on interfaces require ASM 5"

kilim configures asm with Opcodes.ASM4. we should switch to ASM5

does kilim handle notify/wait methods?

My initial idea was to use many coroutines or fibers instead to use many threads because it is more scalable.
I thought i could realize a scheduler in which i can push many coroutines.
Pratically it is a coroutines pool inside the same thread(in general i could also use a coroutine pool running over a thread pool with many thread as core cpus present in the machine and put a coroutine in one of the available thread running) .

When a corotuine is blocked by a wait() instruction, that is inside the code executed by coroutine, it is not necessary to block the thread where coroutine is executed but it is sufficient to suspend current coroutine.
When a corotuine is suspended , it is taken another coroutine ready to be resumed. In this way the thread is never blocked ... and the global performance will be very high.

For this reason is important to instrument synchronized blocks but also notify/wait. It is possible to use inside your fibers or coroutine notify/wait so they suspend just fiber/coroutine and not all thread?

Local vars not restored properly after exception is thrown

Below is a simple test which demonstrates this issue. The code prints out

  0 = 0
  1 = 1
  2 = 2
  3 = 3

While the expected print out should be:

  0 = 0
  1 = 1
  2 = 2
  3 = 3
public class Exceptions extends Task {
    
    private void f() throws Pausable {
        Task.sleep(10);
        throw new RuntimeException();
    }

    public void execute() throws Pausable{
        int foo = 0;
        Task.sleep(10);
        System.out.println(foo + " = 0");
        foo = 1;
        Task.sleep(10);
        System.out.println(foo + " = 1");
        foo = 2;
        Task.sleep(10);
        System.out.println(foo + " = 2");
        try {
            foo = 3;
            f();
        } catch (Throwable t) {
            System.out.println(foo + " = 3");
        }
    }

    public static void main(String args[]) {
        new Exceptions().start();
    }
}

Here's a patch which solves this problem:

diff --git a/src/kilim/analysis/MethodWeaver.java b/src/kilim/analysis/MethodWeaver.java
index ea63a80..724cce9 100755
--- a/src/kilim/analysis/MethodWeaver.java
+++ b/src/kilim/analysis/MethodWeaver.java
@@ -415,15 +415,16 @@ public class MethodWeaver {
         VMType.loadVar(mv, VMType.TOBJECT, getFiberVar());
         mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "upEx", "()I");
         // fiber.pc is on stack
-        Label[] labels = new Label[cwList.size() + 1];
-        labels[0] = resumeLabel;
+        Label[] labels = new Label[cwList.size()];
+        int[] keys = new int[cwList.size()];
         for (int i = 0; i < cwList.size(); i++) {
-            labels[i + 1] = new Label();
+            labels[i] = new Label();
+            keys[i] = callWeavers.indexOf(cwList.get(i)) + 1;
         }
-        mv.visitTableSwitchInsn(0, cwList.size(), resumeLabel, labels);
-        int i = 1;
+        mv.visitLookupSwitchInsn(resumeLabel, keys, labels);
+        int i = 0;
         for (CallWeaver cw: cwList) {
-            if (i > 1) {
+            if (i > 0) {
                 // This is the jump (to normal exception handling) for the previous
                 // switch case.
                 mv.visitJumpInsn(GOTO, resumeLabel);

CachedClassMirrors.getDeclaredMethods should never return null

I have created a classloader that does kilim weaving at runtime. I ran into a problem where the kilim weaver tosses a NullPointerException when trying to weave an interface class that had no declared methods. Turned out to be caused by the fact that the CachedClassMirrors.getDeclaredMethods method returns null for such a class. Since the caller did not check for null this caused a NullPointerException. The CachedClassMirrors.getDeclaredMethods method should return an empty array in this case.

Here's the old version of the method...


    public MethodMirror[] getDeclaredMethods() {
        return declaredMethods;
    }

Here's the new version...


    public MethodMirror[] getDeclaredMethods() {
        if (declaredMethods == null)
            return new MethodMirror[0];
        return declaredMethods;
    }

a thread-safe problem

Hi, I read the code of writeHeader method of kilim.http.HttpResponse class recently. And I found that a static field gmtdf with type java.text.SimpleDateFormat is used for writing HTTP Date header. But as is known to me, the format method of java.text.SimpleDateFormat is not safe in concurrent environment without any synchronization. In order to solve this problem, I think creating a SimpleDateFormat instance for every HttpResponse.writeHeader call, adding an external synchronized block for SimpleDateFormat.format call, or using ThreadLocal for field gmtdf will all be helpful. Anyway, I can submit a PR for this problem after a confirm.

support java 8 and lambdas

add support for java 8, invokedynamic and lambda expressions

to support java 8 we need:

  • ASM 5.0
  • invokedynamic
  • lambda expressions

woven tests fail with Java 7 preview on Mac

I installed the Java 7 preview found http://jdk7.java.net/macportpreview/

Then I set JAVA_HOME='/Library/Java/JavaVirtualMachines/JDK 1.7.0 Developer Preview.jdk/Contents/Home'

Running:

ant clean all test

Returns

  testwoven:
     [echo] Testing Tasks ======================
     [java] .E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E
     [java] Time: 0.009
     [java] There were 32 errors:
     [java] 1) testDupsInStack(kilim.test.TestYield)java.lang.VerifyError: Expecting a stackmap frame at branch target 18 in method kilim.Task.pause(Lkilim/PauseReason;Lkilim/Fiber;)V at offset 4
     [java]     at kilim.test.TestYield.testDupsInStack(TestYield.java:43)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     [java] 2) testConstantsInStack(kilim.test.TestYield)java.lang.VerifyError: Expecting a stackmap frame at branch target 18 in method kilim.Task.pause(Lkilim/PauseReason;Lkilim/Fiber;)V at offset 4
     [java]     at kilim.test.TestYield.testConstantsInStack(TestYield.java:47)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     [java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
... continue 30 more tests...

Local vars not restored properly after call pausable method and throw exception

public class Exceptions extends Task {
private String fWithOutMailBox() throws Pausable {
throw new RuntimeException(); // no pausable method
}

private String fWithMailBox() throws Pausable {
    new Mailbox<String>().get(1000);  // has pausable method
    throw new RuntimeException();
}

public void execute() throws Pausable {
    String foo = "data";
    try {
        foo = fWithOutMailBox();
    } catch (Throwable t) {
        System.out.println("foo=" + foo);
    }
    String foo2 = "data";
    try {
        foo2 = fWithMailBox();
    } catch (Throwable t) {
        System.out.println("foo2=" + foo2);
    }
}

public static void main(String args[]) {
    new Exceptions().start();
}

}
================expect result will be
foo=data
foo2=data
================while real result is
foo=data
foo2=null

@synchronized annotation

This is just a note to document this idea, I might try to implement this...

Currently synchronized methods must be rewritten to use the kilim.ReentrantLock.
So this class...

class SomeClass {
    synchronized void someMethod() throws Pausable { 
    }
}

needs to be rewritten like this...

class SomeClass {
    private final kilim.ReentrantLock lock= new kilim.ReentrantLock();
    void someMethod() throws Pausable { 
        lock.lock();
        try {
        }
        finally {
            lock.unlock();
        }
    }
}

However, it would be really convenient if kilim weaver would do this automatically. I imagine an annotation named @synchronized that would replace the synchronized keyword. Thus, the original method could just be written like this...

class SomeClass {
    @synchronized void someMethod() throws Pausable { 
    }
}

and the kilim weaver would apply the appropriate changes using kilimReentrantLock.

Generated Mailbox.select borks Eclipse

It seems that weaver is mutating Mailbox.select(Mailbox... mboxes) to Mailbox.select(Mailbox[] mboxes, Fiber fiber). That confuses Eclipse and causes constant flood of exceptions coming from internal parser / compiler.

Mailbox<String> foo = new Mailbox<String>();
Mailbox<String> bar = new Mailbox<String>();

Mailbox.select(foo, bar); // kaboom!

Ability to provide uncaught exception handler for Scheduler

There is a piece of code in Task._runExecute() that handles uncaught exceptions:

    } catch (Throwable th) {
        th.printStackTrace();

Could you please redesign this code to allow supplying an uncaught exception handler to Scheduler. Thanks for this great framework.

TaskGroup tasks not being removed.

    TaskGroup g = new TaskGroup();
    Field f = TaskGroup.class.getDeclaredField("addedTasksMB");
    f.setAccessible(true);

    Mailbox<Task> mb = (Mailbox<Task>) f.get(g);

    g.add(Task.fork(() -> System.err.println(1)));
    g.add(Task.fork(() -> System.err.println(2)));
    g.joinb();

    System.err.println("--> SIZE: " + mb.size()); //0, which is expected.

    g.add(Task.fork(() -> System.err.println(3)));
    g.add(Task.fork(() -> System.err.println(4)));
    g.joinb();

    System.err.println("--> SIZE: " + mb.size()); //2, but shouldn't this be 0?

I'm trying to reuse a TaskGroup instance. This may not be the intended usage, but if it is it seems that the number of tasks stored in the group doesn't correctly get removed when being reused.

Exception catch problem

Hi, our team use kilim based on kilim1.0. Here, we has a problem about Exception-catch .
The problem we can reprodue by code:

package kilim.examples;

import kilim.Mailbox;
import kilim.Pausable;
import kilim.Task;

public class IllegalArException extends Task {
	public static void main(String[] args) {
		new IllegalArException().start();
	}

	public void execute() throws Pausable {
		int i = 2;
		try {
			new Mailbox<String>().get(1000);// RPC
			throw new DolphinRunException();
		} catch (DolphinRunException ex) {
			System.out.println("DolphinRunException:" + i);
		} catch (Exception ex) {
			System.out.println("Exception:" + i);
		}
	}

}

class DolphinRunException extends RuntimeException {
	
}

expect result:

DolphinRunException:2

but we get the result:

Exception:2

Thanks first.

pass task context when dealing with Java Dynamic Proxy

Hi , create a new Task inside Dynamic Proxy invoke method could get around the non-weaved problem , but if i put the execution logic inside the Task Body, then i will lost the previous Task's context .
`@override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

final Method mtd = method;
final Object[] ags = args;
if (!sppCmdMap.containsKey(method.getName())) {
    return null;
}
final RpcContext rpcContext = RpcContext.getContext(KilimTask.getCurrentTask().id);
Task t = new Task() {
    public void execute() throws Exception, Pausable {

        if (!sppCmdMap.containsKey(mtd.getName())) {
            return;
        }
        RpcCmdInfo cmd = sppCmdMap.get(mtd.getName());
        if (ags[0] instanceof List) {
            List<Message> reqs = (List<Message>) ags[0];
            exit(rpcInvokeBatch(reqs, cmd, rpcContext));
        } else {
            Message req = (Message) ags[0];
            exit(rpcInvoke(req, cmd, rpcContext));
        }
    }
};
t.start();
ExitMsg m = t.joinb();
return m.result;

}
`

here if i want get the previous Task's Context , i have to use KilimTask.getCurrentTask().id
but this is a Pausable method ...
is there any good idea to solve this ?
Tks advance ! : )
BTW , Kilim is really awesome ! our team is really enjoy with it .

runtime weaver with java 8: java.lang.ClassCircularityError

i'm trying to use the runtime weaver with java 8 (asm5-jdk8 branch). for some simple classes it works, but for others, such as kilim.examples.Tree, i get errors

ant clean compile
cp -R classes c1
ant weave
cp -R classes c2
rm -R c2/kilim/examples/
java -cp "c2:libs/*" -Dkilim.class.path=c1 kilim.tools.Kilim kilim.examples.Spawn
java -cp "c2:libs/*" -Dkilim.class.path=c1 kilim.tools.Kilim kilim.examples.Tree

Spawn works (prints "Hello from 0...)", Tree fails:

Exception in thread "main" java.lang.ClassCircularityError: kilim/examples/Tree
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
    at java.lang.Class.getDeclaredMethods(Class.java:1962)
    at kilim.mirrors.RuntimeClassMirror.getDeclaredMethods(RuntimeClassMirrors.java:163)
    at kilim.mirrors.Detector.findPausableMethod(Detector.java:119)
    at kilim.mirrors.Detector.getPausableStatus(Detector.java:71)
    at kilim.analysis.MethodFlow.visitMethodInsn(MethodFlow.java:219)
    at org.objectweb.asm.MethodVisitor.visitMethodInsn(Unknown Source)
    at org.objectweb.asm.tree.MethodNode.visitMethodInsn(Unknown Source)
    at org.objectweb.asm.ClassReader.a(Unknown Source)
    at org.objectweb.asm.ClassReader.b(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at kilim.analysis.ClassFlow.analyze(ClassFlow.java:85)
    at kilim.analysis.ClassWeaver.weave(ClassWeaver.java:93)
    at kilim.tools.Weaver.weave(Weaver.java:297)
    at kilim.tools.Weaver.weave(Weaver.java:255)
    at kilim.WeavingClassLoader.findClass(WeavingClassLoader.java:61)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
    at java.lang.Class.getDeclaredMethods(Class.java:1962)
    at kilim.mirrors.RuntimeClassMirror.getDeclaredMethods(RuntimeClassMirrors.java:163)
    at kilim.mirrors.Detector.findPausableMethod(Detector.java:119)
    at kilim.mirrors.Detector.getPausableStatus(Detector.java:71)
    at kilim.analysis.MethodFlow.visitMethodInsn(MethodFlow.java:219)
    at org.objectweb.asm.MethodVisitor.visitMethodInsn(Unknown Source)
    at org.objectweb.asm.tree.MethodNode.visitMethodInsn(Unknown Source)
    at org.objectweb.asm.ClassReader.a(Unknown Source)
    at org.objectweb.asm.ClassReader.b(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at kilim.analysis.ClassFlow.analyze(ClassFlow.java:85)
    at kilim.analysis.ClassWeaver.weave(ClassWeaver.java:93)
    at kilim.tools.Weaver.weave(Weaver.java:297)
    at kilim.tools.Weaver.weave(Weaver.java:255)
    at kilim.WeavingClassLoader.findClass(WeavingClassLoader.java:61)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at kilim.tools.Kilim.main(Kilim.java:24)

Enhance exception thrown when pausable methods are called from within a synchronized block

Hi - I'm working on an Eclipse plugin for Kilim, http://kilimbuilder.googlecode.com.

In order to mark methods in Eclipse that have Kilim problems I parse Kilim exceptions and extract information about the methods that contains the problem. The exception thrown when when pausable methods are called from within a synchronized block do not contain enough information, they just have the method name, no class info. So I have enhance the exception so that it contains a complete method descriptor.

In the kilim.analysis.BasicBlock.interpret method I have changed the INVOKEINTERFACE case so that it looks like this (just the line that throws the exception has changed)....

                case INVOKEINTERFACE:
                    // pop args, push return value
                    MethodInsnNode min = ((MethodInsnNode) ain);
                    String desc = min.desc;
                    if (flow.isPausableMethodInsn(min) && frame.numMonitorsActive > 0) {
                        throw new KilimException("Error: Can not call pausable nethods from within a synchronized block\n" +
                                "Caller: " + this.flow.classFlow.name.replace('/', '.') + "." + this.flow.name + this.flow.desc +
                                "\nCallee: " + ((MethodInsnNode)ain).name); 
                    }
                    canThrowException = true;
                    frame.popn(TypeDesc.getNumArgumentTypes(desc));
                    if (opcode != INVOKESTATIC) {
                        v = frame.pop(); // "this" ref
                        //assert checkReceiverType(v, min) : "Method " + flow.name + " calls " + min.name + " on a receiver with incompatible type " + v.getTypeDesc() ;
                    }
                    desc = TypeDesc.getReturnTypeDesc(desc);
                    if (desc != D_VOID) {
                        frame.push(Value.make(i, desc));
                    }
                    break;

CachedClassMirrors.classForName should defer to loaded class objects first, then to cached class mirrors.

While weaving, Kilim was giving me an erroneous error that a method in a base class was not pausable.
I discovered that the Detector.getPausableStatus method erroneous reported that the method in question was not pausable.
I also discoverd that the Detector.getPausableStatus method determines if an exception type is Pausable by comparing it to an instance of ClassMirror, like so...


    ClassMirror c = classForName(ex);
    if (PAUSABLE.isAssignableFrom(c)) {
        return PAUSABLE_METHOD_FOUND;
    }

The source of the problem was that PAUSABLE.isAssignableFrom(c) returned false for the exception type declared by the method in question.
That is, Kilim used the isAssignableFrom method to determine if the method throws an exception of type Pausable, and the PAUSABLE.isAssignableFrom(c) returned false when passed a ClassMirror instance that represented Pausable.

I eventually determined that the reason for this was that the instance of Pausable used in the Detector.getPausableStatus method, 'PAUSABLE ', was an instance of a RuntimeClassMirror, and the instance passed to it was an instance of CachedClassMirror.
I also eventually determined that this was so because the CachedClassMirrors.classForName method returned cached classed before returning runtime classes. Here is the old version of the CachedClassMirrors.classForName method, notice that the code doesnt do what the comment in it says it should do....


public ClassMirror classForName(String className)
        throws ClassMirrorNotFoundException {
    // defer to loaded class objects first, then to cached class mirrors.
    ClassMirror ret = cachedClasses.get(className); 

    if (ret == null) {
        ret = delegate.classForName(className);
    }
    if (ret == null) {
        throw new ClassMirrorNotFoundException(className);
    }
    return ret;
}

I changed the above code to this and my problems were solved...


public ClassMirror classForName(String className)
        throws ClassMirrorNotFoundException {
    // defer to loaded class objects first, then to cached class mirrors.
    ClassMirror ret = delegate.classForName(className);

    if (ret == null) {
        ret = cachedClasses.get(className); 
    }
    if (ret == null) {
        throw new ClassMirrorNotFoundException(className);
    }
    return ret;
}

Annotation on method is removed by Kilim Weaver

i have annotations on class name and method also , after kilim weaver only annotation on class is keeped , but annotation on method is gone .

`
@RpcService(value = "javasvr_ckv_cdb", modid = 670209, cmdid = 232072, routeIp = "")
public interface CkvCdbChain {

@RpcCmd(value = "Add", retry = 2, timeout = 400)
EduCkvChainMsg.AddRsp  addEntry(EduCkvChainMsg.AddReq addReq)throws Pausable,APIException;

@RpcCmd(value = "Del", retry = 2, timeout = 400)
EduCkvChainMsg.DelRsp  delEntry(EduCkvChainMsg.DelReq delReqReq)throws Pausable,APIException;

@RpcCmd(value = "GetOne", retry = 2, timeout = 400)
EduCkvChainMsg.GetOneRsp  getOne(EduCkvChainMsg.GetOneReq getOneReq)throws Pausable,APIException;

@RpcCmd(value = "Mod", retry = 2, timeout = 400)
EduCkvChainMsg.ModRsp  modEnry(EduCkvChainMsg.ModReq modReq)throws Pausable,APIException;

@RpcCmd(value = "GetList", retry = 2, timeout = 400)
EduCkvChainMsg.GetListRsp  getList(EduCkvChainMsg.GetListReq getListReq)throws Pausable,APIException;

@RpcCmd(value = "MultiGetList", retry = 2, timeout = 400)
EduCkvChainMsg.MultiGetListRsp multiGetList(EduCkvChainMsg.MultiGetListReq multiGetListReq) throws Pausable, APIException;

@RpcCmd(value = "GetReverseList", retry = 2, timeout = 400)
EduCkvChainMsg.GetReverseListRsp getReverseList(EduCkvChainMsg.GetReverseListReq getReverseListReq) throws Pausable,APIException;

}
`

need help here , tks advance . :)

Wrong pc: 2

package kilim.test.ex;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import kilim.Pausable;
import kilim.Task;

public class ExCatch extends ExYieldBase {
public ExCatch(int test) {
testCase = test;
}

/*
public void execute() throws pausable {
    if (testCase == 3) {
        doPause = false;
        tryCatchFinally();
    }
}
*/

public void execute() throws Pausable {
    doPause = false;

// test();
//
Method targetMethod = null;

    Class<?> clazz = this.getClass();

    while(targetMethod == null && (clazz != null)) {
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method : methods) {
            if(method.getName().equals("test")) {
                //TODO method override
                targetMethod = method;
                break;
            }
        }
        clazz = clazz.getSuperclass();
    }
    if(targetMethod == null) {
        throw new IllegalArgumentException("xxxxxxxx");
    }

    try {
        Task.invoke(targetMethod, this);
    } catch (Exception e) {
        e.printStackTrace();
    }
    //
    doPause = true;
    test();
    //

// try {
// Task.invoke(targetMethod, this);
// } catch (Exception e) {
// e.printStackTrace();
// }
}

public void test() throws Pausable {
    switch(testCase) {
        case 0: normalCatch(); break; 
        default: throw new IllegalStateException("Unknown test case: " + testCase);
    }
}

void normalCatch() throws Pausable {
    double d = fd;
    String[][] sa = fa;
    String s = fs;
    try {
        pausable(d);
    } catch (ExException eye) {
        eye.printStackTrace();
        String es = eye.getMessage();
        verify(es);
        s = es;
    }
    verify(d);
    verify(sa);
    verify(s);
}

private void pausable(double d) throws ExException, Pausable {
    if (doPause) {
        Task.sleep(50);
    }
    verify(d);
    if(d == 10.0) {
        throw new ExException("10");
    }
}

}

this test will fail.....

java.lang.VerifyError: Mismatched stack types

The following test case will reproduce a problem that I think is a weaving issue.
I am using Java 1.6 update 25 and the latest version of kilim in the repository trunk.
I would attempt to fix this myself but I am having problems finding out what 'Mismatched stack types' even means :-)...

package com.googlecode.contraildb.tests;

import junit.framework.TestCase;
import kilim.Pausable;

public class ReproduceVerifyError extends TestCase {
    static class BadClass {

        public void doSomething() throws Pausable ,Exception {
            new String(getBytes());
        }
        public byte[] getBytes() throws Pausable {
            return "lkj;lkjad;fa".getBytes();
        }
    }

    public void testVerifyError() {
        /*
         * This line will throw the following error at runtime...
         * java.lang.VerifyError: (class: com/googlecode/contraildb/tests/BadClass, method: doSomething signature: (Lkilim/Fiber;)V) Mismatched stack types
         *   at com.googlecode.contraildb.tests.ReproduceVerifyError.testVerifyError(ReproduceVerifyError.java:8)
         */
        new BadClass();
    }
}

The VerifyError will go away if the doSomething method is written this way...

        public void doSomething() throws Pausable ,Exception {
            byte[] bytes= getBytes();
            new String(bytes);
        }

If it helps, here is a textual view of the instrumented class for BadClass...

// Compiled from ReproduceVerifyError.java (version 1.6 : 50.0, super bit)
static class com.googlecode.contraildb.tests.ReproduceVerifyError$BadClass {

  // Field descriptor #10 Z
  // Signature: Z
  public static final boolean $isWoven = true;

  // Method descriptor #13 ()V
  // Stack: 1, Locals: 1
  ReproduceVerifyError$BadClass();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [15]
    4  return
      Line numbers:
        [pc: 0, line: 7]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.googlecode.contraildb.tests.ReproduceVerifyError.BadClass

  // Method descriptor #19 (Lkilim/Fiber;)V
  // Stack: 4, Locals: 4
  public void doSomething(kilim.Fiber arg0) throws kilim.Pausable, java.lang.Exception;
      0  aload_1 [arg0]
      1  getfield kilim.Fiber.pc : int [29]
      4  tableswitch default: 28
          case 0: 36
          case 1: 31
     28  invokestatic kilim.Fiber.wrongPC() : void [32]
     31  aconst_null
     32  aload_0 [this]
     33  goto 40
     36  new java.lang.String [34]
     39  aload_0 [this]
     40  aload_1 [arg0]
     41  invokevirtual kilim.Fiber.down() : kilim.Fiber [38]
     44  invokevirtual com.googlecode.contraildb.tests.ReproduceVerifyError$BadClass.getBytes(kilim.Fiber) : byte[] [42]
     47  aload_1 [arg0]
     48  invokevirtual kilim.Fiber.up() : int [46]
     51  tableswitch default: 132
          case 0: 132
          case 1: 114
          case 2: 80
          case 3: 111
     80  pop
     81  new kilim.S_O [48]
     84  dup
     85  invokespecial kilim.S_O() [49]
     88  astore_2
     89  aload_2
     90  aload_0 [this]
     91  putfield kilim.State.self : java.lang.Object [55]
     94  aload_2
     95  iconst_1
     96  putfield kilim.State.pc : int [56]
     99  astore_3
    100  aload_2
    101  aload_3
    102  putfield kilim.S_O.f0 : java.lang.Object [59]
    105  aload_1 [arg0]
    106  aload_2
    107  invokevirtual kilim.Fiber.setState(kilim.State) : void [63]
    110  return
    111  pop
    112  pop
    113  return
    114  astore_2
    115  pop
    116  aload_1 [arg0]
    117  getfield kilim.Fiber.curState : kilim.State [67]
    120  checkcast kilim.S_O [48]
    123  astore_3
    124  aload_3
    125  getfield kilim.S_O.f0 : java.lang.Object [59]
    128  checkcast java.lang.String [34]
    131  aload_2
    132  invokespecial java.lang.String(byte[]) [70]
    135  return
      Line numbers:
        [pc: 36, line: 10]
        [pc: 135, line: 11]
      Local variable table:
        [pc: 36, pc: 136] local: this index: 0 type: com.googlecode.contraildb.tests.ReproduceVerifyError.BadClass

  // Method descriptor #13 ()V
  // Stack: 0, Locals: 2
  public void doSomething() throws kilim.Pausable, java.lang.Exception;
    0  invokestatic kilim.Task.errNotWoven() : void [75]
    3  return


  // Method descriptor #40 (Lkilim/Fiber;)[B
  // Stack: 2, Locals: 2
  public byte[] getBytes(kilim.Fiber arg0) throws kilim.Pausable;
    0  aload_1 [arg0]
    1  ldc <String "lkj;lkjad;fa"> [77]
    3  invokevirtual java.lang.String.getBytes() : byte[] [80]
    6  areturn
      Line numbers:
        [pc: 1, line: 13]
      Local variable table:
        [pc: 1, pc: 7] local: this index: 0 type: com.googlecode.contraildb.tests.ReproduceVerifyError.BadClass

  // Method descriptor #78 ()[B
  // Stack: 1, Locals: 2
  public byte[] getBytes() throws kilim.Pausable;
    0  invokestatic kilim.Task.errNotWoven() : void [75]
    3  aconst_null
    4  areturn

  Inner classes:
    [inner class info: #2 com/googlecode/contraildb/tests/ReproduceVerifyError$BadClass, outer class info: #7 com/googlecode/contraildb/tests/ReproduceVerifyError
     inner name: #8 BadClass, accessflags: 8 static]
}

Gradle plugin

How do we add kilim to a build.gradle script to run AOT weaving? Thanks!

classes with a single pausable method incorrectly identified as SAMs

classes with a single pausable method are incorrectly identified as functional interfaces

see examples/Userdata.java in https://github.com/nqzero/kilim/tree/srl.icce

specifically nqzero@a352bc2

/*
this class fails with:
java.lang.IncompatibleClassChangeError: Found class kilim.examples.Userdata$Eats1, but interface was expected
at kilim.examples.Userdata.$shim$1(Userdata.java)
at kilim.examples.Userdata.execute(Userdata.java:27)
at kilim.Task._runExecute(Task.java:435)
at kilim.WorkerThread.run(WorkerThread.java:32)
*/

Missing test classes?

Firstly, many thanks for the great work! However, I believe that I have identified a bug in some of the tests.

The test class kilim.test.TestInvalidPausables refers to the following classes:

  • kilim.test.ex.ExInvalidConstructor
  • kilim.test.ex.ExInvalidStaticBlock
  • kilim.test.ex.ExInvalidCallP_NP
  • kilim.test.ex.ExInvalidPDerived
  • kilim.test.ex.ExInvalidPImp

However, none of the classes in the above list are in the package kilim.test.ex, or any other package for that matter. (I have greped the entire project for the class names.)

The tests that involve these missing classes are in fact passing, but only because the test requires an exception to be thrown, and an exception is indeed thrown, but only due to the class missing, instead of the weaving failing.

Could you confirm that this is a bug? Do you have the source of the missing classes?

IDE Debugger/Java Agent Support

Are there any plans to add support for IDEs who build classes independently from maven/gradle for debugging? Speaking of Visual Studio Code in particular, the run/debug and hot code replace are all useless because there's no way to weave the classes without java agent support.

Problem with version 2.0.1

Environment:

JDK:

java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

OS: MacOS 10.13.1

Code:

public class Server extends Task {

    private Mailbox<Long> mailbox;

    public Server(Mailbox<Long> mailbox) {
        this.mailbox = mailbox;
    }

    @Override
    public void execute() throws Pausable, Exception {
        //super.execute();
        try {
            while (true) {
                mailbox.putnb(System.currentTimeMillis() / 1000L);

                Task.sleep(2000L);
                if (mailbox.hasMessage()) {
                    System.out.println("receive data from client:'" + mailbox.getnb() + "'");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Client extends Task {
    private Mailbox<Long> mailbox;

    public Client(Mailbox<Long> mailbox) {
        this.mailbox = mailbox;
    }

    @Override
    public void execute() throws Pausable, Exception {

        try {
            while (true) {
                if (mailbox.hasMessage()) {
                    System.out.println("receive data from server:'" + mailbox.getnb() + "'");
                }

                Task.sleep(1000);
                mailbox.putnb(System.currentTimeMillis() / 1000L);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {

        Mailbox<Long> mailbox = new Mailbox<>();
        Client client = new Client(mailbox);
        Server server = new Server(mailbox);

        client.start();
        server.start();
    }
}

Kilim version
2.0.1

When running main in Main, it outputs nothings buts it works well with kilim 2.0.0-25
see below
2.0.1
image

2.0.0-25
image

Http Server code has issues with buffer size and POST (not chunked) - FIX PROVIDED

Hi,

Ok so I have a basic HTTP server to test this issue, here is the execute method.

public void execute() throws Pausable, Exception {
HttpRequest req = new HttpRequest();
HttpResponse resp = new HttpResponse();

    while (true) {
        // Fill up the request object. This pauses until the entire request has
        // been read in, including all chunks.
        readRequest(req);

        PrintStream p = new PrintStream(resp.getOutputStream());

        if (req.method.equals("GET")) {
            resp.setContentType("text/html");
            p.println("<html><head></head><body>");
            p.println("<form method='post'>");
            p.println("<textarea name='content' rows='10' cols='50'>");
            p.println("</textarea>");
            p.println("<input type='submit' />");
            p.println("</form>");
            p.println("</body></html>");

        } else if (req.method.equals("POST")) {
            resp.setContentType("text/plain");
            String content = req.extractRange(req.contentOffset, req.contentOffset+req.contentLength);
            p.println("["+content+"]");
        } 

        sendResponse(resp);

  if (!req.keepAlive()) {
            break;
        }
    }

    close();
}

Submit the following XML content in the Text area

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dec="http://someplace.com/SomeService" xmlns:ns="http://someplace.com">
soapenv:Header/
soapenv:Body
dec:SomeService
ns:Message


Pell
Pell
M
1990-10-01

        <HomeAddress>
            <AddressLine1></AddressLine1>
            <City></City>
            <State></State>
            <Postcode></Postcode>
            <MonthsAtAddress></MonthsAtAddress>
        </HomeAddress>
    </PrimaryApplicant>
</Application>

     </ns:Message>
  </dec:SomeService>

/soapenv:Body
/soapenv:Envelope


The first time everything is fine. Hit the back button and click Submit again and in the console I
get the following exception:

 [java] java.io.IOException: Malformed HTTP Header. p = 0, cs = 0
 [java]     at kilim.http.HttpRequestParser.initHeader(HttpRequestParser.java:413)
 [java]     at kilim.http.HttpRequest.readHeader(HttpRequest.java:199)
 [java]     at kilim.http.HttpRequest.readFrom(HttpRequest.java:186)
 [java]     at kilim.http.HttpSession.readRequest(HttpSession.java:31)
 [java]     at com.someplace.http.KilimHttpServer.execute(KilimHttpServer.java:24)
 [java]     at kilim.Task._runExecute(Task.java:432)
 [java]     at kilim.WorkerThread.run(WorkerThread.java:32)

Now I spent a few hours on this trying to understand what is happening. First of all the
EndPoint method fill(ByteBuffer buf, int atleastN) is not allocating enough space and is also
not executing a valid while loop.

Secondly even when this is changed so that the capacity is set to buf.position() + atleastN,
there is a off by one error in the calculation of the atLeastN from the HttpRequest method fill method.

These patches resolve the problem to the best of my understanding.

Index: src/kilim/nio/EndPoint.java

--- src/kilim/nio/EndPoint.java (revision 583)
+++ src/kilim/nio/EndPoint.java (working copy)
@@ -101,7 +101,7 @@
*/
public ByteBuffer fill(ByteBuffer buf, int atleastN) throws
IOException, Pausable {
if (buf.remaining() < atleastN) {

  •        ByteBuffer newbb =
    
    ByteBuffer.allocate(Math.max(buf.capacity() * 3 / 2, atleastN));
  •        ByteBuffer newbb = ByteBuffer.allocate(Math.max(buf.capacity() \* 3 / 2, buf.position() + atleastN));
         buf.rewind();
         newbb.put(buf);
         buf = newbb;
    
    @@ -132,7 +132,7 @@
    }
    }
    atleastN -= n;
  •    } while (buf.position() < atleastN);
    
  •    } while (atleastN > 0);
     return buf;
    
    }

Index: src/kilim/http/HttpRequest.java

--- src/kilim/http/HttpRequest.java (revision 583)
+++ src/kilim/http/HttpRequest.java (working copy)
@@ -319,7 +319,7 @@

 // topup if request's buffer doesn't have all the bytes yet.
 public void fill(EndPoint endpoint, int offset, int size) throws

IOException, Pausable {

  •    int total = offset + size;
    
  •    int total = offset + size + 1;
     int currentPos = buffer.position();
     if (total > buffer.position()) {
         buffer = endpoint.fill(buffer, (total - currentPos)); 
    

run() in WorkerThread catches OOM, prints stack trace, calls System.err, calls System.exit(1)

I have several issues with WorkerThread.run() which make the code unsuitable for 3rd-party library use (I really appreciate kilim otherwise!) --

  1. Catches OutOfMemoryException - please let my application worry about the sad state of affairs
  2. Prints to STDERR (or STDOUT) - please do not bury console output in the innards of a library, especially not a library built for reuse
  3. Calls System.exit(1) - this turns an exception into a fatality. It is true that OOM is fairly fatal to begin with, but libraries should be about mechanism, not policy
  4. Calls Throwable.printStackTrace() - similar complaint to previous items, console output and policy instead of mechanism

WorkerThread.run():

public void run() {
    try {
        while (true) {
            Task t = getNextTask(this); // blocks until task available
            runningTask = t;
            t._runExecute(this);
            runningTask = null;
        }
    } catch (ShutdownException se) {
        // nothing to do.
    } catch (OutOfMemoryError ex) {
        System.err.println("Out of memory");
        System.exit(1);
    } catch (Throwable ex) {
        ex.printStackTrace();
        System.err.println(runningTask);
    }
    runningTask = null;
}

Serializable lambdas that are woven fail on deserialization

Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization

javac generates a synthetic method to perform the deserialization, but that method first checks the target signature and detects that we've added the fiber arg and fails. using the cfr decompiler (and munging the name), that's equivalent to:

    private static /* synthetic */ Object $deserializeLambda$(SerializedLambda lambda) {
        switch (lambda.getImplMethodName()) {
            case "lambda$static$adfb2a4f$1": {
                if (lambda.getImplMethodKind() != 6 || !lambda.getFunctionalInterfaceClass().equals("SerTask") || !lambda.getFunctionalInterfaceMethodName().equals("task") || !lambda.getFunctionalInterfaceMethodSignature().equals("()V") || !lambda.getImplClass().equals("SerTask") || !lambda.getImplMethodSignature().equals("()V")) break;
                return fiber -> {
                    // woven lambda contents omitted for the issue report
                };
            }
        }
        throw new IllegalArgumentException("Invalid lambda deserialization");
    }

kilim is especially useful for large distributed systems so this is an important use case, ie at present Pausable lambdas cannot be executed on a remote machine

some options:

  • weave lambdas that include a fiber argument (something similar was done in the jdk10 variant to work around a but in java 10 classloading). downsides: harder to detect unwoven code, no longer possible to manually weave and exposes the fiber arg to the user
  • use ASM to modify the signature check
  • bypass java serialization and create a class by other means on deserialization (not sure that this is doable but conceptually seems possible since that's how the class is generated in the first place). the only component that's needed here is the creation - populating fields would be left to the user, eg using kryo

any thoughts ?

"ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0" in kilim.Mailbox

the issue

$ java -Dkilim.Scheduler.numThreads=1 -Ddebug=true ChanPerfKilim 0 10
[main] size 0, items 10
java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
	at kilim.Mailbox.put(Mailbox.java:134)
	at kilim.Mailbox.put(Mailbox.java:372)
	at ChanPerfKilim$Writer.execute(ChanPerfKilim.java:56)
	at kilim.Task.run(Task.java:550)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
	at kilim.Mailbox.get(Mailbox.java:80)
	at kilim.Mailbox.get(Mailbox.java:169)
	at ChanPerfKilim$Reader.execute(ChanPerfKilim.java:74)
	at kilim.Task.run(Task.java:550)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
33ms

the test case

import kilim.*;
import kilim.tools.*;

public class ChanPerfKilim {

  static final boolean debug = Boolean.getBoolean("debug");

  public static void main(String[] args) throws Exception {
    if (Kilim.trampoline(new Object() {},false,args)) return;
    
    final int size, items;
    
    if (args.length > 0) size = Integer.decode(args[0]);
    else size = 0;
    if (args.length > 1) items = Integer.decode(args[1]);
    else items = 10000000;
    log("size %d, items %d", size, items);
    
    final Mailbox<Integer> chan;
    if (size < 1) chan = new Mailbox<>(0, 1);
    else chan = new Mailbox<>(size, size);

    Mailbox<ExitMsg<?>> exitmb1 = new Mailbox<>();
    Mailbox<ExitMsg<?>> exitmb2 = new Mailbox<>();
    
    Task writer = new Writer(chan, items);
    writer.informOnExit(exitmb1);

    Task reader = new Reader(chan, items);
    writer.informOnExit(exitmb2);

    long ts = System.currentTimeMillis();
    writer.start();
    reader.start();

    exitmb1.getb();
    exitmb2.getb();
    long te = System.currentTimeMillis();
    
    System.out.println((te - ts) + "ms");
  }

  static class Writer extends Task {
    Mailbox<Integer> mymb;
    final int n;

    public Writer(Mailbox<Integer> mymb, int n) {
      this.mymb = mymb;
      this.n = n;
    }

    public void execute() throws Pausable {
      int i = n;
      do {
        int j = --i;
        mymb.put(j);
        log("put(): %d", j);
      } while (0 < i);
    }
  }

  static class Reader extends Task {
    Mailbox<Integer> mymb;
    final int n;

    public Reader(Mailbox<Integer> mymb, int n) {
      this.mymb = mymb;
      this.n = n;
    }

    public void execute() throws Pausable {
      int i = n;
      do {
        int j = mymb.get();
        log("get(): %d", j);
        --i;
      } while (0 < i);
    }
  }

  static void log(String format, Object ...args) {
    if (debug) {
      String threadName = Thread.currentThread().getName();
      String s = String.format(format, args);
      System.out.println(String.format("[%s] %s", threadName, s));
    }
  }

}

Fix to make Detector.findPausableMethod work with generic types

I have a generic base class and a subclass that both implement a pausable method, like so...


public abstract class Base<T> {
    public abstract T run() throws Pausable;
}

public class Sub extends Base<Void> {
    public void run() throws Pausable {
        // do stuff....
    }
}

The problem is that currently Kilim will report an error that says "Base class method is not pausable, but derived class is".

I tracked the source of the problem to the Detector.findPausableMethod method.
This method attempts to find a pausable method using class name, method name, and a method descriptor.
The problem is that in this case the method decriptors return types are different for the base class and the subclass.
There is no reason to compare return types when attempting to identify methods, since Java identifies methods based only on method name and argument types.
Therefore I changed the code to only use the beginning of the method descriptor (with the argument types) when comparing descriptors.

Here is the fixed version of Detector.findPausableMethod...


    private MethodMirror findPausableMethod(String className, String methodName, String desc)
            throws ClassMirrorNotFoundException {
        
        if (isNonPausableClass(className) || isNonPausableMethod(methodName)) 
            return null;

        ClassMirror cl = classForName(className);
        if (cl == null) return null;
        
        for (MethodMirror om : cl.getDeclaredMethods()) {
            if (om.getName().equals(methodName)) {
                String omDesc= om.getMethodDescriptor();
                
                // when comparing descriptors only compare arguments, not return types
                if (omDesc.substring(0,omDesc.indexOf(")")).equals(desc.substring(0,desc.indexOf(")")))) {
                    if (om.isBridge())
                        continue;
                    return om;
                }
            }
        }

        if (OBJECT.equals(cl))
            return null;

        MethodMirror m = findPausableMethod(cl.getSuperclass(), methodName, desc);
        if (m != null)
            return m;
        
        for (String ifname : cl.getInterfaces()) {
            if (isNonPausableClass(ifname)) continue;
            m = findPausableMethod(ifname, methodName, desc);
            if (m != null)
                return m;
        }
        return null;
    }

java.lang.reflect.InvocationTargetException JDK 11, 8 works fine

Version: classpath group: 'org.db4j', name: 'kilim', version: '2.0.2'
No errors if I use JDK 8. Only happening with 11. Any ideas? Thanks in advance!

`java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at kilim.tools.Kilim.trampoline(Kilim.java:113)
at kilim.tools.Kilim.trampoline(Kilim.java:79)
at io.ruin.GameServer.main(GameServer.java:77)
Caused by: java.lang.reflect.InvocationTargetException
Caused by: java.lang.reflect.InvocationTargetException

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at kilim.WeavingClassLoader.run(WeavingClassLoader.java:122)
at kilim.tools.Kilim.trampoline(Kilim.java:110)
... 2 more

Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException

at com.ea.agentloader.AgentLoader$1.loadAgent(AgentLoader.java:244)
at com.ea.agentloader.AgentLoader.loadAgent(AgentLoader.java:77)
at com.ea.agentloader.AgentLoader.loadAgentClass(AgentLoader.java:148)
at com.ea.agentloader.AgentLoader.loadAgentClass(AgentLoader.java:102)
at io.ruin.GameServer.main(GameServer.java:80)
... 8 more

Caused by: java.lang.reflect.InvocationTargetException
Caused by: java.lang.reflect.InvocationTargetException

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.ea.agentloader.AgentLoader$1.loadAgent(AgentLoader.java:240)
... 12 more

Caused by: java.lang.RuntimeException: java.io.IOException: Can not attach to current VM
Caused by: java.lang.RuntimeException: java.io.IOException: Can not attach to current VM

at com.ea.agentloader.AgentLoaderHotSpot.getVirtualMachine(AgentLoaderHotSpot.java:90)
at com.ea.agentloader.AgentLoaderHotSpot.loadAgent(AgentLoaderHotSpot.java:56)
... 17 more

Caused by: java.io.IOException: Can not attach to current VM
at jdk.attach/sun.tools.attach.HotSpotVirtualMachine.(HotSpotVirtualMachine.java:75)
Caused by: java.io.IOException: Can not attach to current VM

at jdk.attach/sun.tools.attach.VirtualMachineImpl.<init>(VirtualMachineImpl.java:48)
at jdk.attach/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:69)
at jdk.attach/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:207)
at com.ea.agentloader.AgentLoaderHotSpot.getVirtualMachine(AgentLoaderHotSpot.java:86)
... 18 more

java.io.FileNotFoundException: null\errors.txt (The system cannot find the path specified)
at java.base/java.io.FileOutputStream.open0(Native Method)
at java.base/java.io.FileOutputStream.open(FileOutputStream.java:298)
at java.base/java.io.FileOutputStream.(FileOutputStream.java:237)
at java.base/java.io.FileOutputStream.(FileOutputStream.java:158)
at java.base/java.io.FileWriter.(FileWriter.java:82)
at io.ruin.api.utils.SimpleLogger.log(SimpleLogger.java:38)
at io.ruin.api.utils.ServerWrapper.logError(ServerWrapper.java:26)
at io.ruin.api.process.ProcessFactory.lambda$static$0(ProcessFactory.java:10)
at java.base/java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1055)
at java.base/java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1050)
at java.base/java.lang.Thread.dispatchUncaughtException(Thread.java:2001)
`

Pause specific task? (Especially from within another Task)

Is it possible to pause a specific Task, especially from within another Task?

Example:

    Task counterTask = new Task() {
        @Override
        public void execute() throws Pausable {
            for(int i = 1; i <= 100; i++) {
                Task.sleep(1000L);
                System.out.println(i);
            }
        }
    }.start();

    Task pauseTask = new Task() {
        @Override
        public void execute() throws Pausable {
            Task.sleep(5000L);
            System.out.println("Pausing counter task...");
            //counterTask.pause(); //<-- this is what I'd like to do.
            Task.sleep(5000L);
            System.out.println("Resuming counter task...");
            counterTask.resume();
        }
    }.start();

please provide maven downloads

Please upload kilim to a maven repo somewhere. This makes your library far easier to use!

The minimal artificat is kilim-0.7.2.jar:
(cd classes; jar cvf ../kilim-0.7.2.jar *; jar i ../kilim-0.7.2)

Other nice ones to have include:
kilim-0.7.2-sources.jar
kilim-0.7.2-javadoc.jar
kilim-0.7.2-test-sources.jar
kilim-0.7.2-test-javadoc.jar
kilim-0.7.2-tests.jar

A pom.xml is also helpful:


4.0.0

<groupId>kilim</groupId>
<artifactId>kilim</artifactId>
<version>0.7.2</version>

<properties>
    <jdk.version>1.6</jdk.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>asm</groupId>
        <artifactId>asm-all</artifactId>
        <version>2.2.3</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>

            <configuration>
                <source>${jdk.version}</source>
                <target>${jdk.version}</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>

            <executions>
                <execution>
                    <id>kilim-weave</id>
                    <phase>process-classes</phase>

                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>

            <configuration>
                <mainClass>kilim.tools.Weaver</mainClass>

                <arguments>
                    <argument>-d</argument>
                    <argument>${project.build.outputDirectory}</argument>
                    <argument>${project.build.outputDirectory}</argument>
                </arguments>
            </configuration>
        </plugin>
    </plugins>
</build>

(That last bit with the exec plugin will automatically weave your compiled code with kilim when building with maven.)

Lastly, here is how I made the javadoc:

mkdir d; javadoc -keywords -linksource -link http://java.sun.com/javase/6/docs/api -author -version -use -d d -source 1.6 -private -sourcepath test -classpath libs/asm-all-2.2.3.jar;libs/junit.jar;kilim-0.7.2.jar -subpackages kilim; (cd d; jar cvf ../kilim-0.7.2-test-javadoc.jar *; jar i ../kilim-0.7.2-test-javadoc.jar)

Similarly for src directory.

local variables not restored after yield inside loop

local variables aren't restored properly if the last instruction in a loop calls a Pausable method. eg:

public static String dummy() throws Pausable {
    Task.yield();
    return "xxxxxxx";
}
public static class FoodTask extends Task {
    public String [] foods = new String[10];
    public void execute() throws Pausable {
        for (int ii = 0; ii < foods.length; ii++) foods[ii] = dummy();
    }
}
public static void main(String[] args) throws Exception {
    FoodTask ft = new FoodTask();
    Mailbox<ExitMsg> exitmb = new Mailbox<ExitMsg>();
    ft.start();
    ft.informOnExit(exitmb);
    exitmb.getb();
    for (String food : ft.foods) System.out.format( "food: %s\n", food );
    System.exit(0);
}

after the task completes, only foods[0] is non-null. variable ii is not being restored before assigning the result of the dummy() call. a workaround is to assign result of the pausable method to a temp variable, and then assign that to the array

kilim.S_L.class not generated

Here is a test case that contains a Pausable method.
When fed into the kilim weaver, kilim should not only weave the Pausable method but it should also generate a class file named kilim.S_L (which is used to manage the methods state info, in this case a long). However, the weaver fails to generate kilim.S_L.

import junit.framework.TestCase;
import kilim.Pausable;
import kilim.Task;

public class KilimTests extends TestCase {

  public void testSleep() throws Throwable {
    runTest(new Task() {
      public void execute() throws Pausable, Exception {
        long start= System.currentTimeMillis();
        Task.sleep(1000); 
        long time= System.currentTimeMillis() - start;
        assertTrue("Task.sleep didnt sleep long enough, only slept for "+time+" milliseconds", start+1000 <= System.currentTimeMillis());
      }
    });
  }

}

putb(T msg, final long timeoutMillis)

Hi,
I read the MailBox.java and have a question. Why the method putb(T msg, final long timeoutMillis) not reput the msg when the mailbox is not full. But the method put(T msg, int timeoutMillis) reput the msg in a loop.
Thanks.

    /**
     * put a non-null message in the mailbox, and block the calling thread  for timeoutMillis
     * if the mailbox is full. 
     */
    public void putb(T msg, final long timeoutMillis) {
        BlockingSubscriber evs = new BlockingSubscriber();
        if (!put(msg, evs)) {
            evs.blockingWait(timeoutMillis);
        }
        if (!evs.eventRcvd) {
            removeSpaceAvailableListener(evs);
        }
    }
/**
     * put a non-null message in the mailbox, and pause the calling task  for timeoutMillis
     * if the mailbox is full. 
     */

    public boolean put(T msg, int timeoutMillis) throws Pausable {
        final Task t = Task.getCurrentTask();
        long begin = System.currentTimeMillis();
        while (!put(msg, t)) {
            TimerTask tt = new TimerTask() {
                public void run() {
                    Mailbox.this.removeSpaceAvailableListener(t);
                    t.onEvent(Mailbox.this, timedOut);
                }
            };
            Task.timer.schedule(tt, timeoutMillis);
            Task.pause(this);
            removeSpaceAvailableListener(t);
            if (System.currentTimeMillis() - begin >= timeoutMillis) {
                return false;
            }
        }
        return true;
    }

HttpFileServer "Duplicate headers received from server" in chrome on refresh

running

java -cp ./classes:$CLASSPATH kilim.examples.HttpFileServer .

and viewing a url (html or pdf) in chrome, eg

http://localhost:7262/docs/kilim_ecoop08.pdf

if i refresh the page using ctrl-f5 or pressing enter on the url line after the page has loaded correctly (ie, every other refresh)

Duplicate headers received from server

The response from the server contained duplicate headers. This problem is generally the result of a misconfigured website or proxy. Only the website or proxy administrator can fix this issue.
Error code: ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH

in firefox, refresh works fine but the initial load of any page (eg, that same pdf) gives

Corrupted Content Error
The page you are trying to view cannot be shown because an error in the data transmission was detected.
The page you are trying to view cannot be shown because an error in the data transmission was detected.Please contact the website owners to inform them of this problem.

the following exceptions are printed on the command line, but none of them seem to be root causes

IO Exception:Connection reset by peer
Connection Terminated
IO Exception:Broken pipe

i haven't figured out how to show the headers in chrome when the error occurs as the developer tools show the headers for the error page instead of the page that failed

Please support ASM 4.0

Can you please support ASM 4 in the library in order to support JDK 7?

I know that others, such as Kresten, have forked kilim in order to support ASM 4, but the trouble is that fixes to the main repo are not being merged into these forks and it is all becoming difficult and a bit complicated.

Many thanks :-)

http upload server

Hi!

Can you please advice what is the best approach to wrote with your library http upload server::receiving post body into file.
The naive implementation is to write the raw data into file in a blocking fashion, but than it could block the whole native thread and influence on all the light weight threads in that thread...

Thanks in advance :D

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.