1707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* 2707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * QEMU System Emulator 3707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 4707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard 5707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 6707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy 7707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal 8707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * in the Software without restriction, including without limitation the rights 9707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is 11707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * furnished to do so, subject to the following conditions: 12707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 13707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * The above copyright notice and this permission notice shall be included in 14707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * all copies or substantial portions of the Software. 15707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 16707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * THE SOFTWARE. 23707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner */ 24707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 25707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner#include "qemu-common.h" 26707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner#include "qemu-aio.h" 27707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 28707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* 29707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * An AsyncContext protects the callbacks of AIO requests and Bottom Halves 30707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * against interfering with each other. A typical example is qcow2 that accepts 31707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * asynchronous requests, but relies for manipulation of its metadata on 32707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * synchronous bdrv_read/write that doesn't trigger any callbacks. 33707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 34707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * However, these functions are often emulated using AIO which means that AIO 35707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * callbacks must be run - but at the same time we must not run callbacks of 36707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * other requests as they might start to modify metadata and corrupt the 37707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * internal state of the caller of bdrv_read/write. 38707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 39707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * To achieve the desired semantics we switch into a new AsyncContext. 40707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Callbacks must only be run if they belong to the current AsyncContext. 41707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Otherwise they need to be queued until their own context is active again. 42707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * This is how you can make qemu_aio_wait() wait only for your own callbacks. 43707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * 44707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * The AsyncContexts form a stack. When you leave a AsyncContexts, you always 45707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * return to the old ("parent") context. 46707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner */ 47707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerstruct AsyncContext { 48707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Consecutive number of the AsyncContext (position in the stack) */ 49707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner int id; 50707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 51707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Anchor of the list of Bottom Halves belonging to the context */ 52707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner struct QEMUBH *first_bh; 53707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 54707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Link to parent context */ 55707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner struct AsyncContext *parent; 56707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner}; 57707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 58707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* The currently active AsyncContext */ 59707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerstatic struct AsyncContext *async_context = &(struct AsyncContext) { 0 }; 60707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 61707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* 62707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks 63707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * won't be called until this context is left again. 64707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner */ 65707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid async_context_push(void) 66707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 67707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner struct AsyncContext *new = qemu_mallocz(sizeof(*new)); 68707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner new->parent = async_context; 69707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner new->id = async_context->id + 1; 70707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner async_context = new; 71707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 72707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 73707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* Run queued AIO completions and destroy Bottom Half */ 74707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerstatic void bh_run_aio_completions(void *opaque) 75707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 76707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH **bh = opaque; 77707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_bh_delete(*bh); 78707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_free(bh); 79707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_aio_process_queue(); 80707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 81707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* 82707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Leave the currently active AsyncContext. All Bottom Halves belonging to the 83707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * old context are executed before changing the context. 84707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner */ 85707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid async_context_pop(void) 86707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 87707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner struct AsyncContext *old = async_context; 88707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH **bh; 89707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 90707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Flush the bottom halves, we don't want to lose them */ 91707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner while (qemu_bh_poll()); 92707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 93707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Switch back to the parent context */ 94707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner async_context = async_context->parent; 95707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_free(old); 96707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 97707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (async_context == NULL) { 98707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner abort(); 99707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 100707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 101707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* Schedule BH to run any queued AIO completions as soon as possible */ 102707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh = qemu_malloc(sizeof(*bh)); 103707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner *bh = qemu_bh_new(bh_run_aio_completions, bh); 104707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_bh_schedule(*bh); 105707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 106707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 107707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* 108707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * Returns the ID of the currently active AsyncContext 109707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner */ 110707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerint get_async_context_id(void) 111707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 112707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner return async_context->id; 113707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 114707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 115707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/***********************************************************/ 116707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner/* bottom halves (can be seen as timers which expire ASAP) */ 117707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 118707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerstruct QEMUBH { 119707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBHFunc *cb; 120707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner void *opaque; 121707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner int scheduled; 122707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner int idle; 123707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner int deleted; 124707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH *next; 125707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner}; 126707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 127707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' TurnerQEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) 128707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 129707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH *bh; 130707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh = qemu_mallocz(sizeof(QEMUBH)); 131707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->cb = cb; 132707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->opaque = opaque; 133707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->next = async_context->first_bh; 134707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner async_context->first_bh = bh; 135707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner return bh; 136707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 137707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 138707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnerint qemu_bh_poll(void) 139707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 140707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH *bh, **bhp; 141707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner int ret; 142707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 143707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner ret = 0; 144707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner for (bh = async_context->first_bh; bh; bh = bh->next) { 145707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (!bh->deleted && bh->scheduled) { 146707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->scheduled = 0; 147707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (!bh->idle) 148707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner ret = 1; 149707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->idle = 0; 150707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->cb(bh->opaque); 151707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 152707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 153707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 154707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* remove deleted bhs */ 155707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bhp = &async_context->first_bh; 156707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner while (*bhp) { 157707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh = *bhp; 158707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (bh->deleted) { 159707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner *bhp = bh->next; 160707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_free(bh); 161707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } else 162707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bhp = &bh->next; 163707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 164707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 165707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner return ret; 166707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 167707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 168707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid qemu_bh_schedule_idle(QEMUBH *bh) 169707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 170707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (bh->scheduled) 171707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner return; 172707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->scheduled = 1; 173707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->idle = 1; 174707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 175707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 176707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid qemu_bh_schedule(QEMUBH *bh) 177707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 178707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (bh->scheduled) 179707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner return; 180707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->scheduled = 1; 181707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->idle = 0; 182707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* stop the currently executing CPU to execute the BH ASAP */ 183707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner qemu_notify_event(); 184707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 185707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 186707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid qemu_bh_cancel(QEMUBH *bh) 187707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 188707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->scheduled = 0; 189707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 190707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 191707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid qemu_bh_delete(QEMUBH *bh) 192707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 193707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->scheduled = 0; 194707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner bh->deleted = 1; 195707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 196707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 197707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turnervoid qemu_bh_update_timeout(int *timeout) 198707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner{ 199707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner QEMUBH *bh; 200707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 201707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner for (bh = async_context->first_bh; bh; bh = bh->next) { 202707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (!bh->deleted && bh->scheduled) { 203707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner if (bh->idle) { 204707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* idle bottom halves will be polled at least 205707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * every 10ms */ 206707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner *timeout = MIN(10, *timeout); 207707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } else { 208707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner /* non-idle bottom halves will be executed 209707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner * immediately */ 210707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner *timeout = 0; 211707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner break; 212707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 213707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 214707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner } 215707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner} 216707c8a8975842105dd04d61a416ee175d033b94dDavid 'Digit' Turner 217