hotspot/src/share/vm/runtime/thread.cpp
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
{- -------------------------------------------
(1) (extern 宣言)
---------------------------------------- -}
extern void JDK_Version_init();
{- -------------------------------------------
(1) JNI のバージョンがサポート範囲かどうか確認.
---------------------------------------- -}
// Check version
if (!is_supported_jni_version(args->version)) return JNI_EVERSION;
{- -------------------------------------------
(1) ostream_init() により, output stream module を gc log のために初期化する.
---------------------------------------- -}
// Initialize the output stream module
ostream_init();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Process java launcher properties.
Arguments::process_sun_java_launcher_properties(args);
{- -------------------------------------------
(1) os::init() により, OS モジュール (乱数生成機, 現在のPID, 高精度タイマー, etc) を初期化する
---------------------------------------- -}
// Initialize the os module before using TLS
os::init();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Initialize system properties.
Arguments::init_system_properties();
{- -------------------------------------------
(1) JDK_Version_init() により, JDK_Version クラスを初期化する (See: JDK_Version).
---------------------------------------- -}
// So that JDK version can be used as a discrimintor when parsing arguments
JDK_Version_init();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Update/Initialize System properties after JDK version number is known
Arguments::init_version_specific_system_properties();
{- -------------------------------------------
(1) Arguments::parse() により, コマンドライン引数などを処理する.
---------------------------------------- -}
// Parse arguments
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
{- -------------------------------------------
(1) PauseAtStartup オプションが指定されていれば, pause file が削除されるまで待つ
---------------------------------------- -}
if (PauseAtStartup) {
os::pause();
}
{- -------------------------------------------
(1) (DTrace のフック点)
---------------------------------------- -}
HS_DTRACE_PROBE(hotspot, vm__init__begin);
{- -------------------------------------------
(1) (トレース出力用の処理)
TraceVmCreationTime のインスタンスを作成し, Threads::create_vm() にかかった時間の計測を開始する
(See: TraceVmCreationTime)
---------------------------------------- -}
// Record VM creation timing statistics
TraceVmCreationTime create_vm_timer;
create_vm_timer.start();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
// Timing (must come after argument parsing)
TraceTime timer("Create VM", TraceStartupTime);
{- -------------------------------------------
(1) os::init_2() により, コマンドライン引数に基づいて OS モジュールをさらに生成&初期化する.
(e.g. synchronization, stack, memory, safepoint pages, etc).
(また, その他のライブラリ(libzip, libjava, etc) をロードしたり,
シグナルハンドラを初期化したりもする)
---------------------------------------- -}
// Initialize the os module after parsing the args
jint os_init_2_result = os::init_2();
if (os_init_2_result != JNI_OK) return os_init_2_result;
{- -------------------------------------------
(1) ostream_init_log() で, output stream logger を初期化する.
必要な agent libraries (hprof, jdi) も初期化してスタートさせる
---------------------------------------- -}
// Initialize output stream logging
ostream_init_log();
{- -------------------------------------------
(1) -Xrun オプションを agentlib, agentpath 形式に変換する
---------------------------------------- -}
// Convert -Xrun to -agentlib: if there is no JVM_OnLoad
// Must be before create_vm_init_agents()
if (Arguments::init_libraries_at_startup()) {
convert_vm_init_libraries_to_agents();
}
{- -------------------------------------------
(1) Threads::create_vm_init_agents() で,
JVMTI エージェントをロードし, それぞれの Agent_OnLoad() 関数を呼び出す.
(なお, JVMTI の phase の変更も行う.
Threads::create_vm_init_agents() の中だけが JVMTI_PHASE_ONLOAD であり,
Threads::create_vm_init_agents() の終了後には JVMTI_PHASE_PRIMORDIAL になる.
(See: Threads::create_vm_init_agents()))
---------------------------------------- -}
// Launch -agentlib/-agentpath and converted -Xrun agents
if (Arguments::init_agents_at_startup()) {
create_vm_init_agents();
}
{- -------------------------------------------
(1) ThreadLocalStorage::init() で, スレッドの状態や TLS などを初期化する.
---------------------------------------- -}
// Initialize Threads state
_thread_list = NULL;
_number_of_threads = 0;
_number_of_non_daemon_threads = 0;
// Initialize TLS
ThreadLocalStorage::init();
{- -------------------------------------------
(1) vm_init_globals() で, 大域データを初期化する
---------------------------------------- -}
// Initialize global data structures and create system classes in heap
vm_init_globals();
{- -------------------------------------------
(1) この段階でスレッドが作れるようになる.
メインスレッドを表す JavaThread が作られ, 現在実行中のネイティブスレッドに対応付けられる.
(ただし, このスレッドは the known list of the Threads には追加されない ?? #TODO)
ちなみに, ここが "point of no return"
(set_as_starting_thread() の途中で失敗したらやり直せない)
---------------------------------------- -}
// Attach the main thread to this os thread
JavaThread* main_thread = new JavaThread();
main_thread->set_thread_state(_thread_in_vm);
// must do this before set_active_handles and initialize_thread_local_storage
// Note: on solaris initialize_thread_local_storage() will (indirectly)
// change the stack size recorded here to one based on the java thread
// stacksize. This adjusted size is what is used to figure the placement
// of the guard pages.
main_thread->record_stack_base_and_size();
main_thread->initialize_thread_local_storage();
main_thread->set_active_handles(JNIHandleBlock::allocate_block());
if (!main_thread->set_as_starting_thread()) {
vm_shutdown_during_initialization(
"Failed necessary internal allocation. Out of swap space");
delete main_thread;
*canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
return JNI_ENOMEM;
}
{- -------------------------------------------
(1) メインスレッドの stack guard page を作成する.
(os::create_main_thread() の後で作らないと Linux でクラッシュするとのこと)
---------------------------------------- -}
// Enable guard page *after* os::create_main_thread(), otherwise it would
// crash Linux VM, see notes in os_linux.cpp.
main_thread->create_stack_guard_pages();
{- -------------------------------------------
(1) ObjectMonitor::Initialize() で, Java レベルの同期排他機構の初期化を行う.
---------------------------------------- -}
// Initialize Java-Level synchronization subsystem
ObjectMonitor::Initialize() ;
{- -------------------------------------------
(1) init_globals() で, 残りの大域モジュールを初期化する.
(e.g. BootClassLoader, CodeCache, Interpreter, Compiler, JNI, SystemDictionary, Universe, etc)
ちなみに, ここも "point of no return"
(init_globals() の途中で失敗したらやり直せない)
---------------------------------------- -}
// Initialize global modules
jint status = init_globals();
if (status != JNI_OK) {
delete main_thread;
*canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
return status;
}
{- -------------------------------------------
(1) メインスレッドを表す JavaThread 内のプラットフォーム依存なフィールドの初期化を行う
---------------------------------------- -}
// Should be done after the heap is fully created
main_thread->cache_global_variables();
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
HandleMark hm;
{- -------------------------------------------
(1) main スレッドが list (the known list of the Threads??) に追加される.
(Thread_Lock(??) を最初にロックするのはこの時らしい ?? #TODO)
---------------------------------------- -}
{ MutexLocker mu(Threads_lock);
Threads::add(main_thread);
}
{- -------------------------------------------
(1) ここまでで JavaThread が動き出した状態になったので,
JvmtiExport::transition_pending_onload_raw_monitors() を呼んで
JvmtiPendingMonitors 内に溜まっている JvmtiRawMonitor を現在のスレッドへと移し替える.
(See: JvmtiPendingMonitors)
---------------------------------------- -}
// Any JVMTI raw monitors entered in onload will transition into
// real raw monitor. VM is setup enough here for raw monitor enter.
JvmtiExport::transition_pending_onload_raw_monitors();
{- -------------------------------------------
(1) (verify)
(Verify 系のオプションが指定されていれば, Universe::verify() で Universe のチェックを行う)
---------------------------------------- -}
if (VerifyBeforeGC &&
Universe::heap()->total_collections() >= VerifyGCStartAt) {
Universe::heap()->prepare_for_verify();
Universe::verify(); // make sure we're starting with a clean slate
}
{- -------------------------------------------
(1) VMThread::create() で, VMThread を生成する.
(生成後, Notify_lock を使って同期を取り,
VMThread が ready 状態になるまで待ってから次に進む.
(See: VMThread::run()))
---------------------------------------- -}
// Create the VMThread
{ TraceTime timer("Start VMThread", TraceStartupTime);
VMThread::create();
Thread* vmthread = VMThread::vm_thread();
if (!os::create_thread(vmthread, os::vm_thread))
vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");
// Wait for the VM thread to become ready, and VMThread::run to initialize
// Monitors can have spurious returns, must always check another state flag
{
MutexLocker ml(Notify_lock);
os::start_thread(vmthread);
while (vmthread->active_handles() == NULL) {
Notify_lock->wait();
}
}
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert (Universe::is_fully_initialized(), "not initialized");
EXCEPTION_MARK;
{- -------------------------------------------
(1) DumpSharedSpaces オプションが指定されている場合には, ここでヒープをダンプして終了.
---------------------------------------- -}
// At this point, the Universe is initialized, but we have not executed
// any byte code. Now is a good time (the only time) to dump out the
// internal state of the JVM for sharing.
if (DumpSharedSpaces) {
Universe::heap()->preload_and_dump(CHECK_0);
ShouldNotReachHere();
}
{- -------------------------------------------
(1) (JVMTI の phase の変更)
(ここからが JVMTI_PHASE_START)
---------------------------------------- -}
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::enter_start_phase();
{- -------------------------------------------
(1) (JVMTI のフック点) (See: VMStart イベント)
(なお, ここで java.lang.instrument の premain() が呼び出されたりする)
---------------------------------------- -}
// Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.
JvmtiExport::post_vm_start();
{- -------------------------------------------
(1) initialize_class() を用いて, 種々の Java クラスがロードされ初期化される.
(e.g. java.lang.String, java.lang.System, java.lang.ThreadGroup, java.lang.Thread, java.lang.reflect.Method, java.lang.ref.Finalizer, java.lang.Class, and the rest of the System)
---------------------------------------- -}
{
TraceTime timer("Initialize java.lang classes", TraceStartupTime);
if (EagerXrunInit && Arguments::init_libraries_at_startup()) {
create_vm_init_libraries();
}
if (InitializeJavaLangString) {
initialize_class(vmSymbols::java_lang_String(), CHECK_0);
} else {
warning("java.lang.String not initialized");
}
{- -------------------------------------------
(1.1) AggressiveOpts オプションが指定されている場合は, ... #TODO
---------------------------------------- -}
if (AggressiveOpts) {
{
// Forcibly initialize java/util/HashMap and mutate the private
// static final "frontCacheEnabled" field before we start creating instances
#ifdef ASSERT
klassOop tmp_k = SystemDictionary::find(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet");
#endif
klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);
KlassHandle k = KlassHandle(THREAD, k_o);
guarantee(k.not_null(), "Must find java/util/HashMap");
instanceKlassHandle ik = instanceKlassHandle(THREAD, k());
ik->initialize(CHECK_0);
fieldDescriptor fd;
// Possible we might not find this field; if so, don't break
if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {
k()->java_mirror()->bool_field_put(fd.offset(), true);
}
}
if (UseStringCache) {
// Forcibly initialize java/lang/StringValue and mutate the private
// static final "stringCacheEnabled" field before we start creating instances
klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_lang_StringValue(), Handle(), Handle(), CHECK_0);
// Possible that StringValue isn't present: if so, silently don't break
if (k_o != NULL) {
KlassHandle k = KlassHandle(THREAD, k_o);
instanceKlassHandle ik = instanceKlassHandle(THREAD, k());
ik->initialize(CHECK_0);
fieldDescriptor fd;
// Possible we might not find this field: if so, silently don't break
if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {
k()->java_mirror()->bool_field_put(fd.offset(), true);
}
}
}
}
// Initialize java_lang.System (needed before creating the thread)
if (InitializeJavaLangSystem) {
initialize_class(vmSymbols::java_lang_System(), CHECK_0);
initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);
Handle thread_group = create_initial_thread_group(CHECK_0);
Universe::set_main_thread_group(thread_group());
initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);
oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);
main_thread->set_threadObj(thread_object);
// Set thread status to running since main thread has
// been started and running.
java_lang_Thread::set_thread_status(thread_object,
java_lang_Thread::RUNNABLE);
// The VM preresolve methods to these classes. Make sure that get initialized
initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0);
initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK_0);
// The VM creates & returns objects of this class. Make sure it's initialized.
initialize_class(vmSymbols::java_lang_Class(), CHECK_0);
call_initializeSystemClass(CHECK_0);
} else {
warning("java.lang.System not initialized");
}
// an instance of OutOfMemory exception has been allocated earlier
if (InitializeJavaLangExceptionsErrors) {
initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0);
initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0);
initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0);
initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0);
initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0);
initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0);
initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0);
} else {
warning("java.lang.OutOfMemoryError has not been initialized");
warning("java.lang.NullPointerException has not been initialized");
warning("java.lang.ClassCastException has not been initialized");
warning("java.lang.ArrayStoreException has not been initialized");
warning("java.lang.ArithmeticException has not been initialized");
warning("java.lang.StackOverflowError has not been initialized");
}
}
// See : bugid 4211085.
// Background : the static initializer of java.lang.Compiler tries to read
// property"java.compiler" and read & write property "java.vm.info".
// When a security manager is installed through the command line
// option "-Djava.security.manager", the above properties are not
// readable and the static initializer for java.lang.Compiler fails
// resulting in a NoClassDefFoundError. This can happen in any
// user code which calls methods in java.lang.Compiler.
// Hack : the hack is to pre-load and initialize this class, so that only
// system domains are on the stack when the properties are read.
// Currently even the AWT code has calls to methods in java.lang.Compiler.
// On the classic VM, java.lang.Compiler is loaded very early to load the JIT.
// Future Fix : the best fix is to grant everyone permissions to read "java.compiler" and
// read and write"java.vm.info" in the default policy file. See bugid 4211383
// Once that is done, we should remove this hack.
initialize_class(vmSymbols::java_lang_Compiler(), CHECK_0);
{- -------------------------------------------
(1)
---------------------------------------- -}
// More hackery - the static initializer of java.lang.Compiler adds the string "nojit" to
// the java.vm.info property if no jit gets loaded through java.lang.Compiler (the hotspot
// compiler does not get loaded through java.lang.Compiler). "java -version" with the
// hotspot vm says "nojit" all the time which is confusing. So, we reset it here.
// This should also be taken out as soon as 4211383 gets fixed.
reset_vm_info_property(CHECK_0);
{- -------------------------------------------
(1) JNIEnv (JNI Function Table) 内の Get<Primitive>Field 関数を高速版に置き換える.
(See: [here](nooEDMFr0n.html) for details)
---------------------------------------- -}
quicken_jni_functions();
{- -------------------------------------------
(1) 基本的な初期化が終わったので, set_init_completed() で _init_completed 変数を true にする
(ConcurrentGCThread 等がこの変数の値を見ており, 初期化が完了するまで処理を開始しないようにしている.
See: is_init_completed())
---------------------------------------- -}
// Set flag that basic initialization has completed. Used by exceptions and various
// debug stuff, that does not work until all basic classes have been initialized.
set_init_completed();
{- -------------------------------------------
(1) (DTrace のフック点)
---------------------------------------- -}
HS_DTRACE_PROBE(hotspot, vm__init__end);
{- -------------------------------------------
(1) VM の起動処理が終わった時間を記録する.
---------------------------------------- -}
// record VM initialization completion time
Management::record_vm_init_completed();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Compute system loader. Note that this has to occur after set_init_completed, since
// valid exceptions may be thrown in the process.
// Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and
// set_init_completed has just been called, causing exceptions not to be shortcut
// anymore. We call vm_exit_during_initialization directly instead.
SystemDictionary::compute_java_system_loader(THREAD);
if (HAS_PENDING_EXCEPTION) {
vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
}
{- -------------------------------------------
(1) GC アルゴリズムとして CMS か G1GC が指定されている場合には,
ここで SurrogateLockerThread を生成しておく.
---------------------------------------- -}
#ifndef SERIALGC
// Support for ConcurrentMarkSweep. This should be cleaned up
// and better encapsulated. The ugly nested if test would go away
// once things are properly refactored. XXX YSR
if (UseConcMarkSweepGC || UseG1GC) {
if (UseConcMarkSweepGC) {
ConcurrentMarkSweepThread::makeSurrogateLockerThread(THREAD);
} else {
ConcurrentMarkThread::makeSurrogateLockerThread(THREAD);
}
if (HAS_PENDING_EXCEPTION) {
vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
}
}
#endif // SERIALGC
{- -------------------------------------------
(1) (JVMTI の phase の変更)
(ここからが JVMTI_PHASE_LIVE)
---------------------------------------- -}
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::enter_live_phase();
{- -------------------------------------------
(1) シグナル処理を行うためのスレッド("Signal Dispatcher" スレッド)を立ち上げる.
(これは VMInit イベントを送出する前に行う必要があるとのこと)
---------------------------------------- -}
// Signal Dispatcher needs to be started before VMInit event is posted
os::signal_init();
{- -------------------------------------------
(1) 以下の2つの条件がどちらも成り立つなら,
AttachListener::init() で AttachListener を初期化する (See: AttachListener)
* AttachListener 機能が有効
(= DisableAttachMechanism オプションが指定されていない)
* AttachListener を HotSpot の起動時に初期化することになっている
(= StartAttachListener オプションが指定されている, もしくは
AttachListener::init_at_startup() が true を返す)
---------------------------------------- -}
// Start Attach Listener if +StartAttachListener or it can't be started lazily
if (!DisableAttachMechanism) {
if (StartAttachListener || AttachListener::init_at_startup()) {
AttachListener::init();
}
}
{- -------------------------------------------
(1) Threads::create_vm_init_libraries() で,
-Xrun オプションで指定された JVMTI エージェントをロードし, それぞれの JVM_OnLoad() 関数を呼び出す.
---------------------------------------- -}
// Launch -Xrun agents
// Must be done in the JVMTI live phase so that for backward compatibility the JDWP
// back-end can launch with -Xdebug -Xrunjdwp.
if (!EagerXrunInit && Arguments::init_libraries_at_startup()) {
create_vm_init_libraries();
}
{- -------------------------------------------
(1) (JVMTI のフック点) (See: VMInit イベント)
---------------------------------------- -}
// Notify JVMTI agents that VM initialization is complete - nop if no agents.
JvmtiExport::post_vm_initialized();
{- -------------------------------------------
(1) ChunkPoolCleaner オブジェクトを生成し, 実行を開始させる.
(See: ChunkPoolCleaner)
---------------------------------------- -}
Chunk::start_chunk_pool_cleaner_task();
{- -------------------------------------------
(1) CompileBroker を初期化する
(See: CompileBroker)
---------------------------------------- -}
// initialize compiler(s)
CompileBroker::compilation_init();
{- -------------------------------------------
(1) Management::initialize() を呼んで serviceability 機能関係の初期化を行う
(ServiceThread の起動, JMX Management Server の起動, etc)
(See: )
(See: [here](novYWKneN9.html) for details)
もしこの初期化処理でエラーが起きたら, vm_exit() で異常終了.
---------------------------------------- -}
Management::initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
// management agent fails to start possibly due to
// configuration problem and is responsible for printing
// stack trace if appropriate. Simply exit VM.
vm_exit(1);
}
{- -------------------------------------------
(1) コマンドラインオプションでの指定に基づき, 必要があれば簡易的なプロファイラを生成する.
(See: FlatProfiler)
(See: AllocationProfiler)
(See: MemProfiler)
(See: StatSampler)
---------------------------------------- -}
if (Arguments::has_profile()) FlatProfiler::engage(main_thread, true);
if (Arguments::has_alloc_profile()) AllocationProfiler::engage();
if (MemProfiling) MemProfiler::engage();
StatSampler::engage();
{- -------------------------------------------
(1) CheckJNICalls オプションが指定されていれば, JniPeriodicChecker オブジェクトを生成しておく.
(See: JniPeriodicChecker)
---------------------------------------- -}
if (CheckJNICalls) JniPeriodicChecker::engage();
{- -------------------------------------------
(1) biased locking 処理を有効にする
---------------------------------------- -}
BiasedLocking::init();
{- -------------------------------------------
(1) もし sun.misc.PostVMInitHook クラスがあれば, sun.misc.PostVMInitHook.run() メソッドを呼び出しておく.
(sun.misc.PostVMInitHook クラスは OpenJDK では見当たらない (Oracle JDK の rt.jar 内には存在している).
まぁクラスがなければ call_postVMInitHook() が何もせずに返ってくるだけだが...
See: sun.misc.PostVMInitHook)
---------------------------------------- -}
if (JDK_Version::current().post_vm_init_hook_enabled()) {
call_postVMInitHook(THREAD);
// The Java side of PostVMInitHook.run must deal with all
// exceptions and provide means of diagnosis.
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
}
{- -------------------------------------------
(1) もし PeriodicTask があれば, WatcherThread::start() で WatcherThread を生成する (See: WatcherThread).
---------------------------------------- -}
// Start up the WatcherThread if there are any periodic tasks
// NOTE: All PeriodicTasks should be registered by now. If they
// aren't, late joiners might appear to start slowly (we might
// take a while to process their first tick).
if (PeriodicTask::num_tasks() > 0) {
WatcherThread::start();
}
{- -------------------------------------------
(1) OS モジュールに関する最後の初期化処理を実行する.
(といっても, 現状ではこの関数はどのプラットフォーム上でも何もしないようだが...)
---------------------------------------- -}
// Give os specific code one last chance to start
os::init_3();
{- -------------------------------------------
(1) TraceVmCreationTime::end() を呼び出して Threads::create_vm() にかかった時間の計測を終了する.
---------------------------------------- -}
create_vm_timer.end();
{- -------------------------------------------
(1) リターン.
---------------------------------------- -}
return JNI_OK;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.