Split time functions into rs_time.rsh header.

Change-Id: I598b0031d15749c91d11fbd37b075d0564a94dbf
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index a50321e..fc3a065 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -66,6 +66,7 @@
 
         unitTests.add(new UT_primitives(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
+        unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
new file mode 100644
index 0000000..f302e1a
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_rstime extends UnitTest {
+    private Resources mRes;
+
+    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "rsTime", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime);
+        pRS.setMessageHandler(mRsMessage);
+        s.invoke_test_rstime(0, 0);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstime.rs b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
new file mode 100644
index 0000000..5e3e078
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
@@ -0,0 +1,52 @@
+#include "shared.rsh"
+
+static bool basic_test(uint32_t index) {
+    bool failed = false;
+
+    rs_time_t curTime = rsTime(0);
+    rs_tm tm;
+    rsDebug("curTime", curTime);
+
+    rsLocaltime(&tm, &curTime);
+
+    rsDebug("tm.tm_sec", tm.tm_sec);
+    rsDebug("tm.tm_min", tm.tm_min);
+    rsDebug("tm.tm_hour", tm.tm_hour);
+    rsDebug("tm.tm_mday", tm.tm_mday);
+    rsDebug("tm.tm_mon", tm.tm_mon);
+    rsDebug("tm.tm_year", tm.tm_year);
+    rsDebug("tm.tm_wday", tm.tm_wday);
+    rsDebug("tm.tm_yday", tm.tm_yday);
+    rsDebug("tm.tm_isdst", tm.tm_isdst);
+
+    // Test a specific time (only valid for PST localtime)
+    curTime = 1294438893;
+    rsLocaltime(&tm, &curTime);
+
+    _RS_ASSERT(tm.tm_sec == 33);
+    _RS_ASSERT(tm.tm_min == 21);
+    _RS_ASSERT(tm.tm_hour == 14);
+    _RS_ASSERT(tm.tm_mday == 7);
+    _RS_ASSERT(tm.tm_mon == 0);
+    _RS_ASSERT(tm.tm_year == 111);
+    _RS_ASSERT(tm.tm_wday == 5);
+    _RS_ASSERT(tm.tm_yday == 6);
+    _RS_ASSERT(tm.tm_isdst == 0);
+
+    return failed;
+}
+
+void test_rstime(uint32_t index, int test_num) {
+    bool failed = false;
+    failed |= basic_test(index);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+        rsDebug("rstime_test FAILED", -1);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+        rsDebug("rstime_test PASSED", 0);
+    }
+}
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 6a065b2..c5ee7ee 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -44,6 +44,7 @@
 uint32_t Context::gThreadTLSKeyCount = 0;
 uint32_t Context::gGLContextCount = 0;
 pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
     if (returnVal != EGL_TRUE) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 3c402c4..df275bc 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -75,6 +75,8 @@
     static uint32_t gThreadTLSKeyCount;
     static uint32_t gGLContextCount;
     static pthread_mutex_t gInitMutex;
+    // Library mutex (for providing thread-safe calls from the runtime)
+    static pthread_mutex_t gLibMutex;
 
     struct ScriptTLSStruct {
         Context * mContext;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index f61b983..0b21669 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -100,70 +100,24 @@
 // Time routines
 //////////////////////////////////////////////////////////////////////////////
 
-static int32_t SC_second() {
+static time_t SC_time(time_t *timer) {
     GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_sec;
+    return time(timer);
 }
 
-static int32_t SC_minute() {
+static tm* SC_localtime(tm *local, time_t *timer) {
     GET_TLS();
+    if (!local) {
+      return NULL;
+    }
 
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_min;
-}
-
-static int32_t SC_hour() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_hour;
-}
-
-static int32_t SC_day() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_mday;
-}
-
-static int32_t SC_month() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_mon;
-}
-
-static int32_t SC_year() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_year;
+    // The native localtime function is not thread-safe, so we
+    // have to apply locking for proper behavior in RenderScript.
+    pthread_mutex_lock(&rsc->gLibMutex);
+    tm *tmp = localtime(timer);
+    memcpy(local, tmp, sizeof(*tmp));
+    pthread_mutex_unlock(&rsc->gLibMutex);
+    return local;
 }
 
 static int64_t SC_uptimeMillis() {
@@ -498,12 +452,8 @@
     { "_Z6rsFracf", (void *)&SC_frac, true },
 
     // time
-    { "_Z8rsSecondv", (void *)&SC_second, true },
-    { "_Z8rsMinutev", (void *)&SC_minute, true },
-    { "_Z6rsHourv", (void *)&SC_hour, true },
-    { "_Z5rsDayv", (void *)&SC_day, true },
-    { "_Z7rsMonthv", (void *)&SC_month, true },
-    { "_Z6rsYearv", (void *)&SC_year, true },
+    { "_Z6rsTimePi", (void *)&SC_time, true },
+    { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true },
     { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
     { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
     { "_Z7rsGetDtv", (void*)&SC_getDt, false },
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index d059997..a74c0e0 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -118,32 +118,6 @@
 extern float __attribute__((overloadable))
     rsFrac(float);
 
-// time
-extern int32_t __attribute__((overloadable))
-    rsSecond(void);
-extern int32_t __attribute__((overloadable))
-    rsMinute(void);
-extern int32_t __attribute__((overloadable))
-    rsHour(void);
-extern int32_t __attribute__((overloadable))
-    rsDay(void);
-extern int32_t __attribute__((overloadable))
-    rsMonth(void);
-extern int32_t __attribute__((overloadable))
-    rsYear(void);
-
-// Return the current system clock in milliseconds
-extern int64_t __attribute__((overloadable))
-    rsUptimeMillis(void);
-
-// Return the current system clock in nanoseconds
-extern int64_t __attribute__((overloadable))
-    rsUptimeNanos(void);
-
-// Return the time in seconds since function was last called in this script.
-extern float __attribute__((overloadable))
-    rsGetDt(void);
-
 // Send a message back to the client.  Will not block and returns true
 // if the message was sendable and false if the fifo was full.
 // A message ID is required.  Data payload is optional.
diff --git a/libs/rs/scriptc/rs_time.rsh b/libs/rs/scriptc/rs_time.rsh
new file mode 100644
index 0000000..f1abed63
--- /dev/null
+++ b/libs/rs/scriptc/rs_time.rsh
@@ -0,0 +1,36 @@
+#ifndef __RS_TIME_RSH__
+#define __RS_TIME_RSH__
+
+typedef int rs_time_t;
+
+typedef struct {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+} rs_tm;
+
+extern rs_time_t __attribute__((overloadable))
+    rsTime(rs_time_t *timer);
+
+extern rs_tm * __attribute__((overloadable))
+    rsLocaltime(rs_tm *local, const rs_time_t *timer);
+
+// Return the current system clock in milliseconds
+extern int64_t __attribute__((overloadable))
+    rsUptimeMillis(void);
+
+// Return the current system clock in nanoseconds
+extern int64_t __attribute__((overloadable))
+    rsUptimeNanos(void);
+
+// Return the time in seconds since function was last called in this script.
+extern float __attribute__((overloadable))
+    rsGetDt(void);
+
+#endif