Categories
discuss

Implementing an acquire for a release from Unsafe.putOrdered*()?

What do you think is the best correct way for implementing the acquire part of a release/acquire pair in Java?

I’m trying to model some of the actions in an application of mine using classic release/acquire semantics (without StoreLoad and without sequential consistency across threads).

There are a couple of ways to achieve the rough equivalent of a store-release in the JDK. java.util.concurrent.Atomic*.lazySet() and the underlying sun.misc.Unsafe.putOrdered*() are the most often cited approaches to do that. However there’s no obvious way to implement a load-acquire.

  • The JDK APIs which allow lazySet() mostly use volatile variables internally, so their store-releases are paired with volatile loads. In theory volatile loads should be more expensive than load-acquires, and should not provide anything more than a pure load-acquire in the context of a preceding store-release.

  • sun.misc.Unsafe does not provide getAcquire()* equivalents of the putOrdered*() methods, even though such acquire methods are planned for the upcoming VarHandles API.

  • Something that sounds like it would work is a plain load, followed by sun.misc.Unsafe.loadFence(). It’s somewhat disconcerting that I haven’t seen this anywhere else. This may be related to the fact that it’s a pretty ugly hack.

P.S. I understand well that these mechanisms are not covered by the JMM, that they are not sufficient for maintaining sequential consistency, and that the actions they create are not synchronization actions (e.g. I understand that they for example break IRIW). I also understand that the store-releases provided by Atomic*/Unsafe are most often used either for eagerly nulling out references or in producer/consumer scenarios, as an optimized message passing mechanism for some important index.

Answer

Volatile read is exactly what you are looking for.

In fact, corresponding volatile operations already have release/acquire semantics (otherwise happens-before is not possible for paired volatile write-read), but paired volatile operations should not only be sequentially consistent (~happens-before), but also they should be in total synchronization order, thats why StoreLoad barrier is inserted after volatile write: to guarantee total order of volatile writes to different locations, so all threads will see those values in the same order.

Volatile read has acquire semantics: proof from hotspot codebase, also there is direct recommendation by Doug Lea in JSR-133 cookbook (LoadLoad and LoadStore barriers after each volatile read).

Unsafe.loadFence() also has acquire semantics (proof), but used not to read value (you can do the same with plain volatile read), but to prevent reorder plain reads with subsequent volatile read. This is used in StampedLock for optimistic reading (see StampedLock#validate method implementation and usages).

Update after discussion in comments.

Let’s check if Unsafe#loadStore() and volatile read are the same and have acquire semantics.

I’m looking at hotspot C1 compiler source code to avoid reading through all the optimizations in C2. It transforms bytecode (in fact, not bytecode, but its interpreter representation) into LIR (Low-Level Intermediate Representation) and then translates graph to actual opcodes depends on target microarchitecture.

Unsafe#loadFence is intrinsic which has _loadFence alias. In C1 LIR generator it generates this:

case vmIntrinsics::_loadFence :
if (os::is_MP()) __ membar_acquire();

where __ is macros for LIR generation.

Now let’s look at volatile read implementation in the same LIR generator. It tries to insert null checks, checks IRIW, checks if we are on x32 and trying to read 64-bit value (to make some magic with SSE/FPU) and, finally, leads us to the same code:

if (is_volatile && os::is_MP()) {
    __ membar_acquire();
}

Assembler generator then inserts platform-specific acquire instruction(s) here.

Looking at specific implementations (no links here, but all can be found in src/cpu/{$cpu_model}/vm/c1_LIRAssembler_{$cpu_model}.cpp)

  • SPARC

    void LIR_Assembler::membar_acquire() {
        // no-op on TSO
    }
    
  • x86

    void LIR_Assembler::membar_acquire() {
        // No x86 machines currently require load fences
    }
    
  • Aarch64 (weak memory model, barriers should be present)

    void LIR_Assembler::membar_acquire() {
        __ membar(Assembler::LoadLoad|Assembler::LoadStore);
    }
    

    According to aarch architecture description such membar will be compiled as dmb ishld instruction after load.

  • PowerPC (also weak memory model)

    void LIR_Assembler::membar_acquire() {
        __ acquire();
    }
    

    which then transforms into specific PowerPC instruction lwsync. According to the comments lwsync is semantically equivalent to

    lwsync orders Store|Store, Load|Store, Load|Load, but not Store|Load

    But as long as PowerPC hasn’t any weaker barriers, this is the only choice to implement acquire semantics on PowerPC.

Conclusions

Volatile reads and Unsafe#loadFence() are equal in terms of memory ordering (but maybe not in terms of possible compiler optimizations), on most popular x86 it’s no-op, and PowerPC is the only supported architecture with has no precise acquire barriers.

Categories
discuss

BottomSheetDialog with transparent background

I would like to display a bottom sheet dialog less wide than the screen width.

For instance, the Share option from Google Play Music on a Nexus 9.

the Share option from Google Play Music on a Nexus 9

Do you know how to achieve this ?

For now I just succed to reduce the width of the sheet content but the background is still at the screen width and display a white background.

Some code:

build.gradle

compile 'com.android.support:design:23.3.0'

MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    mBottomSheetDialog = new BottomSheetDialog(this);
    mBottomSheetDialog.setContentView(R.layout.sheet_test);
    mBottomSheetDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialog) {
            mBottomSheetDialog = null;
        }
    });
    mBottomSheetDialog.show();
}

sheet_test

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            style="@style/TextAppearance.AppCompat.Body1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:text="Some Text"
            android:textColor="@color/colorPrimary" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ddd" />

        <TextView
            style="@style/TextAppearance.AppCompat.Body1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="16dp"
            android:text="Some Text" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ddd" />

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

Answer

So, I figured out 2 solutions.

Best one:

Create an activity with transparent background just for your bottom sheet. Implement your own layout with a coordinator layout and a bottom sheet. Set the margin you want. Set the content you want.

Not tested yet.

Lazy one:

Extends BottomSheetDialogFragment, in onActivityCreated add:

    Resources resources = getResources();

    // Set margin for Landscape Mode. Maybe a more elegant solution will be to implements our own bottom sheet with our own margins.
    if (resources.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        assert getView() != null;
        View parent = (View) getView().getParent();
        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) parent.getLayoutParams();
        layoutParams.setMargins(
                resources.getDimensionPixelSize(R.dimen.bottom_sheet_margin_left), // 64dp
                0,
                resources.getDimensionPixelSize(R.dimen.bottom_sheet_margin_right), // 64dp
                0
        );
        parent.setLayoutParams(layoutParams);
    }
Categories
discuss

Double for loop in JavaScript

var
startx = 0,
starty = 0,
endx = 12,
endy = 100;

for(startx;startx <= endx; startx+=1){
        for(starty; starty <= endy; starty+=1){
            console.log(startx, endx, starty, endy);
     }
}

Expected output:

0, 12, 0, 100
0, 12, 1, 100
0, 12, 2, 100
...
0, 12, 100, 100
1, 12, 0, 100
1, 12, 1, 100
...
12, 12, 100, 100
;EOO

Output on Chrome 39+

0, 12, 0, 100
0, 12, 1, 100
0, 12, 2, 100
...
0, 12, 100, 100

So the problem is the first for loop does not iterate over startx variable.

Could you tell me why it does not iterate?

Answer

That was a fun puzzle. It took me a few times before i caught it.

The reason is that starty is not reset after the first iteration and therefore the second for loop will only run once since the condition will always go false.

You want:

var startx = 0,
    starty = 0,
    endx = 12,
    endy = 100;

for (; startx <= endx; startx++) {
    for (starty = 0; starty <= endy; starty++) {
        console.log(startx, endx, starty, endy);
    }
}

I also simplified startx+=1 to startx++, same goes for starty.

I will also suggest to get into the habit of writing each var statement on it’s own:

