Programmatically change post visibility on save_post action return a 500

There is some information about this problem in the Action Reference for save post:

If you are calling a function such as wp_update_post that includes the save_post hook, your hooked function will create an infinite loop. To avoid this, unhook your function before calling the function you need, then re-hook it afterward.

So something like this should work:

[...]
add_action( 'save_post', array( $this, 'save_meta_box' ), 13, 2 );
[...]
public function save_meta_box( $post_id, $post ) {
    if ( isset( $_POST['options'] ) ) {
        myplugin_set_options( $post_id, $_POST['options'] );

        remove_action( 'save_post',  array( $this, 'save_meta_box' ), 13, 2 );

        // switch post visibility
        switch ( $_POST['options']['type'] ) {
            case 'normal':
                wp_update_post( array( 'ID' => $post_id, 'post_status' => 'private' ));
                break;
            case 'extended':
                wp_update_post( array( 'ID' => $post_id, 'post_status' => 'publish' ));
                break;
        }

        add_action( 'save_post', array( $this, 'save_meta_box' ), 13, 2 );
    }
}