diff --git a/Rakefile b/Rakefile index 4e49aa7..0cded4a 100644 --- a/Rakefile +++ b/Rakefile @@ -42,6 +42,8 @@ def check(m) "build/tests/check_#{m}" end + + namespace "test" do desc "Run all tests" task 'run' => ["unit", "scenarios"] @@ -102,6 +104,7 @@ file check("client") => build/nbdtypes.o build/listen.o build/flexnbd.o + build/flexthread.o build/control.o build/readwrite.o build/parse.o @@ -139,6 +142,7 @@ file check("serve") => build/readwrite.o build/parse.o build/client.o + build/flexthread.o build/serve.o build/flexnbd.o build/mirror.o @@ -159,6 +163,7 @@ file check("readwrite") => build/serve.o build/parse.o build/acl.o + build/flexthread.o build/control.o build/flexnbd.o build/mirror.o @@ -176,6 +181,7 @@ file check("listen") => build/listen.o build/flexnbd.o build/status.o + build/flexthread.o build/mbox.o build/mirror.o build/self_pipe.o @@ -199,6 +205,7 @@ file check("flexnbd") => build/control.o build/listen.o build/mbox.o + build/flexthread.o build/status.o build/self_pipe.o build/client.o diff --git a/src/client.c b/src/client.c index 295fb53..f230e68 100644 --- a/src/client.c +++ b/src/client.c @@ -470,6 +470,10 @@ void client_cleanup(struct client* client, munmap(client->mapped, client->serve->size); } if (client->fileno) { close(client->fileno); } + + if ( server_io_locked( client->serve ) ) { server_unlock_io( client->serve ); } + if ( server_acl_locked( client->serve ) ) { server_unlock_acl( client->serve ); } + } void* client_serve(void* client_uncast) diff --git a/src/control.c b/src/control.c index 055f479..6607502 100644 --- a/src/control.c +++ b/src/control.c @@ -205,6 +205,7 @@ void control_serve( struct control * control ) void * control_runner( void * control_uncast ) { + debug("Control thread"); NULLCHECK( control_uncast ); struct control * control = (struct control *)control_uncast; @@ -313,7 +314,7 @@ int control_mirror(struct control_client* client, int linesc, char** lines) * one mirror at a time. This is enforced by only accepting a * single client at a time on the control socket. */ - flexnbd_switch_lock( flexnbd ); + flexnbd_lock_switch( flexnbd ); { struct server * serve = flexnbd_server(flexnbd); serve->mirror_super = mirror_super_create( @@ -333,10 +334,13 @@ int control_mirror(struct control_client* client, int linesc, char** lines) "Failed to create mirror thread" ); + debug("Control thread mirror super waiting"); enum mirror_state state = mirror_super_wait( serve->mirror_super ); + debug("Control thread writing response"); control_write_mirror_response( state, client->socket ); } - flexnbd_switch_unlock( flexnbd ); + debug( "Control thread unlocking switch" ); + flexnbd_unlock_switch( flexnbd ); debug( "Control thread going away." ); return 0; @@ -392,6 +396,12 @@ void control_cleanup(struct control_client* client, int fatal __attribute__ ((unused)) ) { if (client->socket) { close(client->socket); } + + /* This is wrongness */ + if ( server_io_locked( client->flexnbd->serve ) ) { server_unlock_io( client->flexnbd->serve ); } + if ( server_acl_locked( client->flexnbd->serve ) ) { server_unlock_acl( client->flexnbd->serve ); } + if ( flexnbd_switch_locked( client->flexnbd ) ) { flexnbd_unlock_switch( client->flexnbd ); } + control_client_destroy( client ); } diff --git a/src/flexnbd.c b/src/flexnbd.c index 10675e4..09a26f8 100644 --- a/src/flexnbd.c +++ b/src/flexnbd.c @@ -77,7 +77,7 @@ void flexnbd_create_shared( flexnbd->signal_fd = flexnbd_build_signal_fd(); - pthread_mutex_init( &flexnbd->switch_mutex, NULL ); + flexnbd->switch_mutex = flexthread_mutex_create(); } @@ -186,16 +186,22 @@ void flexnbd_destroy( struct flexnbd * flexnbd ) /* THOU SHALT NOT DEREFERENCE flexnbd->serve OUTSIDE A SWITCH LOCK */ -void flexnbd_switch_lock( struct flexnbd * flexnbd ) +void flexnbd_lock_switch( struct flexnbd * flexnbd ) { NULLCHECK( flexnbd ); - pthread_mutex_lock( &flexnbd->switch_mutex ); + flexthread_mutex_lock( flexnbd->switch_mutex ); } -void flexnbd_switch_unlock( struct flexnbd * flexnbd ) +void flexnbd_unlock_switch( struct flexnbd * flexnbd ) { NULLCHECK( flexnbd ); - pthread_mutex_unlock( &flexnbd->switch_mutex ); + flexthread_mutex_unlock( flexnbd->switch_mutex ); +} + +int flexnbd_switch_locked( struct flexnbd * flexnbd ) +{ + NULLCHECK( flexnbd ); + return flexthread_mutex_held( flexnbd->switch_mutex ); } struct server * flexnbd_server( struct flexnbd * flexnbd ) @@ -208,11 +214,11 @@ struct server * flexnbd_server( struct flexnbd * flexnbd ) void flexnbd_replace_acl( struct flexnbd * flexnbd, struct acl * acl ) { NULLCHECK( flexnbd ); - flexnbd_switch_lock( flexnbd ); + flexnbd_lock_switch( flexnbd ); { server_replace_acl( flexnbd_server(flexnbd), acl ); } - flexnbd_switch_unlock( flexnbd ); + flexnbd_unlock_switch( flexnbd ); } @@ -221,11 +227,11 @@ struct status * flexnbd_status_create( struct flexnbd * flexnbd ) NULLCHECK( flexnbd ); struct status * status; - flexnbd_switch_lock( flexnbd ); + flexnbd_lock_switch( flexnbd ); { status = status_create( flexnbd_server( flexnbd ) ); } - flexnbd_switch_unlock( flexnbd ); + flexnbd_unlock_switch( flexnbd ); return status; } @@ -245,13 +251,13 @@ void flexnbd_switch( struct flexnbd * flexnbd, struct server *(listen_cb)(struct NULLCHECK( flexnbd ); NULLCHECK( flexnbd->listen ); - flexnbd_switch_lock( flexnbd ); + flexnbd_lock_switch( flexnbd ); { struct server * new_server = listen_cb( flexnbd->listen ); NULLCHECK( new_server ); flexnbd_set_server( flexnbd, new_server ); } - flexnbd_switch_unlock( flexnbd ); + flexnbd_unlock_switch( flexnbd ); } @@ -266,11 +272,11 @@ int flexnbd_default_deny( struct flexnbd * flexnbd ) int result; NULLCHECK( flexnbd ); - flexnbd_switch_lock( flexnbd ); + flexnbd_lock_switch( flexnbd ); { result = server_default_deny( flexnbd->serve ); } - flexnbd_switch_unlock( flexnbd ); + flexnbd_unlock_switch( flexnbd ); return result; } diff --git a/src/flexnbd.h b/src/flexnbd.h index 6878523..20d442c 100644 --- a/src/flexnbd.h +++ b/src/flexnbd.h @@ -8,6 +8,7 @@ #include "self_pipe.h" #include "mbox.h" #include "control.h" +#include "flexthread.h" /* Carries the "globals". */ struct flexnbd { @@ -28,7 +29,7 @@ struct flexnbd { /* switch_mutex is the lock around dereferencing the serve * pointer. */ - pthread_mutex_t switch_mutex; + struct flexthread_mutex * switch_mutex; /* File descriptor for a signalfd(2) signal stream. */ int signal_fd; @@ -60,8 +61,9 @@ struct flexnbd * flexnbd_create_listening( void flexnbd_destroy( struct flexnbd * ); enum mirror_state; enum mirror_state flexnbd_get_mirror_state( struct flexnbd * ); -void flexnbd_switch_lock( struct flexnbd * ); -void flexnbd_switch_unlock( struct flexnbd * ); +void flexnbd_lock_switch( struct flexnbd * ); +void flexnbd_unlock_switch( struct flexnbd * ); +int flexnbd_switch_locked( struct flexnbd * ); int flexnbd_default_deny( struct flexnbd * ); void flexnbd_set_server( struct flexnbd * flexnbd, struct server * serve ); void flexnbd_switch( struct flexnbd * flexnbd, struct server *(listen_cb)(struct listen *) ); diff --git a/src/flexthread.c b/src/flexthread.c new file mode 100644 index 0000000..ef1d7df --- /dev/null +++ b/src/flexthread.c @@ -0,0 +1,75 @@ +#include "flexthread.h" +#include "util.h" + +#include + + +struct flexthread_mutex * flexthread_mutex_create(void) +{ + struct flexthread_mutex * ftm = + xmalloc( sizeof( struct flexthread_mutex ) ); + + FATAL_UNLESS( 0 == pthread_mutex_init( &ftm->mutex, NULL ), + "Mutex initialisation failed" ); + return ftm; + +} + + +void flexthread_mutex_destroy( struct flexthread_mutex * ftm ) +{ + NULLCHECK( ftm ); + + if( flexthread_mutex_held( ftm ) ) { + flexthread_mutex_unlock( ftm ); + } + else if ( (pthread_t)NULL != ftm->holder ) { + /* This "should never happen": if we can try to destroy + * a mutex currently held by another thread, there's a + * logic bug somewhere. I know the test here is racy, + * but there's not a lot we can do about it at this + * point. + */ + fatal( "Attempted to destroy a flexthread_mutex"\ + " held by another thread!" ); + } + + FATAL_UNLESS( 0 == pthread_mutex_destroy( &ftm->mutex ), + "Mutex destroy failed" ); + free( ftm ); +} + + +int flexthread_mutex_lock( struct flexthread_mutex * ftm ) +{ + NULLCHECK( ftm ); + + int failure = pthread_mutex_lock( &ftm->mutex ); + if ( 0 == failure ) { + ftm->holder = pthread_self(); + } + + return failure; +} + + +int flexthread_mutex_unlock( struct flexthread_mutex * ftm ) +{ + NULLCHECK( ftm ); + + pthread_t orig = ftm->holder; + ftm->holder = (pthread_t)NULL; + int failure = pthread_mutex_unlock( &ftm->mutex ); + if ( 0 != failure ) { + ftm->holder = orig; + } + return failure; +} + + +int flexthread_mutex_held( struct flexthread_mutex * ftm ) +{ + NULLCHECK( ftm ); + return pthread_self() == ftm->holder; +} + diff --git a/src/flexthread.h b/src/flexthread.h new file mode 100644 index 0000000..6a39097 --- /dev/null +++ b/src/flexthread.h @@ -0,0 +1,29 @@ +#ifndef FLEXTHREAD_H +#define FLEXTHREAD_H + +#include + +/* Define a mutex wrapper object. This wrapper allows us to easily + * track whether or not we currently hold the wrapped mutex. If we hold + * the mutex when we destroy it, then we first release it. + * + * These are specifically for the case where an ERROR_* handler gets + * called when we might (or might not) have a mutex held. The + * flexthread_mutex_held() function will tell you if your thread + * currently holds the given mutex. It's not safe to make any other + * comparisons. + */ + +struct flexthread_mutex { + pthread_mutex_t mutex; + pthread_t holder; +}; + +struct flexthread_mutex * flexthread_mutex_create(void); +void flexthread_mutex_destroy( struct flexthread_mutex * ); + +int flexthread_mutex_lock( struct flexthread_mutex * ); +int flexthread_mutex_unlock( struct flexthread_mutex * ); +int flexthread_mutex_held( struct flexthread_mutex * ); + +#endif diff --git a/src/listen.c b/src/listen.c index 001d34e..00fa799 100644 --- a/src/listen.c +++ b/src/listen.c @@ -65,8 +65,13 @@ struct server *listen_switch( struct listen * listen ) } -void listen_cleanup( void * unused __attribute__((unused)) ) +void listen_cleanup( struct listen * listen ) { + NULLCHECK( listen ); + + if ( flexnbd_switch_locked( listen->flexnbd ) ) { + flexnbd_unlock_switch( listen->flexnbd ); + } } int do_listen( struct listen * listen ) @@ -75,11 +80,11 @@ int do_listen( struct listen * listen ) int have_control = 0; - flexnbd_switch_lock( listen->flexnbd ); + flexnbd_lock_switch( listen->flexnbd ); { flexnbd_set_server( listen->flexnbd, listen->init_serve ); } - flexnbd_switch_unlock( listen->flexnbd ); + flexnbd_unlock_switch( listen->flexnbd ); /* WATCH FOR RACES HERE: flexnbd->serve is set, but the server * isn't running yet and the switch lock is released. diff --git a/src/mirror.c b/src/mirror.c index a30dc67..440ea7f 100644 --- a/src/mirror.c +++ b/src/mirror.c @@ -23,7 +23,6 @@ #include "readwrite.h" #include "bitset.h" #include "self_pipe.h" -#include "acl.h" #include "status.h" @@ -182,6 +181,7 @@ int mirror_pass(struct server * serve, int should_lock, uint64_t *written) */ if (should_lock) { server_lock_io( serve ); } { + debug("in lock block"); /** FIXME: do something useful with bytes/second */ /** FIXME: error handling code here won't unlock */ @@ -194,6 +194,7 @@ int mirror_pass(struct server * serve, int should_lock, uint64_t *written) /* now mark it clean */ bitset_clear_range(map, current, run); + debug("leaving lock block"); } if (should_lock) { server_unlock_io( serve ); } @@ -280,9 +281,11 @@ void mirror_on_exit( struct server * serve ) } -void mirror_cleanup( struct mirror_status * mirror, +void mirror_cleanup( struct server * serve, int fatal __attribute__((unused))) { + NULLCHECK( serve ); + struct mirror_status * mirror = serve->mirror; NULLCHECK( mirror ); info( "Cleaning up mirror thread"); @@ -290,6 +293,8 @@ void mirror_cleanup( struct mirror_status * mirror, close( mirror->client ); } mirror->client = -1; + + if( server_io_locked( serve ) ){ server_unlock_io( serve ); } } @@ -404,7 +409,7 @@ void* mirror_runner(void* serve_params_uncast) struct mirror_status * mirror = serve->mirror; NULLCHECK( mirror->dirty_map ); - error_set_handler( (cleanup_handler *) mirror_cleanup, mirror ); + error_set_handler( (cleanup_handler *) mirror_cleanup, serve ); info( "Connecting to mirror" ); diff --git a/src/self_pipe.c b/src/self_pipe.c index 3fcee37..12bc3f2 100644 --- a/src/self_pipe.c +++ b/src/self_pipe.c @@ -39,8 +39,7 @@ void self_pipe_server_error( int err, char *msg ) } /** - * Allocate a struct self_pipe, opening the pipe and allocating a - * pthread mutex. + * Allocate a struct self_pipe, opening the pipe. * * Returns NULL if the pipe couldn't be opened or if we couldn't set it * non-blocking. diff --git a/src/serve.c b/src/serve.c index cd4b0c0..0045e07 100644 --- a/src/serve.c +++ b/src/serve.c @@ -81,8 +81,8 @@ struct server * server_create ( strcpy(out->filename_incomplete, s_file); strcpy(out->filename_incomplete + strlen(s_file), ".INCOMPLETE"); - pthread_mutex_init(&out->l_io, NULL); - pthread_mutex_init(&out->l_acl, NULL); + out->l_io = flexthread_mutex_create(); + out->l_acl= flexthread_mutex_create(); out->close_signal = self_pipe_create(); out->acl_updated_signal = self_pipe_create(); @@ -100,8 +100,8 @@ void server_destroy( struct server * serve ) self_pipe_destroy( serve->close_signal ); serve->close_signal = NULL; - pthread_mutex_destroy( &serve->l_acl ); - pthread_mutex_destroy( &serve->l_io ); + flexthread_mutex_destroy( serve->l_acl ); + flexthread_mutex_destroy( serve->l_io ); if ( serve->acl ) { acl_destroy( serve->acl ); @@ -126,23 +126,39 @@ void server_dirty(struct server *serve, off64_t from, int len) #define SERVER_LOCK( s, f, msg ) \ do { NULLCHECK( s ); \ - FATAL_IF( 0 != pthread_mutex_lock( &s->f ), msg ); } while (0) + FATAL_IF( 0 != flexthread_mutex_lock( s->f ), msg ); } while (0) #define SERVER_UNLOCK( s, f, msg ) \ do { NULLCHECK( s ); \ - FATAL_IF( 0 != pthread_mutex_unlock( &s->f ), msg ); } while (0) + FATAL_IF( 0 != flexthread_mutex_unlock( s->f ), msg ); } while (0) void server_lock_io( struct server * serve) { + debug("IO locking"); + SERVER_LOCK( serve, l_io, "Problem with I/O lock" ); } void server_unlock_io( struct server* serve ) { + debug("IO unlocking"); + SERVER_UNLOCK( serve, l_io, "Problem with I/O unlock" ); } + +/* This is only to be called from error handlers. */ +int server_io_locked( struct server * serve ) +{ + NULLCHECK( serve ); + return flexthread_mutex_held( serve->l_io ); +} + + + void server_lock_acl( struct server *serve ) { + debug("ACL locking"); + SERVER_LOCK( serve, l_acl, "Problem with ACL lock" ); } @@ -152,6 +168,13 @@ void server_unlock_acl( struct server *serve ) } +int server_acl_locked( struct server * serve ) +{ + NULLCHECK( serve ); + return flexthread_mutex_held( serve->l_acl ); +} + + /** Return the actual port the server bound to. This is used because we * are allowed to pass "0" on the command-line. */ @@ -640,6 +663,11 @@ void serve_cleanup(struct server* params, pthread_join(thread_id, &status); } } + + if ( server_acl_locked( params ) ) { + server_unlock_acl( params ); + } + debug( "Cleanup done"); } diff --git a/src/serve.h b/src/serve.h index 8620440..2fdb2e6 100644 --- a/src/serve.h +++ b/src/serve.h @@ -38,7 +38,7 @@ struct server { uint64_t size; /** Claims around any I/O to this file */ - pthread_mutex_t l_io; + struct flexthread_mutex * l_io; /** to interrupt accept loop and clients, write() to close_signal[1] */ struct self_pipe * close_signal; @@ -49,7 +49,9 @@ struct server { * has been replaced */ struct self_pipe * acl_updated_signal; - pthread_mutex_t l_acl; + + /* Claimed around any updates to the ACL. */ + struct flexthread_mutex * l_acl; struct mirror_status* mirror; struct mirror_super * mirror_super; @@ -90,6 +92,11 @@ void server_replace_acl( struct server *serve, struct acl * acl); void server_control_arrived( struct server *serve ); int server_is_in_control( struct server *serve ); int server_default_deny( struct server * serve ); +int server_io_locked( struct server * serve ); +int server_acl_locked( struct server * serve ); +void server_lock_acl( struct server *serve ); +void server_unlock_acl( struct server *serve ); + int do_serve( struct server * ); diff --git a/tests/acceptance/fakes/dest/close_after_entrust.rb b/tests/acceptance/fakes/dest/close_after_entrust.rb new file mode 100755 index 0000000..bf08bf1 --- /dev/null +++ b/tests/acceptance/fakes/dest/close_after_entrust.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +# Open a server, accept a client, then we expect a single write +# followed by an entrust. Disconnect after the entrust. We expect a +# reconnection followed by a full mirror. + +require 'flexnbd/fake_dest' +include FlexNBD + +addr, port, src_pid = *ARGV +server = FakeDest.new( addr, port ) +client = server.accept + +client.write_hello +write_req = client.read_request +data = client.read_data( write_req[:len] ) +client.write_reply( write_req[:handle], 0 ) + +entrust_req = client.read_request +fail "Not an entrust" unless entrust_req[:type] == 65536 +client.close + +client2 = server.accept +client2.receive_mirror + +exit(0) + diff --git a/tests/acceptance/flexnbd/fake_dest.rb b/tests/acceptance/flexnbd/fake_dest.rb index 6901967..d6c0ec8 100644 --- a/tests/acceptance/flexnbd/fake_dest.rb +++ b/tests/acceptance/flexnbd/fake_dest.rb @@ -94,6 +94,31 @@ module FlexNBD end + def receive_mirror + write_hello() + loop do + req = read_request + case req[:type] + when 1 + read_data( req[:len] ) + write_reply( req[:handle] ) + when 65536 + write_reply( req[:handle] ) + break + else + raise "Unexpected request: #{req.inspect}" + end + end + + disc = read_request + + if disc[:type] == 2 + close + else + raise "Not a disconnect: #{req.inspect}" + end + end + end # class Client diff --git a/tests/acceptance/test_source_error_handling.rb b/tests/acceptance/test_source_error_handling.rb index d456a3a..0de5260 100644 --- a/tests/acceptance/test_source_error_handling.rb +++ b/tests/acceptance/test_source_error_handling.rb @@ -26,86 +26,72 @@ class TestSourceErrorHandling < Test::Unit::TestCase def test_destination_hangs_after_connect_reports_error_at_source - run_fake( "dest/hang_after_connect" ) - - stdout, stderr = @env.mirror12_unchecked - assert_match( /Remote server failed to respond/, stderr ) - assert_success + run_fake( "dest/hang_after_connect", + /Remote server failed to respond/ ) end def test_destination_rejects_connection_reports_error_at_source - run_fake( "dest/reject_acl" ) - - stdout, stderr = @env.mirror12_unchecked - assert_match /Mirror was rejected/, stderr - assert_success + run_fake( "dest/reject_acl", + /Mirror was rejected/ ) end def test_wrong_size_causes_disconnect - run_fake( "dest/hello_wrong_size" ) - stdout, stderr = @env.mirror12_unchecked - assert_match /Remote size does not match local size/, stderr - assert_success + run_fake( "dest/hello_wrong_size", + /Remote size does not match local size/ ) end def test_wrong_magic_causes_disconnect - run_fake( "dest/hello_wrong_magic" ) - stdout, stderr = @env.mirror12_unchecked - assert_match /Mirror was rejected/, stderr - assert_success "dest/hello_wrong_magic fake failed" + run_fake( "dest/hello_wrong_magic", + /Mirror was rejected/ ) end def test_disconnect_after_hello_causes_retry - run_fake( "dest/close_after_hello" ) - stdout, stderr = @env.mirror12_unchecked - assert_match( /Mirror started/, stdout ) - - assert_success + run_fake( "dest/close_after_hello", + /Mirror started/ ) end def test_write_times_out_causes_retry run_fake( "dest/hang_after_write" ) - stdout, stderr = @env.mirror12_unchecked - - assert_success end def test_rejected_write_causes_retry run_fake( "dest/error_on_write" ) - stdout, stderr = @env.mirror12_unchecked - assert_success end def test_disconnect_before_write_reply_causes_retry run_fake( "dest/close_after_write" ) - @env.mirror12_unchecked - assert_success end def test_bad_write_reply_causes_retry run_fake( "dest/write_wrong_magic" ) - @env.mirror12_unchecked - assert_success end def test_pre_entrust_disconnect_causes_retry run_fake( "dest/close_after_writes" ) - @env.mirror12_unchecked - assert_success + end + + + def test_post_entrust_disconnect_causes_retry + @env.nbd1.can_die(0) + run_fake( "dest/close_after_entrust" ) end private - def run_fake(name) + def run_fake(name, err=nil) @env.run_fake( name, @env.ip, @env.port2 ) + stdout, stderr = @env.mirror12_unchecked + assert_success + assert_match( err, stderr ) if err + return stdout, stderr end def assert_success( msg=nil ) diff --git a/tests/unit/check_flexthread.c b/tests/unit/check_flexthread.c new file mode 100644 index 0000000..092ab5b --- /dev/null +++ b/tests/unit/check_flexthread.c @@ -0,0 +1,62 @@ +#include "flexthread.h" +#include "util.h" + +#include + + +START_TEST( test_mutex_create ) +{ + struct flexthread_mutex * ftm = flexthread_mutex_create(); + NULLCHECK( ftm ); + flexthread_mutex_destroy( ftm ); +} +END_TEST + + +START_TEST( test_mutex_lock ) +{ + struct flexthread_mutex * ftm = flexthread_mutex_create(); + + fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held before lock" ); + flexthread_mutex_lock( ftm ); + fail_unless( flexthread_mutex_held( ftm ), "Flexthread_mutex is not held inside lock" ); + flexthread_mutex_unlock( ftm ); + fail_if( flexthread_mutex_held( ftm ), "Flexthread_mutex is held after unlock" ); + + flexthread_mutex_destroy( ftm ); +} +END_TEST + + +Suite* flexthread_suite(void) +{ + Suite *s = suite_create("flexthread"); + TCase *tc_create = tcase_create("create"); + TCase *tc_destroy = tcase_create("destroy"); + + tcase_add_test( tc_create, test_mutex_create ); + tcase_add_test( tc_create, test_mutex_lock ); + + suite_add_tcase(s, tc_create); + suite_add_tcase(s, tc_destroy); + + return s; +} + +int main(void) +{ +#ifdef DEBUG + log_level = 0; +#else + log_level = 2; +#endif + int number_failed; + Suite *s = flexthread_suite(); + SRunner *sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + log_level = 0; + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? 0 : 1; +} + diff --git a/tests/unit/check_serve.c b/tests/unit/check_serve.c index 18a8325..bdeaae7 100644 --- a/tests/unit/check_serve.c +++ b/tests/unit/check_serve.c @@ -63,6 +63,7 @@ void teardown( void ) START_TEST( test_replaces_acl ) { struct flexnbd flexnbd; + flexnbd.signal_fd = -1; struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 ); struct acl * new_acl = acl_create( 0, NULL, 0 ); @@ -77,6 +78,7 @@ END_TEST START_TEST( test_signals_acl_updated ) { struct flexnbd flexnbd; + flexnbd.signal_fd = -1; struct server * s = server_create( &flexnbd, "127.0.0.1", "0", dummy_file, 0, 0, NULL, 1, 1 ); struct acl * new_acl = acl_create( 0, NULL, 0 ); @@ -189,6 +191,8 @@ END_TEST START_TEST( test_acl_update_leaves_good_client ) { struct flexnbd flexnbd; + flexnbd.signal_fd = -1; + struct server * s = server_create( &flexnbd, "127.0.0.7", "0", dummy_file, 0, 0, NULL, 1, 1 ); char *lines[] = {"127.0.0.1"}; @@ -202,7 +206,6 @@ START_TEST( test_acl_update_leaves_good_client ) serve_open_server_socket( s ); actual_port = server_port( s ); - client_fd = connect_client( "127.0.0.7", actual_port, "127.0.0.1" ); server_accept( s ); entry = &s->nbd_client[0];