var a;
var b;

This makes it easier to stop on when debugging. Try stepping into def() without stepping into abc().

var a = abc(),
    b = def();

How is a for loop broken down:

The for loop is broken down into 3 parts:

for(initial; condition; after)

initial is called before the loop, can safely be omitted.
condition is called just before running the code in the loop, will always be true if omitted
after is called after the code in the loop same as writing:

for(var i = 0; i < 10;) {
  // code
  i++;
}
Categories
discuss

External HTML asset not bundled by React Native in production build for use by Webview

I’m building an Android application using React Native. It has a webview that reads an HTML file locally.

This is the piece of code I’m using to render webview.

<WebView ref="webview"
      source={require('./helloworld.html')}
      javaScriptEnabled style={styles.webView} />

This works well during development build. The HTML file loads on the webview and renders well.

But it doesn’t on Android release/production build. The webview is empty and if I inspect using chrome://inspect, the webview is empty and doesn’t load the HTML file.

From what I understand is the React Native fails to bundle helloworld.html as an asset during Android production build. I noticed that it works fine on iOS.

Any idea how to fix it?

Answer

As per the discussions around here https://github.com/facebook/react-native/issues/6004, it’s a known defect. Assets are not bundled for Android production build but works fine in dev build.

A solution is store assets in Android assets folder manually, and then load the resource using

<WebView
    source={{ uri: 'file:///android_asset/helloworld.html' }}
    startInLoadingState={true} />
Categories
discuss

How to show the ‘has-error’ class on an invalid field in Angular 2

Given:

<div class="form-group" [fieldValidity]="email">
  <label for="email" class="sr-only">Email</label>
  <input [(ngModel)]="model.email" ngControl="email" required>
</div>

And my custom [fieldValidity] directive:

import { Directive, ElementRef, Input } from 'angular2/core';
import {NgControlName} from 'angular2/common';
@Directive({
  selector: '[fieldValidity]'
})
export class FieldValidityDirective {
  private el: HTMLElement;
  @Input('fieldValidity') field: NgControlName;
  constructor(el: ElementRef) { 
    this.el = el.nativeElement;
  }
  private _onValidityChange(value: string) {
    //TODO test field.valid || field.pristine
    if (?) { 
      this.el.classList.remove('has-error');
    } else {
      this.el.classList.add('has-error');
    }
  }
}

How can I get subscribe to the field.valid && field .pristine values to show the error? (I’ve marked it with ‘TODO’ below)

Answer

You could also implement the ngDoCheck method to check the validity:

ngDoCheck(value: string) {
  if (field.valid || field.pristine) { 
    this.el.classList.remove('has-error');
  } else {
    this.el.classList.add('has-error');
  }
}

That said you could implement a wrapping component that leverages ngClass directly on the element. Something like that:

@Component({
  selector: 'field',
  template: `
    <div class="form-group form-group-sm" [ngClass]="{'has-error':state && !state.valid}">
      <label for="for" class="col-sm-3 control-label">{{label}}</label>
      <div class="col-sm-8">
        <!-- Input, textarea or select -->
        <ng-content></ng-content>
        <span *ngIf="state && !state.valid" class="help-block text-danger">
          <span *ngIf="state.errors.required">The field is required</span>
        </span>
    </div>
  </div>
`
})
export class FormFieldComponent {
  @Input()
  label: string;

  @Input()
  state: Control;
}

You can even go further by directly referencing the control from the ng-content using the @ContentChild decorator:

@Component({
  (...)
})
export class FormFieldComponent {
  @Input()
  label: string;

  @ContentChild(NgFormControl) state;

  (...)
}

This way you would be able to define your input this way with ngFormControl (would also work with ngControl):

<form [ngFormModel]="companyForm">
  <field label="Name">
    <input [ngFormControl]="companyForm.controls.name" 
           [(ngModel)]="company.name"/>
  </field>
</form>

See this article for more details (section “Form component for fields”):

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..