* Not all pthreads features are supported on Android, thus the changes.
* Changing the `data_store` signature is enough to support nulls because the APIs of both underlying implementations already supported them.
* Declaring the lines for <activity> in the modules allows for non-fullscreen and non-orientation-locked apps!
Pull-Request: #927
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>
new_annotation max_api_version
new_annotation target_api_version
new_annotation android_manifest
+ new_annotation android_manifest_application
+ new_annotation android_manifest_activity
end
import java
fun [](key: String): nullable Object is abstract
# Store `value` at `key`
- fun []=(key: String, value: Serializable) is abstract
+ fun []=(key: String, value: nullable Serializable) is abstract
end
# limitations under the License.
# Impements the services of `mnit:app` using the API from the Android ndk
-module android_app
+module android_app is
+ android_manifest_activity """
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden"
+ android:screenOrientation="portrait""""
+end
import mnit
import android
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Offers some POSIX threads services that are not available on all platforms
+module extra is
+ c_compiler_option("-pthread")
+ c_linker_option("-pthread")
+end
+
+intrude import pthreads
+
+in "C" `{
+ // TODO protect with: #ifdef WITH_LIBGC
+ #ifndef ANDROID
+ #define GC_THREADS
+ #include <gc.h>
+ #endif
+`}
+
+redef extern class NativePthread
+ fun cancel: Bool `{
+ return pthread_cancel(*recv);
+ `}
+end
+
+redef class Thread
+ # Cancel the execution of the thread
+ fun cancel
+ do
+ if native == null then return
+ native.cancel
+ native = null
+ end
+end
+
+# Does not return if the running thread is to be cancelled
+fun test_cancel `{ pthread_testcancel(); `}
+
+private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
+ new(count: Int) `{
+ pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
+ int res = pthread_barrier_init(barrier, NULL, count);
+ return barrier;
+ `}
+
+ fun destroy `{ pthread_barrier_destroy(recv); `}
+
+ fun wait `{ pthread_barrier_wait(recv); `}
+end
// TODO protect with: #ifdef WITH_LIBGC
// We might have to add the next line to gc_chooser.c too, especially
// if we get an error like "thread not registered with GC".
+ #ifndef ANDROID
#define GC_THREADS
#include <gc.h>
- //#endif
+ #endif
`}
redef class Sys
return (nullable_Object)thread_return;
`}
- fun cancel: Bool `{
- return pthread_cancel(*recv);
- `}
-
fun attr: NativePthreadAttr `{
pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
pthread_getattr_np(*recv, pattr);
# pthread_mutexattr_setrobust_np
end
-private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
- new(count: Int) `{
- pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
- int res = pthread_barrier_init(barrier, NULL, count);
- return barrier;
- `}
-
- fun destroy `{ pthread_barrier_destroy(recv); `}
-
- fun wait `{ pthread_barrier_wait(recv); `}
-end
-
private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
new `{
pthread_key_t *key = malloc(sizeof(pthread_key_t));
`}
end
+private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
+ new `{
+ pthread_cond_t cond;
+ int r = pthread_cond_init(&cond, NULL);
+ if (r == 0) {
+ pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
+ memmove(pcond, &cond, sizeof(pthread_cond_t));
+ return pcond;
+ }
+ return NULL;
+ `}
+
+ fun destroy `{ pthread_cond_destroy(recv); `}
+
+ fun signal `{ pthread_cond_signal(recv); `}
+
+ fun broadcast `{ pthread_cond_broadcast(recv); `}
+
+ fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(recv, mutex); `}
+end
+
#
## Nity part
#
return r
end
- # Cancel the execution of the thread
- fun cancel
- do
- if native == null then return
- native.cancel
- native = null
- end
-
redef fun finalize
do
if native == null then return
# Exit current thread and return `value` to caller of `Thread::join`
fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
-# Does not return if the running thread is to be cancelled
-fun test_cancel `{ pthread_testcancel(); `}
-
# Returns the handle to the running `Thread`
fun thread: Thread
do
class Barrier
super Finalizable
+ private var mutex = new Mutex
+ private var cond: nullable NativePthreadCond = new NativePthreadCond
+
# Number of threads that must be waiting for `wait` to unblock
var count: Int
- private var native: nullable NativePthreadBarrier is noinit
-
- init do native = new NativePthreadBarrier(count)
+ private var threads_waiting = 0
# Wait at this barrier and block until there are a `count` threads waiting
- fun wait do native.wait
+ fun wait
+ do
+ mutex.lock
+ threads_waiting += 1
+ if threads_waiting == count then
+ threads_waiting = 0
+ cond.broadcast
+ else
+ cond.wait(mutex.native.as(not null))
+ end
+ mutex.unlock
+ end
redef fun finalize
do
- var native = self.native
- if native != null then
- native.destroy
- native.free
+ var cond = self.cond
+ if cond != null then
+ cond.destroy
+ cond.free
end
- self.native = null
+ self.cond = null
end
end
# Custom lines to add to the AndroidManifest.xml in the <application> node
var manifest_application_lines = new Array[String]
+ # Custom lines to add to AndroidManifest.xml as attributes inside the <activity> node
+ var manifest_activity_attributes = new Array[String]
+
# Minimum API level required for the application to run
var min_api: nullable Int = null
annots = collect_annotations_on_modules("android_manifest_application", mmodule)
for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
+ annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
+ for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+
# Get the date and time (down to the minute) as string
var local_time = new Tm.localtime
var local_time_s = local_time.strftime("%y%m%d%H%M")
# Also copy over the java files
dir = "{android_project_root}/src/"
- var extra_java_files = compiler.mainmodule.extra_java_files
- if extra_java_files != null then for file in extra_java_files do
- var path = file.filename
- path.file_copy_to("{dir}/{path.basename("")}")
+ for mmodule in compiler.mainmodule.in_importation.greaters do
+ var extra_java_files = mmodule.extra_java_files
+ if extra_java_files != null then for file in extra_java_files do
+ var path = file.filename
+ path.file_copy_to(dir/path.basename(""))
+ end
end
## Generate delagating makefile
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:configChanges="orientation|keyboardHidden"
- android:screenOrientation="portrait"
+ {{{project.manifest_activity_attributes.join("\n")}}}
{{{icon_declaration}}}>
- <!-- Tell NativeActivity the name of or .so -->
- <meta-data android:name=\"{{{app_package}}}\"
- android:value=\"{{{app_name}}}\" />
+ <!-- Tell NativeActivity the name of our .so -->
+ <meta-data android:name=\"android.app.lib_name\"
+ android:value=\"main\" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />