Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 109116bb authored by Stephen Hines's avatar Stephen Hines
Browse files

Fix bugs with unsigned rsAtomicCas/Max/Min.

BUG=5888007

rsAtomicMax/Min did not have proper semantics for unsigned integers. They were
always using signed comparisons. rsAtomicCas had the wrong function signature
in our math library, leading to no way to properly link/execute it.

Change-Id: I336cdd8cd9f2d8093f12e101b55b2797515f039b
parent fb9ffe02
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -329,6 +329,16 @@ static int32_t SC_AtomicXor(volatile int32_t *ptr, int32_t value) {
    return prev;
}

static uint32_t SC_AtomicUMin(volatile uint32_t *ptr, uint32_t value) {
    uint32_t prev, status;
    do {
        prev = *ptr;
        uint32_t n = rsMin(value, prev);
        status = android_atomic_release_cas((int32_t) prev, (int32_t)n, (volatile int32_t*) ptr);
    } while (CC_UNLIKELY(status != 0));
    return prev;
}

static int32_t SC_AtomicMin(volatile int32_t *ptr, int32_t value) {
    int32_t prev, status;
    do {
@@ -339,6 +349,16 @@ static int32_t SC_AtomicMin(volatile int32_t *ptr, int32_t value) {
    return prev;
}

static uint32_t SC_AtomicUMax(volatile uint32_t *ptr, uint32_t value) {
    uint32_t prev, status;
    do {
        prev = *ptr;
        uint32_t n = rsMax(value, prev);
        status = android_atomic_release_cas((int32_t) prev, (int32_t) n, (volatile int32_t*) ptr);
    } while (CC_UNLIKELY(status != 0));
    return prev;
}

static int32_t SC_AtomicMax(volatile int32_t *ptr, int32_t value) {
    int32_t prev, status;
    do {
@@ -524,9 +544,9 @@ static RsdSymbolTable gSyms[] = {
    { "_Z11rsAtomicXorPVii", (void *)&SC_AtomicXor, true },
    { "_Z11rsAtomicXorPVjj", (void *)&SC_AtomicXor, true },
    { "_Z11rsAtomicMinPVii", (void *)&SC_AtomicMin, true },
    { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicMin, true },
    { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicUMin, true },
    { "_Z11rsAtomicMaxPVii", (void *)&SC_AtomicMax, true },
    { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicMax, true },
    { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicUMax, true },
    { "_Z11rsAtomicCasPViii", (void *)&SC_AtomicCas, true },
    { "_Z11rsAtomicCasPVjjj", (void *)&SC_AtomicCas, true },

+1 −1
Original line number Diff line number Diff line
@@ -242,7 +242,7 @@ extern int32_t __attribute__((overloadable))
 * @return old value
 */
extern uint32_t __attribute__((overloadable))
    rsAtomicCas(volatile uint32_t* addr, int32_t compareValue, int32_t newValue);
    rsAtomicCas(volatile uint32_t* addr, uint32_t compareValue, uint32_t newValue);

#endif //defined(RS_VERSION) && (RS_VERSION >= 14)

+2 −1
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008-2011 The Android Open Source Project
 * Copyright (C) 2008-2012 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.
@@ -72,6 +72,7 @@ public class RSTestCore {
        unitTests.add(new UT_alloc(this, mRes, mCtx));
        unitTests.add(new UT_refcount(this, mRes, mCtx));
        unitTests.add(new UT_foreach(this, mRes, mCtx));
        unitTests.add(new UT_atomic(this, mRes, mCtx));
        unitTests.add(new UT_math(this, mRes, mCtx));
        unitTests.add(new UT_fp_mad(this, mRes, mCtx));
        /*
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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_atomic extends UnitTest {
    private Resources mRes;

    protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) {
        super(rstc, "Atomics", ctx);
        mRes = res;
    }

    public void run() {
        RenderScript pRS = RenderScript.create(mCtx);
        ScriptC_atomic s = new ScriptC_atomic(pRS, mRes, R.raw.atomic);
        pRS.setMessageHandler(mRsMessage);
        s.invoke_atomic_test();
        pRS.finish();
        waitForMessage();
        pRS.destroy();
    }
}
+77 −0
Original line number Diff line number Diff line
#include "shared.rsh"

// Testing atomic operations
static bool testUMax(uint32_t dst, uint32_t src) {
    bool failed = false;
    uint32_t old = dst;
    uint32_t expect = (dst > src ? dst : src);
    uint32_t ret = rsAtomicMax(&dst, src);
    _RS_ASSERT(old == ret);
    _RS_ASSERT(dst == expect);
    return failed;
}

static bool testUMin(uint32_t dst, uint32_t src) {
    bool failed = false;
    uint32_t old = dst;
    uint32_t expect = (dst < src ? dst : src);
    uint32_t ret = rsAtomicMin(&dst, src);
    _RS_ASSERT(old == ret);
    _RS_ASSERT(dst == expect);
    return failed;
}

static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) {
    bool failed = false;
    uint32_t old = dst;
    uint32_t expect = (dst == cmp ? swp : dst);
    uint32_t ret = rsAtomicCas(&dst, cmp, swp);
    _RS_ASSERT(old == ret);
    _RS_ASSERT(dst == expect);
    return failed;
}

static bool test_atomics() {
    bool failed = false;

    failed |= testUMax(5, 6);
    failed |= testUMax(6, 5);
    failed |= testUMax(5, 0xf0000006);
    failed |= testUMax(0xf0000006, 5);

    failed |= testUMin(5, 6);
    failed |= testUMin(6, 5);
    failed |= testUMin(5, 0xf0000006);
    failed |= testUMin(0xf0000006, 5);

    failed |= testUCas(4, 4, 5);
    failed |= testUCas(4, 5, 5);
    failed |= testUCas(5, 5, 4);
    failed |= testUCas(5, 4, 4);
    failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005);
    failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005);
    failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004);
    failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004);

    if (failed) {
        rsDebug("test_atomics FAILED", 0);
    }
    else {
        rsDebug("test_atomics PASSED", 0);
    }

    return failed;
}

void atomic_test() {
    bool failed = false;
    failed |= test_atomics();

    if (failed) {
        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
    }
    else {
        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
    }
}