Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / android_crazy_linker / src / tests / test_load_library_callbacks.cpp
blob9281efe2ff091ca1548abcbc7096ce49f4d4bbb0
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.
7 #include <pthread.h>
8 #include <stdio.h>
9 #include <crazy_linker.h>
11 #include "test_util.h"
13 namespace {
15 typedef void (*FunctionPtr)();
17 // Data block passed between callback poster and callback handler.
18 class CallbackData {
19 public:
20 CallbackData() {
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_;
29 pthread_cond_t cond_;
32 bool PostCallback(crazy_callback_t* callback, void* poster_opaque) {
33 printf("Post callback, poster_opaque %p, handler %p, opaque %p\n",
34 poster_opaque,
35 callback->handler,
36 callback->opaque);
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_);
46 return true;
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;
62 struct ThreadData {
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);
72 pthread_exit(NULL);
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.
90 pthread_t thread;
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");
104 return thread;
107 } // namespace
109 int main() {
110 crazy_context_t* context = crazy_context_create();
111 crazy_library_t* library;
113 // DEBUG
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;
121 void* poster_opaque;
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");
129 // Load libfoo.so.
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");
142 // Call it.
143 (*foo_func)();
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.
148 pthread_t thread =
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);
157 return 0;