00001 /** @file 00002 00003 A brief file description 00004 00005 @section license License 00006 00007 Licensed to the Apache Software Foundation (ASF) under one 00008 or more contributor license agreements. See the NOTICE file 00009 distributed with this work for additional information 00010 regarding copyright ownership. The ASF licenses this file 00011 to you under the Apache License, Version 2.0 (the 00012 "License"); you may not use this file except in compliance 00013 with the License. You may obtain a copy of the License at 00014 00015 http://www.apache.org/licenses/LICENSE-2.0 00016 00017 Unless required by applicable law or agreed to in writing, software 00018 distributed under the License is distributed on an "AS IS" BASIS, 00019 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00020 See the License for the specific language governing permissions and 00021 limitations under the License. 00022 */ 00023 00024 #include "ink_config.h" 00025 #include <assert.h> 00026 00027 #include "ink_atomic.h" 00028 #include "ink_queue.h" 00029 00030 /* 00031 * This file was added during the debugging of Bug 50475. 00032 * It was found that a race condition was introduced on the sparc architecture 00033 * when the ink_queue.c file was moved over to ink_queue.cc. Debugging this 00034 * problem resulted in the discovery that gcc was spitting out the 00035 * "ldd" (load double) instruction for loading of the 64 bit field "data" 00036 * while CC was spitting out two "ld" (load) instructions. The old code 00037 * was calling item.data = head.data on sparcs and not putting any restriction 00038 * on the order of loading of the fields. 00039 * 00040 * This is a problem on the sparcs because the "pointer" field was being loaded 00041 * before the "version" field. This can result in a very subtle race condition 00042 * which subverts the addition of the "version" field. 00043 * 00044 * Take this scenario 00045 * item.ptr = head.ptr 00046 * (call to ink_freelist_new ) 00047 * next.ptr = *(item.ptr) <---- Error 00048 * (call to ink_freelist_free ) 00049 * item.version = head.version 00050 * next.version = item.version ++; 00051 * cas64(head, item, next) 00052 00053 * Note, that the cas64 call will be succesful and the next.ptr will probably 00054 * be a pointer into the vtable entry. The next alloc will result in a write into 00055 * the vtable area. 00056 * 00057 * The fix for this problem is to read the version before reading the pointer 00058 * on 32 bit architectures (currently everything other than alphas). This is 00059 * done using the following function. This file only contains one function 00060 * to make looking at the assembly code simple. 00061 * 00062 * If you ever change the compiler or the compiler options to this file, make 00063 * sure you look at the assembly generated to see if the version is read first. 00064 * Also, make sure that you run the test_freelist microbenchmark for at least 00065 * 24 hours on a dual processor box. 00066 */ 00067 00068 void 00069 ink_queue_load_64(void *dst, void *src) 00070 { 00071 #if (defined(__i386__) || defined(__arm__) || defined(__mips__)) && (SIZEOF_VOIDP == 4) 00072 volatile int32_t src_version = (*(head_p *) src).s.version; 00073 void *src_pointer = (*(head_p *) src).s.pointer; 00074 00075 (*(head_p *) dst).s.version = src_version; 00076 (*(head_p *) dst).s.pointer = src_pointer; 00077 #else 00078 *(void**)dst = *(void**)src; 00079 #endif 00080 }