1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // A crazy linker test to test callbacks for delayed execution.
9 #include <crazy_linker.h>
11 #include "test_util.h"
15 typedef void (*FunctionPtr
)();
17 // Data block passed between callback poster and callback handler.
21 callback_
.handler
= NULL
;
22 callback_
.opaque
= NULL
;
23 pthread_mutex_init(&mutex_
, NULL
);
24 pthread_cond_init(&cond_
, NULL
);
27 crazy_callback_t callback_
;
28 pthread_mutex_t mutex_
;
32 bool PostCallback(crazy_callback_t
* callback
, void* poster_opaque
) {
33 printf("Post callback, poster_opaque %p, handler %p, opaque %p\n",
38 CallbackData
* callback_data
= reinterpret_cast<CallbackData
*>(poster_opaque
);
40 // Set callback_ and signal the arrival of the PostCallback() call.
41 pthread_mutex_lock(&callback_data
->mutex_
);
42 callback_data
->callback_
= *callback
;
43 pthread_cond_signal(&callback_data
->cond_
);
44 pthread_mutex_unlock(&callback_data
->mutex_
);
49 void CheckAndRunCallback(CallbackData
* callback_data
) {
50 printf("Run callback, callback_data %p\n", callback_data
);
52 if (!callback_data
->callback_
.handler
) {
53 Panic("Post for delayed execution not invoked\n");
56 // Run the callback, then clear it.
57 crazy_callback_run(&callback_data
->callback_
);
58 callback_data
->callback_
.handler
= NULL
;
59 callback_data
->callback_
.opaque
= NULL
;
63 crazy_library_t
* library
;
64 crazy_context_t
* context
;
67 void* ThreadBody(void *thread_arg
) {
68 const ThreadData
* thread_data
= reinterpret_cast<ThreadData
*>(thread_arg
);
70 // Close the library, asynchronously.
71 crazy_library_close_with_context(thread_data
->library
, thread_data
->context
);
75 pthread_t
AsyncCrazyLibraryCloseWithContext(crazy_library_t
* library
,
76 crazy_context_t
* context
,
77 CallbackData
* callback_data
) {
78 printf("Async close, library %p, context %p\n", library
, context
);
80 ThreadData thread_data
= {library
, context
};
81 void* thread_arg
= reinterpret_cast<void*>(&thread_data
);
83 // Clear the indication that the new thread has called PostCallback().
84 pthread_mutex_lock(&callback_data
->mutex_
);
85 callback_data
->callback_
.handler
= NULL
;
86 callback_data
->callback_
.opaque
= NULL
;
87 pthread_mutex_unlock(&callback_data
->mutex_
);
89 // Start the thread that closes the library.
91 if (pthread_create(&thread
, NULL
, ThreadBody
, thread_arg
) != 0) {
92 Panic("Failed to create thread for close\n");
95 // Wait for the library close to call PostCallback() before returning.
96 printf("Waiting for PostCallback() call\n");
97 pthread_mutex_lock(&callback_data
->mutex_
);
98 while (!callback_data
->callback_
.handler
) {
99 pthread_cond_wait(&callback_data
->cond_
, &callback_data
->mutex_
);
101 pthread_mutex_unlock(&callback_data
->mutex_
);
102 printf("Done waiting for PostCallback() call\n");
110 crazy_context_t
* context
= crazy_context_create();
111 crazy_library_t
* library
;
114 crazy_context_set_load_address(context
, 0x20000000);
116 // Set a callback poster.
117 CallbackData callback_data
;
118 crazy_context_set_callback_poster(context
, &PostCallback
, &callback_data
);
120 crazy_callback_poster_t poster
;
123 // Check that the API returns the values we set.
124 crazy_context_get_callback_poster(context
, &poster
, &poster_opaque
);
125 if (poster
!= &PostCallback
|| poster_opaque
!= &callback_data
) {
126 Panic("Get callback poster error\n");
130 if (!crazy_library_open(&library
, "libfoo.so", context
)) {
131 Panic("Could not open library: %s\n", crazy_context_get_error(context
));
133 CheckAndRunCallback(&callback_data
);
135 // Find the "Foo" symbol.
136 FunctionPtr foo_func
;
137 if (!crazy_library_find_symbol(
138 library
, "Foo", reinterpret_cast<void**>(&foo_func
))) {
139 Panic("Could not find 'Foo' in libfoo.so\n");
145 // Close the library. Because the close operation will wait for the
146 // callback before returning, we have to run it in a separate thread, and
147 // wait for it to call PostCallback() before continuing.
149 AsyncCrazyLibraryCloseWithContext(library
, context
, &callback_data
);
150 CheckAndRunCallback(&callback_data
);
152 if (pthread_join(thread
, NULL
) != 0) {
153 Panic("Failed to join thread for close\n");
156 crazy_context_destroy(context
);